REST API
Errors

Errors

Cobuntu errors are JSON with a stable envelope and a meaningful HTTP status. Match on the status code, not the message string.

Error envelope

{
  "error": "API key missing required scope: WRITE_MEMBERS",
  "code": "INSUFFICIENT_SCOPE",
  "requestId": "req_8f9a2b3c4d5e6f7g",
  "grantedScopes": ["READ_PUBLIC"]
}
FieldAlways present?Notes
errorHuman-readable message. Useful for logs/operators. Not stable — wording can change between versions.
codeWhen setMachine-readable code. Stable across versions for the same logical failure. Use this for programmatic branching.
requestIdWhen setTrace id. Quote this in support tickets.
(extras)When setSome errors include extra fields like grantedScopes (403), field (400 validation), retryAfter (429).

Status code reference

400 Bad Request — request is malformed

The request body / query params didn't pass validation. The code field tells you which validation failed:

  • INVALID_INPUT — generic shape issue (missing required field, wrong type)
  • INVALID_EMAIL — email field didn't match RFC pattern
  • INVALID_SLUG — URL slug had unsupported characters
  • INVALID_DATE — date string wasn't ISO 8601
  • INVALID_AMOUNT — money amount was negative or non-integer cents

These are client bugs. Fix the request; retrying won't help.

401 Unauthorized — no key, or invalid key

{ "error": "API key required. Pass it via X-API-Key header." }

or

{ "error": "Invalid API key." }

Either the X-API-Key header is missing/empty, or the key doesn't exist (typo / revoked / wrong env). See Authentication for the full flow.

403 Forbidden — key valid but lacks permission

Three flavors:

{ "error": "API key missing required scope: WRITE_MEMBERS",
  "grantedScopes": ["READ_PUBLIC"] }

Key doesn't carry the scope this endpoint requires. Generate a key with the right scope, or use ADMIN.

{ "error": "API key does not have access to this community" }

Key belongs to a different community than the URL's :communityTag. Keys are per-community.

{ "error": "Atlas is not enabled for this community" }

The endpoint requires a feature flag the community doesn't have. Enable in cobuntu-admin first.

404 Not Found

The resource doesn't exist (deleted, never created, wrong id). The response body has minimal detail by design — we don't leak existence information.

409 Conflict

The state transition you're attempting isn't valid:

  • member.approved already approved → 409 (use idempotency, not retry)
  • Subscription already cancelled → 409
  • Refund exceeds remaining refundable amount → 409

The code field tells you the specific conflict.

422 Unprocessable Entity — semantic validation

The request was syntactically valid (passed 400 checks) but semantically wrong:

  • Trying to approve a request that's already rejected
  • RSVPing to an event that's full
  • Submitting a form that requires fields you didn't include

429 Too Many Requests — rate limited

{ "error": "Rate limit exceeded. Retry after 4 seconds.",
  "code": "RATE_LIMITED" }

Headers include Retry-After (seconds) and X-RateLimit-Reset (Unix timestamp when the window resets). Back off and retry.

Default rate limits:

  • Publishable keys: 100 req/s
  • Secret keys: 50 req/s
  • Broadcasts: 5 sends / 24h / community

500 Internal Server Error

We had a bug. The response body has a requestId — quote it in support so we can find the trace. Retries are safe (we're already idempotent at the request level for reads + writes carrying an Idempotency-Key).

502 Bad Gateway / 503 Service Unavailable

An upstream we depend on (Stripe, our database, etc.) is degraded. Retry with exponential backoff: 1s → 2s → 4s → 8s → 16s, cap at ~5 attempts. Past that, surface a user-facing error.

504 Gateway Timeout

A request took longer than our 30s edge timeout. Almost always indicates either a slow query on our side (file a bug with requestId) or your call hit a network blip. Retry.

Idempotency

Write endpoints accept Idempotency-Key: <your-uuid> header. Two requests with the same key (within 24h) get the same response — the second is a replay of the first, never a duplicate state change.

curl -X POST https://api.cobuntu.com/api/v1/communities/my-community/applications/req_123/approve \
  -H "X-API-Key: sk_live_..." \
  -H "Idempotency-Key: 8f9a2b3c-4d5e-6f7g-8h9i-0j1k2l3m4n5o"

Use any UUID v4. Pattern: generate one per logical operation in your code, persist it alongside the operation, retry safely.

Retry strategy summary

StatusRetry?Backoff
400, 401, 403, 404, 409, 422No — client error, fix the requestn/a
429Yes, after Retry-AfterUse the header value
500Yes (with Idempotency-Key on writes)Exponential: 1s, 2s, 4s, 8s, 16s
502, 503, 504Yes (with Idempotency-Key on writes)Same as 500
Network error (no response)Yes (with Idempotency-Key on writes)Same as 500