Skip to main content

API reference

Error codes

The uniform error envelope, every machine-readable code Jobby.dev returns, and which are safe to retry.

Last updated

Every non-2xx response carries the same JSON envelope. The code field is the stable, machine-readable identifier — branch on it, not on the human-readable error string.

The envelope

{
  "error": "Off-session charges require one-time consent. ...",
  "code": "OFF_SESSION_CONSENT_REQUIRED",
  "details": { "target_plan": "pro", "interval": "monthly" }
}
  • error — always present, human- readable, may include guidance for the user.
  • code— present on every error v1 generates. Stable identifier; the v1 contract guarantees we don't rename codes once shipped.
  • details — optional, code-specific. Validation errors carry a flattened zod-style report; off-session consent errors carry a fresh checkout URL; SCA errors carry the payment-intent ID. Document per-code, but always JSON-serializable.

Codes

The full list, with HTTP status and whether retry is safe:

CodeHTTPRetryable?Meaning
VALIDATION400noRequest body / query parameters failed schema validation.
INVALID_TOKEN401noThe bearer token is missing, malformed, or revoked.
INSUFFICIENT_SCOPE403noThe token is valid but doesn't carry the required scope.
PLAN_GATED403noThe endpoint is gated to a higher plan tier than the caller has.
NOT_FOUND404noResource doesn't exist OR caller isn't the owner. Existence isn't leaked across tenants.
ALREADY_ON_PLAN409noOff-session upgrade attempted on the plan/interval the user is already on.
SUBSCRIPTION_NOT_ELIGIBLE409noSubscription is in a state (incomplete, past_due, canceled) that doesn't allow the requested action.
OFF_SESSION_CONSENT_REQUIRED402noOff-session charge requires prior consent. The error details carry a one-shot hosted-checkout URL.
ACTION_REQUIRED_NO_URL402noBank requires 3DS / SCA but Stripe didn't return a redirect URL. Use the billing portal as a fallback.
RATE_LIMITED429yes (with back-off)Per-token rate limit exceeded. Retry-After header carries the wait.
DEPENDENCY_UNAVAILABLE503yes (with back-off)Upstream provider (Stripe, Daily, Anthropic, Supabase) is temporarily unreachable. Safe to retry with back-off.
INTERNAL500noUnexpected server error. Already logged to Sentry; please open a support ticket if persistent.

Retryability

Codes marked yes (with back-off) are safe to retry with exponential back-off bounded by the retry-after / rate-limit signal. Codes marked no represent application-level decisions; retrying without changing the request will get the same error.

Idempotency

Mutating endpoints accept an optional Idempotency-Key header (UUID v4). If the same key is replayed within 24 hours, the original response is returned without re-applying the side effect. Use this for any retry loop on a non-idempotent endpoint (off-session charge, match decline, event create).

Error mapping in SDKs

Both the JS and Python SDKs throw a typed JobbydevError on non-2xx responses, carrying code, status, details, and retryAfterSeconds. Branch on error.code, never on error.message (the human string can change).

Related reading