Skip to main content

Error JSON shape

Every error response — regardless of status code — uses the same envelope:
Some errors include an optional details field with structured context (typically validation errors):
Branch on code, not error. The code is stable; the error string is for humans and may be reworded over time.

HTTP status codes

404 is intentional for hidden resources. If you query a resource that exists but your workspace can’t see, you get 404 (not 403) so the response doesn’t leak whether the resource exists.

Common error codes

Codes worth special handling in client logic:

UNAUTHORIZED (401)

Your session cookie or bearer token is missing or expired. Re-authenticate the user (or, for the extension, request a new token).

FORBIDDEN (403)

Authenticated, but the user doesn’t have the right workspace role or doesn’t own the resource. Common on admin-only endpoints (billing changes, member management, share updates).

BUDGET_EXCEEDED (402)

Workspace has run out of credits. The user needs to upgrade or wait for the next billing cycle. The Billing overview explains the credit model.

RATE_LIMIT_EXCEEDED (429)

You’re hitting an endpoint too often. The response includes Retry-After and X-RateLimit-* headers — see the section below.

VALIDATION_ERROR (400 / 422)

Request body or query failed schema validation. The details field tells you exactly which fields are wrong. Surface this to the user — don’t retry blindly.

CONFLICT (409)

Something already exists (duplicate invite, subscription already in this state) or you’re racing another writer. Re-fetch the current state before retrying.

STRIPE_CARD_DECLINED / STRIPE_PAYMENT_FAILED (402)

Stripe sanitized error codes for billing operations. Don’t expose raw Stripe error messages — surface a friendly retry / “update card” CTA.

INTERNAL_ERROR (500)

Connie failed. Retry with exponential backoff up to a few attempts; if it persists, contact support.

Rate limits

Connie rate-limits most endpoints using a Redis-backed sliding window. Limits are tiered by plan and applied at multiple scopes (per-user, per-workspace, or per-IP depending on the endpoint).

Default tiers

These are starting points — individual endpoints may be tighter (e.g. checkout, password reset). Inspect the response headers for the actual limit applied.

Rate-limit response headers

Every rate-limited response — both successes and 429s — includes:
1

Check Remaining proactively

On every response, read X-RateLimit-Remaining. If it’s low, slow down — don’t wait for a 429.
2

Respect Retry-After

On a 429, sleep for the number of seconds in Retry-After before the next request. Don’t retry sooner — you’ll just get another 429.
3

Backoff for 5xx

For 5xx, use exponential backoff with jitter — start at 1 second, double up to ~30 seconds. Cap retries at 4–5 attempts.
4

Don't retry 4xx (except 429)

A 400, 403, 404, or 422 won’t change on retry — fix the request first.

Worked example

A typical client-side handler:
Branching on body.code keeps your error handling stable across API versions — the codes are part of the contract, the human-readable strings are not.