Errors and limits

Dashboard, account and agent requests answer errors with JSON, always in the same shape. Use code, which is stable; message is meant for people and can change.

{ "error": { "code": "key_cap_daily", "message": "a spending limit has been reached", "retryable": true, "retry_after_seconds": 41200,
             "remediation": "The key's daily spending limit is used up; wait until it resets at 00:00 UTC or ask the key's owner to raise it.",
             "docs_url": "https://pilot.e3d.ai/docs/errors#key_cap_daily" } }
  • retryable says whether the identical request may succeed later with nobody changing anything.
  • retry_after_seconds appears when the wait is known; it is also the Retry-After header. 429 responses carry that header.
  • remediation is one sentence a person or a model can act on.
  • docs_url points to the code's entry below (the codes added for agents have their own heading; the older ones are in the table).
  • A refusal for a spending limit, a rate or capacity can name the specific code in a reason field, next to code: limit_reached.

Error codes

CodeStatusMeaning
bad_request400malformed request line, URL or length headers
invalid_json400body is not a strict JSON object
invalid_request400a field is missing, unknown or malformed
invalid_code400verification, reset or sign-in code not accepted
password_rejected400new password fails the policy
invalid_pack400pack is not purchasable
quote_required400token pricing: a web debate needs a quote id from POST /api/debates/quote
quote_exceeds_limit400token pricing: the debate could cost more than the per-debate maximum
unknown_model_rate400token pricing: a model on the panel has no price
terms_required403the terms must be accepted first (in the dashboard gate)
terms_changed409the terms changed; read the current version and accept again
panel_too_small400a debate panel needs at least two companies
panel_too_large400more companies than the panel limit
provider_not_allowed400a company that is not offered
duplicate_provider400a company is listed twice
families_not_distinct400a debate panel needs companies from at least two vendors
required_provider_missing400a company that always takes part was left out of the panel
bad_signature400Stripe signature invalid
invalid_event400Stripe event malformed
quote_exceeds_balance402token pricing: the debate's maximum is more than the balance
search_unavailable503token pricing with web search: the run listener refused the search fields (rolled back inside the capability cache); the hold was released in full; ask again for a new quote
unauthenticated401no session cookie
session_expired401the session has ended; sign in again
invalid_credentials401 (login) / 403 (reauth, change-password)email or password not accepted
invite_required403closed sign-up (PILOT_SIGNUP_MODE=invite): a missing, malformed, unknown, used, revoked, expired or reserved invite code; one answer for all of them
forbidden_origin403Origin or fetch metadata not allowed
csrf_failed403CSRF token missing or wrong
reauth_required403step-up older than 10 minutes
suspended403billing suspended: the account balance is negative or a dispute is open
not_found404no such route or resource
invite_invalid404the team invitation cannot be used by this account
method_not_allowed405wrong method for the route
request_timeout408body not received in time
key_limit40925 keys already exist
account_closing409the account is closing or closed
request_conflict409checkout requestId reused for another purchase
request_in_progress409identical checkout still running; retry
liability_outstanding409cannot close: negative balance
adjustments_unresolved409cannot close: open dispute
holds_open409cannot close: usage in progress
credits_remaining409cannot close without confirming forfeiture
version_conflict409the debate panel changed elsewhere; read it again
panel_unavailable409the debate panel has fewer than two offered companies from different vendors left
debate_not_finished409only a finished debate can be saved as a decision
decision_limit409the account has the maximum number of saved decisions
share_limit409the account has the maximum number of active share links
team_limit409the account owns or belongs to the maximum number of teams
member_limit409the team has the maximum number of members
invite_limit409the team has the maximum number of pending invitations
already_member409the account is already a member of the team
team_readonly409the team is read-only (its owner closed the account)
team_owner_must_resolve409the owner cannot leave or close while the team has other members
insufficient_credits409not enough credits on the account for a debate
key_inactive409the key named for attribution is revoked
quote_changed409token pricing: the quote is stale or the price rose since it was shown; a fresh quote comes with it
payload_too_large413body over the limit
unsupported_media_type415body is not application/json
rate_limited429limit reached; see Retry-After
too_many_debates429two web debates are already in progress
limit_reached429a usage limit is reached: a key's spending cap, the account-wide daily ceiling, open requests or rate
internal_error500unexpected failure
receipt_failed500webhook receipt not durable
checkout_unavailable502Stripe Checkout unavailable
accounts_unavailable503platform accounts service unavailable
debates_unavailable503web debates are not available right now
handler_timeout503request took too long
launch_disabled503purchases not open yet
usage_unavailable503usage analytics unavailable
retry_later503webhook processing deferred
webhook_unavailable503webhook not configured

Agent error codes

These are the codes of the agent contract (spending limits, quotes, idempotency, rate and capacity) and of the internal listener. Agent calls use the status shown; the dashboard API keeps the statuses in the table above. Each entry says what to do.

key_revoked

403 · not retryable as is. This key was revoked; ask the key's owner for a new key.

key_unknown

401 · not retryable as is. This key is not recognised; check that the whole key was copied.

key_cap_per_run

403 · not retryable as is. This run could cost more than the key's per-run limit; ask a shorter or smaller debate, or ask the key's owner to raise the limit.

key_cap_daily

429 · retry after 00:00 UTC. The key's daily spending limit is used up; wait until it resets at 00:00 UTC or ask the key's owner to raise it.

key_cap_total

403 · not retryable as is. The key's lifetime spending limit is used up; ask the key's owner to raise it or issue a new key.

key_cap_period

429 · retryable. The key's monthly spending limit is used up; wait for the new month or ask the key's owner to raise it.

account_cap_daily

429 · retry after 00:00 UTC. The account's daily spending ceiling is reached; wait until it resets at 00:00 UTC.

insufficient_credits

402 · not retryable as is. The account does not have enough credits for this run's maximum; ask a human to add credits.

quote_required

400 · not retryable as is. Get a quote first and pass its quote_id.

quote_expired

410 · not retryable as is. The quote is unknown or older than 10 minutes; get a new quote.

quote_mismatch

409 · not retryable as is. The run does not match its quote (see the mismatch list); get a new quote for exactly this run.

quote_used

409 · not retryable as is. This quote already belongs to another run; get a new quote.

quote_changed

409 · not retryable as is. The price changed after the quote; get a new quote and check the new maximum.

quote_exceeds_limit

400 · not retryable as is. This debate could cost more than the per-debate maximum; use fewer models or a shorter length.

idempotency_key_invalid

400 · not retryable as is. Send an idempotency_key of 8 to 128 letters, digits or the characters . _ : -

idempotency_conflict

409 · not retryable as is. This idempotency_key was already used for a different request; use a new key for a different request.

in_progress

409 · retry after about 5 seconds. The first attempt with this key is still running; wait, then repeat the same call to get its result.

rate_limited

429 · retry after the next minute starts. Too many requests; slow down and retry after the wait.

concurrency_limit

429 · retry after about 15 seconds. Too many debates are already running for this key or account; wait for one to finish.

panel_unavailable

409 · not retryable as is. The requested models are not available on this account's panel; list the providers and choose from them.

question_too_large

413 · not retryable as is. The question is over the size limit; shorten it.

kill_switch

503 · retry after about 300 seconds. New debates are paused by the operator; retry later.

service_capacity

503 · retry after 00:00 UTC. The service's daily capacity is reached; retry after it resets at 00:00 UTC.

pricing_paused

503 · not retryable as is. Debates for this connection are paused for a pricing check; contact support.

too_many_failed_runs

429 · retry after 00:00 UTC. Too many debates did not finish today; retry after 00:00 UTC.

terms_required

403 · not retryable as is. The account owner must accept the current terms in the dashboard.

account_suspended

403 · not retryable as is. Billing is suspended for this account; the owner must resolve it in the dashboard.

account_closing

409 · not retryable as is. The account is closing or closed.

invalid_request

400 · not retryable as is. A field is missing, unknown or malformed (see the message); fix the request.

unsupported_version

400 · not retryable as is. Send a supported version header.

unauthorized

401 · not retryable as is. The service token is wrong; this is a configuration error, not for end users.

not_found

404 · not retryable as is. No such route or resource.

service_unavailable

503 · retry after about 10 seconds. Billing is temporarily unavailable; retry shortly with the same idempotency_key.

internal_error

500 · retry after about 10 seconds. Unexpected failure; retry once with the same idempotency_key.

proxy_headers_rejected

400 · not retryable as is. Remove proxy headers from requests to this listener.

forbidden

403 · not retryable as is. This listener or route is not available to you.

too_many_failed_attempts

429 · retry after about 60 seconds. Too many failed authentication attempts; wait a minute.

unhealthy

503 · retry after about 10 seconds. The service is not healthy; retry shortly.

MCP endpoint responses

The MCP endpoint at https://pilot.e3d.ai/mcp answers with plain HTTP statuses before a tool runs.

StatusMeaning
401The key is missing, wrong, revoked or expired.
403The request came from a browser origin that is not allowed.
405Only POST (and DELETE to end a session) are supported; there is no event stream.
406The client must accept application/json.
415The body must be application/json.
429Too many requests; wait for Retry-After.
503The server is busy; retry after Retry-After.

A refusal for credits, limits or suspension arrives as a tool result that explains why; see Credits and billing.

Limits

ScopeLimit
Sign-in10 per minute per address, plus a wait of 1, 2, 4 ... up to 60 seconds after consecutive failures for one email
Sign-up5 per hour per address
Forgot password and resend code5 per hour per address and 3 per hour per email
Email me a code10 starts per hour per address and 3 per hour per email; 20 attempts per hour per address, and 5 attempts per email per hour across all codes
Verification and reset codes5 attempts per code (sign-in codes are valid 10 minutes)
Password confirmation5 per 10 minutes per session
Dashboard reads120 per minute per session
Dashboard changes30 per minute per account
Keys25 per account
Sessions10 per account
Request body64 KiB

Spending limits reset at 00:00 UTC. Each key can have a cap per day, month or in total (a default daily cap applies when you set none), and an account-wide daily ceiling covers everything the account spends. Reaching either answers limit_reached; running out of credits answers insufficient_credits. The usage page shows what was charged to the website and to each key.