Skip to main content

Errors

{ "error": { "type": "insufficient_scope", "message": "…", "scope": "sms:send" } }
FieldContract
typeStable. Branch on this. New values may appear; an existing one is never repurposed.
messageHuman-readable, may change at any time. Never parse it.
scopePresent on insufficient_scope — exactly which capability to request next.

The catalog

typeStatusWhat happenedWhat to do
invalid_request400Missing or malformed field, unknown enum value, unknown field in the body, or unparseable JSONFix the request. The message names the field.
unauthenticated401No credential, or one that is invalid, revoked or expiredRefresh the token, or check the key
insufficient_scope403Valid credential, missing scopeRe-authorize with the scope in the scope field
permission_denied403Scope is fine — the person's role lacks the permissionTheir admin changes the role in the portal
not_found404No such object, or it is not this account'sCheck the id
conflict409The request contradicts current stateRe-read, then retry
unsupported400A recognized parameter with a value this API cannot honourSee the message — e.g. enabled=false as a filter
rate_limited429Too many requestsBack off. Not currently emitted — see Rate limits.
unavailable503A dependency is downRetry with backoff
internal_error500Something failed on our sideRetry. You were not charged.

The two 403s are not the same problem

This is the single most common source of lost time on this API.

{ "error": { "type": "insufficient_scope", "message": "credential is not authorized for sms:send", "scope": "sms:send" } }

Your code's problem. The credential was never granted sms:send. Re-authorize, or add the scope to the key.

{ "error": { "type": "permission_denied", "message": "the user who authorized this application does not have access to call recordings" } }

Not your code's problem. The scope is present; the user behind the token lacks the matching admin-center permission. No amount of re-authorizing fixes it — their administrator has to change their role. See Scopes.

401 names the scope it wanted

Every challenge carries an RFC 6750 header, so a spec-compliant client can ask for exactly the right grant next time instead of over-asking:

WWW-Authenticate: Bearer realm="Telebroad API", error="invalid_token", scope="sms:read"

What is safe to retry

StatusSafe to retryWhy
5xxYesNothing was created or charged. Guaranteed.
429Yes, after backing offNothing happened
4xxNo — fix the request firstIt will fail identically

Two writes are idempotent, so a retry after a timeout is safe even if the first attempt succeeded:

  • POST /sms/conversations/{line}/{number}/resolve — re-resolving does not re-stamp who closed it or when.
  • POST /webhooks/{id}/enable and /disable — setting the state it is already in is a no-op.

POST /sms/messages is not idempotent. A retry after a timeout may send and bill a second message. If you cannot tolerate that, check SMS history before retrying.

5xx messages are deliberately vague

An internal error always reads "internal error". Internal messages carry table names, SQL fragments and hostnames, so they are logged on our side rather than returned. If you need one traced, send us the timestamp, the endpoint and the account — every one is logged with a correlation code.