Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.kash.bot/llms.txt

Use this file to discover all available pages before exploring further.

Every error response from api.kash.bot follows RFC 7807 Problem Details with Content-Type: application/problem+json.

Wire shape

{
  "type":     "https://docs.kash.bot/developer-docs/api-errors/INSUFFICIENT_SCOPE",
  "title":    "Insufficient scope",
  "status":   403,
  "code":     "INSUFFICIENT_SCOPE",
  "detail":   "This route requires the 'trades:write' scope. The supplied API key does not include it.",
  "instance": "/v1/trades",
  "requestId": "req_01HZ..."
}
FieldUse
typeURI of the per-code documentation page (RFC 7807 §3.1). Stable; safe to fetch.
titleShort human-readable summary.
statusThe HTTP status (echoed for clients that lose it).
codeStable machine-readable string. Branch on this; never on title or detail.
detailSanitised human-readable explanation. May reference the specific bad input.
instanceURI of the request that produced this error.
requestIdTrace handle. Include in support tickets — gets you straight to the right span in our backend.

How to handle errors

Branch on code, not on status or message text. Status codes are coarse (a 400 could mean any of a dozen specific failures); code is the unambiguous identifier.
try {
  await kash.trades.create(body);
} catch (err) {
  if (err instanceof KashError) {
    switch (err.code) {
      case 'INSUFFICIENT_SCOPE':
        // Re-issue the key with `trades:write`.
        break;
      case 'RATE_LIMIT_EXCEEDED':
        await sleep(err.retryAfterMs ?? 1000);
        // retry
        break;
      case 'IDEMPOTENCY_KEY_CONFLICT':
        // Same key was used with a different body. Either replay the
        // original body or generate a new key.
        break;
      // ...
    }
  }
  throw err;
}
The TypeScript SDK throws typed subclasses (KashRateLimitError, KashAuthorizationError, etc.) so you can catch by error type as well.

Status code conventions

StatusWhen
200Successful read.
201Successful resource creation (immediate).
202Accepted, work in progress (high-value trade pending confirmation; redelivery).
304If-None-Match cache hit — no body. See ETags.
400Validation failure on the request itself (VALIDATION_FAILED, malformed JSON).
401Auth failure (API_KEY_MISSING, API_KEY_INVALID, API_KEY_REVOKED, REQUEST_SIGNATURE_INVALID).
403Authenticated but not authorised (INSUFFICIENT_SCOPE, IP_NOT_ALLOWED).
404Resource doesn’t exist (or doesn’t exist to you — ownership-checked routes return 404 not 403 to prevent enumeration).
409Conflict (IDEMPOTENCY_KEY_CONFLICT, SPENDING_LIMIT_EXCEEDED, TRADE_NOT_AWAITING_CONFIRMATION, INSUFFICIENT_BALANCE, etc.).
410Gone (a previously valid resource is permanently removed).
422Semantically valid but rejected by domain rules (e.g. MARKET_NOT_TRADEABLE).
429Rate limit exceeded. Honour Retry-After.
500Server bug. Include requestId when reporting.
502Upstream dependency error (RPC, DB).
503Route temporarily disabled (ROUTE_DISABLED) or dependency unavailable.
504Upstream timeout.

Error code catalog

Every code has a stable per-page documentation entry at https://docs.kash.bot/developer-docs/api-errors/<CODE> — see the Error catalogue for the full index. The type field on every error is exactly that URL — copy-paste it into a browser to read the page, or fetch it programmatically. The CLI ships an offline copy of the full catalog. kash explain <CODE> works without a network round-trip:
kash explain INSUFFICIENT_SCOPE
Common codes to know:
CodeWhen it fires
API_KEY_MISSINGNo X-API-Key header.
API_KEY_INVALIDKey not recognised or HMAC mismatch.
API_KEY_REVOKEDValid format, but the key has been revoked.
API_KEY_EXPIREDKey is past its expires_at timestamp.
INSUFFICIENT_SCOPEKey lacks the scope this route requires.
IP_NOT_ALLOWEDSource IP not in this key’s allowlist.
RATE_LIMIT_EXCEEDEDPer-key quota exceeded. Honour Retry-After. The cap is tier-differentiated — see Rate Limits.
SPENDING_LIMIT_EXCEEDEDTrade would exceed the key’s per-trade or daily cap. The extensions.cap field is per_trade or daily_volume. Caps are tier-differentiated — see Rate Limits for the matrix and upgrade path.
VALIDATION_FAILEDRequest body or query failed schema validation.
IDEMPOTENCY_KEY_CONFLICTSame Idempotency-Key reused with a different body. See Idempotency.
MARKET_NOT_TRADEABLEMarket is FROZEN/RESOLVED, on an unsupported chain, or otherwise inactive.
INSUFFICIENT_BALANCESmart account doesn’t have enough USDC for the trade.
TRADE_NOT_AWAITING_CONFIRMATIONConfirm called on a trade that’s not in pending_confirmation.
CONFIRMATION_TOKEN_INVALIDConfirmation token didn’t match.
CONFIRMATION_TOKEN_USEDConfirmation token already redeemed (or by a concurrent confirm).
CONFIRMATION_EXPIREDConfirmation window passed; the trade auto-failed.
RESOURCE_NOT_FOUNDTrade/market/event id doesn’t exist (or doesn’t belong to you).
DEPENDENCY_UNAVAILABLEUpstream (DB, chain RPC) is degraded. Treat like Retry-After.
ROUTE_DISABLEDOps kill switch is active for this route.
WEBHOOK_REPLAY_LIMIT_REACHEDMore than 5 manual redeliveries for the same event.
WEBHOOK_SECRET_ROTATION_COOLDOWNWebhook-secret rotation called within 60s of a prior successful rotation. Protects the rollback slot — see Secret Rotation.
REQUEST_SIGNATURE_INVALIDOpt-in body-signing on POST /v1/trades failed verification.
The full list lives at the Error catalogue. The CLI’s offline copy and these docs pages are both generated from the same source-of-truth markdown at release time, so they stay in sync.

What’s NOT in errors

Defensive design choices to be aware of:
  • No stack traces. Internal stack frames are stripped before the response.
  • No DB error strings. Postgres / RPC errors are sanitised to user-safe messages.
  • No URLs with credentials. Defence-in-depth scrubbing in case anything slips into a log line.
  • 404 instead of 403 for ownership. Trying to GET someone else’s trade returns RESOURCE_NOT_FOUND, not FORBIDDEN. This prevents id-enumeration attacks (you can’t tell whether a UUID exists if it’s not yours).
  • Generic DEPENDENCY_UNAVAILABLE when upstream fails. We deliberately hide which upstream — DB vs RPC vs Redis — to avoid leaking architecture detail to attackers. Your requestId lets us correlate to the precise root cause server-side.

Reporting bugs

Include the requestId when emailing [email protected] or filing an issue on the relevant public mirror (SDK · CLI · Protocol SDK (TS) · Protocol SDK (Python)). One id is enough — we can pull the full distributed trace, every event, and every retry attempt from it.

Next

Idempotency

Safely retry trade creation without producing duplicates.

Pagination

Cursor-based, never offset. How to walk a list endpoint.