API conventions

Authentication, errors, pagination, timestamps and the other rules that every endpoint shares.

Learn these once and every endpoint reads the same way.

Base URL and authentication

Every request goes to https://api.dialgem.com, over HTTPS. Send your organization API key in the X-API-Key header.

bash
curl https://api.dialgem.com/v1/agents -H "X-API-Key: $DIALGEM_API_KEY"

Keep the key on your server. See Get your API keys and API key scopes. A browser should use a web call token instead.

GET /v1/api-key-info tells you which organization a key belongs to.

Requests and responses

  • Bodies are JSON. Send Content-Type: application/json.
  • Field names are snake_case in requests, responses and webhooks.
  • IDs are strings. Treat them as opaque.
  • Unknown fields can appear in responses. Ignore the ones you do not use, so new fields never break you.
  • PATCH changes only the fields you send. Some fields take null to clear them, which the field's reference entry says.

Errors

A failed request returns an HTTP status and a body of one shape:

json
{
  "err_code": "invalid_request",
  "err_msg": "Request body is invalid: 1 error.",
  "request_id": "fd1355dd-5bb0-4990-b537-1a166f8db9bd",
  "issues": [
    { "code": "schema_invalid", "severity": "error", "message": "voice_speed: Input should be less than or equal to 2" }
  ]
}
FieldMeaning
err_codeA stable code. Branch on this, not on the message.
err_msgA message for a person. It can change.
request_idQuote it when you contact support.
issuesPresent on validation errors. Each says what is wrong and, for a flow, which node_id.
StatusUsually means
400The request could not be understood.
401No key, a bad key, an expired key, a revoked key, or a request from an address the key does not allow.
402Not enough credit. See Billing.
403The key lacks the scope for this call (INSUFFICIENT_SCOPE), or the action is switched off for your account.
404It does not exist, or it belongs to another organization. The two look the same.
409A conflict, such as a name already in use or a voice still used by an agent.
422The body is valid JSON but fails validation. Read issues.
429Too many requests. Wait, and honour Retry-After when it is sent.
5xxA problem on our side. Retry with backoff.

Pagination

List endpoints that can grow large use cursors. Calls, for example:

  • limit sets the page size (1 to 100 for calls).
  • The response includes has_more and a pagination_key.
  • Pass pagination_key back to get the next page.

A cursor stays valid while new items arrive, so walking pages does not skip or repeat. A cursor is tied to the sort order it was issued for: ask for the same order on the next page. The SDKs walk pages for you with for await and plain for.

Timestamps and units

WhereFormat
Call started_at, ended_atISO 8601, UTC, no timezone suffix.
Call start_timestamp, end_timestampEpoch milliseconds.
Phone numbers and saved LLMs and flowsEpoch milliseconds (creation_timestamp, last_modification_timestamp, created_timestamp).
Durations*_ms fields are milliseconds, *_s fields are seconds.
MoneyIntegers in units of $0.0001. 1700 is $0.17.

Phone numbers are E.164: +14155550123.

Metadata

Calls and web calls carry a metadata object for your own data. It can be up to 16 KB of JSON, comes back unchanged, and is included in webhooks. Setting metadata on a call with PATCH replaces the whole object.

Versions

An agent has a draft and numbered versions. Version 0 means the draft. Publishing freezes a copy as the next number, and a phone number or call can be pinned to one. The version a call ran comes back on the call as agent_version. See Prompt agents.

Safe retries

  • GET, PUT, PATCH and DELETE are safe to retry.
  • Do not blindly retry a POST. Creating a call twice rings the person twice. The SDKs never retry a POST unless you ask.
  • Webhook deliveries are at least once. Deduplicate with X-Dialgem-Delivery. See Webhooks.

A call's recording_url is a freshly signed, short-lived link made on every read. Download it promptly instead of storing the link.

Extending a schema

New fields keep these conventions. A field is added only when its behaviour is implemented, and nothing is published as a placeholder.