Errors
The error format and every error code with its HTTP status, what it means and what to do about it — plus which errors are safe to retry.
Format
Every error — from the API or the app's endpoints — has the same shape and never contains a stack trace:
{
"error": {
"code": "INVALID_STATE",
"message": "Field company_size must be a number.",
"request_id": "req_7Gm2xPq9Lk4sVt1RbN8w"
}
}| Field | Description |
|---|---|
code | A stable, machine-readable code from the tables below. Switch on it — not on message. |
message | A human-readable explanation. It can change; don't parse it. |
request_id | The request's ID, also sent in the X-Request-ID header. Include it when you contact support. |
details | Optional extra data, depending on the code (see details). |
Error codes
Request and access
| Code | Status | Meaning | What to do |
|---|---|---|---|
INVALID_REQUEST | 400 | The request is malformed: invalid JSON, a body that isn't a JSON object, an invalid Idempotency-Key or query parameter — such as limit=1000 on GET /v1/executions. | Fix the request. details lists the offending fields when there are any. |
PAYLOAD_TOO_LARGE | 413 | The request body is larger than 128 KB. | Send a smaller body — for a large state, send only the fields the questions need. See Limits. |
INVALID_API_KEY | 401 | The API key is missing, malformed, unknown or revoked. | Send Authorization: Bearer <key> with an active key. |
UNAUTHORIZED | 401 | App: you're not signed in, your session expired or it was ended — by Sign out everywhere or a password change; also a wrong e-mail or password at sign-in. Webhook URLs with a secret: the call has no valid Dcision-Signature or Authorization: Bearer whsec_…. | Sign in again — or sign the webhook call with the current secret. |
FORBIDDEN | 403 | You can't do this: an API key used outside /v1; a workspace you aren't a member of — then details.reason is "workspace_access"; or an action your role doesn't allow — Viewers can't change anything; settings, provider keys, secrets and members need an Admin; billing, ownership and deleting the workspace need the Owner. | Use API keys only on /v1. For a role, ask an Admin or the Owner — the message names the role needed. |
NOT_FOUND | 404 | App: the execution, API key, template, plan, checkout session, member, invitation, delivery or secret doesn't exist in this workspace. Webhook URLs: the token is unknown, was rotated, or the webhook is turned off. | Check the ID — or copy the webhook URL again from the decision's Advanced tab. |
CONFLICT | 409 | The change conflicts with the current state: a slug already taken or locked after the first deploy, a draft saved meanwhile by someone else, a concurrent deploy or create, a limit (50 active API keys, 50 secrets, 50 pending invitations, 10 owned workspaces), an invitation for someone already in the workspace, an Owner leaving without a transfer, a workspace with a live paid subscription being deleted, a subscription that already exists or doesn't. | Reload, then follow the message. |
Decisions
| Code | Status | Meaning | What to do |
|---|---|---|---|
DECISION_NOT_FOUND | 404 | No decision with this slug in the API key's workspace, or a malformed slug. | Check the slug and that the key belongs to the decision's workspace. |
DECISION_NOT_DEPLOYED | 409 | The decision exists but has never been deployed. | Deploy it from its Deploy tab. |
DECISION_DISABLED | 409 | The decision's endpoint is disabled. | Click Enable endpoint in its Deploy tab. |
INVALID_STATE | 422 | The state doesn't match the decision's state schema, or is too large — by itself, or together with the questions for the engine's token budget. message names the field or the limit. | Fix the state; for the token budget, send only the fields the questions need. Don't retry it unchanged. |
INVALID_SCHEMA | 422 | The decision schema is invalid — when saving or deploying a draft. details lists every issue. | Fix the issues in the editor (Go to error). |
IDEMPOTENCY_CONFLICT | 409 | The Idempotency-Key was used in the last 24 hours with a different request — or, with Retry-After: 1, the first request with this key is still running. | With Retry-After: wait and retry with the same key to get the stored response. Without it: use a new key for a new request — see Idempotency. |
Limits and billing
| Code | Status | Meaning | What to do |
|---|---|---|---|
RATE_LIMITED | 429 | Too many requests in the current minute for your workspace — or the Playground's own limits, or, in the app, too many billing actions (checkout, plan changes, portal…), invitations, sign-in codes or sign-in attempts. | Wait Retry-After seconds, then retry — see Rate limits. |
CREDITS_EXHAUSTED | 402 | The plan's included decisions for the period are used up and the workspace has no credits left. | The Owner adds credits or turns on automatic recharge on the Billing page (details.billingUrl), or upgrades. Retrying before that doesn't help. |
SPEND_CAP_REACHED | 402 | The workspace's spend cap for the billing cycle is reached. | The Owner raises or removes the cap on the Billing page, or wait until details.periodEnd. |
QUOTA_EXCEEDED | 402 | A plan configured with a hard cap — or without a price per 1M decisions — used all its included decisions for the period, so it can't continue with credits. | Upgrade, or wait until details.periodEnd. Retrying earlier doesn't help. |
PLAN_LIMIT_REACHED | 402 | The workspace already has the maximum number of decisions of its plan. | Delete a decision or upgrade. |
PAYMENT_FAILED | 402 | The card was declined while changing plans. | Update the payment method, then try again. |
BILLING_NOT_CONFIGURED | 503 | That plan, interval or currency can't be bought online yet. | Try again later or write to sales@dcision.io. |
BILLING_PROVIDER_ERROR | 502 | The payment provider failed to process the request. | Try again in a moment. |
Engine
Dcision has already retried transient engine failures — up to 2 retries within the decision's timeoutMs — before it returns one of these errors. A decision with onEngineError: "fallback" answers 200 with its fallback action instead, for every code below except ENGINE_NOT_CONFIGURED — see Decision settings.
| Code | Status | Meaning | What to do |
|---|---|---|---|
ENGINE_NOT_CONFIGURED | 424 | The workspace has no usable engine credential: My own provider key is selected but no key is saved for that provider, or Dcision's engine key is unavailable. | Add the key in Settings → Engine, or switch to Dcision's key. |
ENGINE_TIMEOUT | 504 | The engine didn't answer within the decision's timeoutMs. | Retry with backoff and the same Idempotency-Key; raise timeoutMs if it happens often. |
ENGINE_RATE_LIMITED | 503 | The engine provider is overloaded or rate limited, or Dcision's shared engine key had no free slot before the deadline. | Retry with backoff. With your own key, check your provider's limits. |
ENGINE_UNAVAILABLE | 503 | The engine provider failed or couldn't be reached. | Retry with backoff. |
ENGINE_INVALID_REQUEST | 502 | The provider rejected the request; the message includes its reason. | Usually not transient: check the state and the model, then contact support with the request ID. |
ENGINE_AUTH_FAILED | 502 | The provider rejected the engine key. | Fix or replace your provider key in Settings → Engine. |
ENGINE_ERROR | 502 | The engine answered outside the decision's contract (a missing or unknown answer). | Retry once; if it persists, contact support with the request ID. |
Server
| Code | Status | Meaning | What to do |
|---|---|---|---|
INTERNAL_ERROR | 500 | An unexpected error on Dcision's side. | Retry with backoff; contact support with the request ID if it persists. |
Retrying
| Retry | Don't retry unchanged |
|---|---|
429 RATE_LIMITED — after Retry-After | 400, 401, 403, 404, 413, 422 |
409 IDEMPOTENCY_CONFLICT with Retry-After — same key, after the wait | Any other 409 |
500 INTERNAL_ERROR | 402 CREDITS_EXHAUSTED, SPEND_CAP_REACHED, QUOTA_EXCEEDED, PLAN_LIMIT_REACHED, PAYMENT_FAILED |
503 ENGINE_RATE_LIMITED, ENGINE_UNAVAILABLE | 424 ENGINE_NOT_CONFIGURED |
504 ENGINE_TIMEOUT | 502 ENGINE_AUTH_FAILED, ENGINE_INVALID_REQUEST |
502 ENGINE_ERROR — once | |
| Network errors and timeouts on your side |
Send an Idempotency-Key so a retry after a lost response doesn't run — or bill — the decision twice. A complete client is in Idempotent retries.
Errors are never billed, and neither are engine-error fallbacks. Invalid states and engine failures are recorded as executions with status Error, so you can inspect them — in the app or with GET /v1/executions?status=error.
Details
details carries structured data for some codes:
{
"error": {
"code": "INVALID_SCHEMA",
"message": "The decision schema is invalid.",
"request_id": "req_7Gm2xPq9Lk4sVt1RbN8w",
"details": [{ "path": "questions.0.options", "message": "Add at least 2 options (besides \"other\")." }]
}
}{
"error": {
"code": "CREDITS_EXHAUSTED",
"message": "The 2.5M decisions included in the Developer plan are used up and the workspace has no credits left. Add credits or turn on automatic recharge.",
"request_id": "req_Lz4Wq8nT1vXc7Rm2Kp9H",
"details": {
"used": 2500000,
"included": 2500000,
"availableCents": 0,
"currency": "usd",
"billingUrl": "https://app.dcision.io/billing"
}
}
}{
"error": {
"code": "SPEND_CAP_REACHED",
"message": "The workspace reached its spend cap of $50.00 for this billing cycle. Raise the cap or wait until 2026-11-01.",
"request_id": "req_Qm8Vr2Lx5Nc1Tw7Hk4Jd",
"details": {
"spendCapCents": 5000,
"spentCents": 5000,
"currency": "usd",
"periodEnd": "2026-11-01T00:00:00.000Z",
"billingUrl": "https://app.dcision.io/billing"
}
}
}{
"error": {
"code": "FORBIDDEN",
"message": "You don't have access to this workspace.",
"request_id": "req_Pw3Nx8Kd1Lq6Tz2Vb9Rc",
"details": { "reason": "workspace_access" }
}
}| Code | details |
|---|---|
INVALID_REQUEST | [{ "path", "message" }] for invalid fields, when available |
INVALID_SCHEMA | [{ "path", "message" }] — every schema issue |
CREDITS_EXHAUSTED | used, included, availableCents (the credit left, in cents of currency — zero or slightly negative), currency (usd or brl), billingUrl |
SPEND_CAP_REACHED | spendCapCents, spentCents (the cycle's spending with credits, in cents), currency, periodEnd (ISO 8601), billingUrl |
QUOTA_EXCEEDED | used, included, periodEnd (ISO 8601), upgradeUrl |
PLAN_LIMIT_REACHED | limit, used, upgradeUrl |
FORBIDDEN (workspace access) | { "reason": "workspace_access" } — you aren't a member of that workspace (any more). Role refusals carry no details. |
CONFLICT (stale draft) | currentRevision |
PAYMENT_FAILED | code, declineCode from the card network |
Webhook events
The decision.completed event of the OpenAPI document — the request sent to webhook destinations, its headers, every field of the event and the answers Dcision expects.
Rate limits
Per-workspace request limits for each plan, separate windows for decisions and reads, the X-RateLimit headers on every call, Retry-After on 429 and how to back off.