View Markdown

Errors

One error shape, a named code for every failure, and a docs link in each.

Every error, on every endpoint, is the same shape:

json
{
  "error": {
    "code": "account_not_funded",
    "message": "The venue account 0x7e15…51f9 holds $0.00; this venue requires at least $5 to start.",
    "docs_url": "https://docs.superior.trade/runtime/credentials",
    "details": null
  }
}
  • code — stable, machine-readable, never reworded. Branch on this.
  • message — human-readable, specific to the instance (real values, not placeholders).
  • docs_url — the page that explains the fix. Agents: fetch it as markdown via /<path>.md.
  • details — structured extras where they exist (validation line numbers, coverage windows).

Every response — success or error — also carries an x-request-id header. Quote it in any support conversation; it's how we find your exact request in our logs.

Code registry#

HTTPCodeAreaNotes
401unauthorizedauthAPI key or authenticated Privy session is missing, invalid, or not accepted for this route
429rate_limitedauthHonor retry-after — see rate limits
400email_not_allowedaccountDisposable/blocked domain
400invalid_otpaccountWrong or superseded code
400otp_expiredaccountCode older than 10 minutes
429too_many_attemptsaccount5 failed tries burns the code
409key_limit_reachedaccount10 active keys max
400insufficient_held_balanceaccountArbitrum wallet withdrawal exceeds held_usd
400invalid_withdrawal_sourceaccountSend arbitrum or hyperliquid explicitly
400no_login_walletaccountVerify a login wallet before withdrawing
400idempotency_key_requiredaccountWithdrawals must send the header
400withdrawal_otp_required, invalid_codeaccountSupply the active challenge and six-digit withdrawal code
409withdrawal_destination_unavailable, withdrawal_challenge_mismatchaccountRegister the destination or request a challenge for the current amount
409idempotency_key_conflict, withdrawal_state_conflictaccountKeep the same key and body; never switch to a new key while a withdrawal may be in progress
409withdrawal_source_unavailableaccountThe source is coming soon or unavailable; do not fall back automatically
410code_expiredaccountRequest a new withdrawal OTP
429resend_cooldown, email_limit_reached, attempt_limit_reachedaccountWait for the applicable OTP limit to reset
502wallet_upstream_unavailableaccountThe managed-wallet provider could not prepare the withdrawal; retry later with the same key
503withdrawal_sponsorship_unavailableaccountSponsored Arbitrum submission is unavailable; retain the same key and never send unsponsored
503wallet_repository_unavailableaccountRetry later with the same key; do not create a replacement key
400unknown_venuecontext
400unknown_symbolcontext
404data_unavailablecontextCovered window in details
400window_too_largecontextSplit the request
400unsupported_framework_venueruntimeCheck the venue matrix
400strategy_invalidruntimeFramework diagnostics in details
400config_invalidruntimeOffending key named in details
400credential_in_configruntimeSecrets go in credentials, never config
409name_takenruntimeDeployment name is unique per account — a retried create hitting this means the first attempt succeeded
400credential_scope_unsaferuntimeMaster/withdrawal-capable key rejected by default; override with allow_unscoped_credential + acknowledgement fields (credentials)
400credentials_missingruntimeAttach credentials before starting live
400credentials_invalidruntimeVenue rejected the key (revoked agent, bad permissions)
402account_not_fundedruntimeBelow the venue's min_deposit_usd
409deployment_limit_reachedruntimePlan cap — see usage
429limit_exceededruntimeConcurrent backtest slots full
409positions_openruntimeOn delete; force requires body acknowledgement
409already_runningruntime
409not_runningruntime
422exchange_rejectedruntimeThe venue rejected a typed place or cancel action (executions)
502venue_unavailableruntimeThe order venue could not be reached; retry with the same Idempotency-Key
503execution_persistence_failedruntimeThe venue result could not be durably recorded; do not retry with a new Idempotency-Key
500internal_errorserverOur fault — x-request-id please
503runtime_unavailableserverControl plane can't reach the cluster; running strategies are unaffected

Design commitments#

  1. Distinct problems get distinct codes. "Not onboarded" is not "not funded"; an agent must be able to pick the right fix without parsing prose. (This is a direct lesson from the current API, where a missing agent wallet surfaced as a funding error.)
  2. Codes are append-only. New failure modes add codes; existing codes never change meaning.
  3. 5xx means us, 4xx means the request. A venue rejecting your key is a 4xx (credentials_invalid) — it's actionable by you. Our cluster being unreachable is a 5xx — retry later, we're paging someone.
  4. Creates are retry-safe; money movement demands it. POST /runtime/deployments and /runtime/backtests accept an Idempotency-Key; /runtime/executions and /wallet/withdraw require it. Execution replays return the durable completed order record.
  5. Destructive overrides are never a query flag. Deleting around open positions takes an explicit body acknowledgement (force + acknowledge_positions_open) — never a query flag.