OdyDocs

Errors

One error envelope for every failure, the codes it can carry, what to do about each, and how to use request IDs.

Ody uses conventional HTTP status codes: 2xx succeeded, 4xx means the request needs to change, 5xx means something went wrong on Ody's side. Every error body has the same shape.

#The error envelope

JSON
{
  "error": {
    "code": "permission_denied",
    "message": "This API key is missing the 'messages:send' scope",
    "requestId": "req_5f0c2a9b1e7d"
  }
}
  • error.code string — Machine-readable. Branch on this, never on message.
  • error.message string — Human-readable and safe to log. Wording may change.
  • error.requestId string — Same value as the X-Request-Id response header.

#Codes

StatuscodeMeaningWhat to do
400invalid_argumentA parameter is missing or malformed, or the body isn't JSONFix the request; the message says which field
401unauthenticatedKey missing, malformed, unknown, or revokedDon't retry. Alert whoever owns the integration
403permission_deniedKey lacks the scope; the message names itUse a key with that scope
404not_foundNo such resource in this workspace (or a malformed ID)Check the ID and that the key's workspace owns it
409failed_preconditionThe workspace can't do this yet: no active number, texting not registered, agent not published, no plan, identity not verified, number already takenSurface it to a human; retrying won't help
429resource_exhaustedRate limit exceededWait Retry-After seconds, then retry with backoff
500internalUnexpected server errorRetry with exponential backoff and jitter; cap retries

#Request IDs

Every response — success or error — carries an X-Request-Id header. Log it next to your own request logs, and quote it when you contact support: it identifies the exact request on our side.

You can also send your own X-Request-Id (up to 64 characters: letters, digits, _ and -). Ody echoes it back instead of minting one, which makes correlating retries across systems easy.

Shell
curl -i https://api.ody.co/v1/api/contacts \
  -H "Authorization: Bearer $ODY_API_KEY" \
  -H "X-Request-Id: sync-2026-10-14-0001"

#Retrying safely

SituationRetry?
429Yes — after Retry-After
500, network error, timeoutYes — exponential backoff with jitter. For POST /messages and POST /numbers, always send an Idempotency-Key so a retry can't double-send or double-buy
400, 401, 403, 404, 409No — the same request will fail the same way

#SDK errors

The SDKs raise a typed error carrying the same fields:

import { OdyError } from "@ody/sdk";

try {
  await ody.contacts.get("00000000-0000-0000-0000-000000000000");
} catch (err) {
  if (err instanceof OdyError) {
    console.error(err.code, err.status, err.requestId, err.retryAfter);
  }
}
Last updated Wed Oct 14 2026 00:00:00 GMT+0000 (Coordinated Universal Time)Something wrong on this page? Tell us