Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.calmtreasury.xyz/llms.txt

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

Envelope

Every non-2xx response shares this shape:
{
  "error": {
    "code":    "validation_error",
    "message": "Validation error",
    "details": { /* optional, on 400 only */ }
  }
}
  • code — stable, machine-readable, snake_case. Branch on this.
  • message — human-readable, may change wording.
  • details — optional structured context (e.g. zod field errors).

Auth + session

CodeStatusWhen
no_access_token401SDK’s getAccessToken() returned null. User isn’t signed in.
token_required401Missing Authorization: Bearer … on POST /v1/session.
invalid_token401JWT signature/claims invalid, malformed, or aud missing.
token_expired401JWT past its exp.
wallet_not_linked403Privy identity token has no linked_accounts wallet entry.
session_required401Cookie missing on a wallet route. Call POST /v1/session.
session_invalid401Cookie failed verification or expired. Re-bootstrap.
wallet_token_mismatch403URL :address doesn’t match the cookie’s bound wallet.

Wallet routes

CodeStatusWhen
invalid_wallet400URL :address isn’t a valid 0x-prefixed Ethereum address.
customer_not_registered404No row yet for (app_id, wallet). Call POST /v1/wallets/:address.
already_registered409This wallet is already registered for this app.
validation_error400Request body failed schema check. details has the zod errors.
email_already_in_use400Bridge rejected — email belongs to another customer in the dev account.

Virtual account

CodeStatusWhen
kyc_required409Bridge customer status isn’t active. Finish KYC first.
already_has_virtual_account409Wallet already has a VA. Use GET instead.
virtual_account_not_provisioned404No VA exists yet for this wallet. Use POST to create one.

Upstream

CodeStatusWhen
bridge_error502Bridge call failed (timeout, 5xx, or unexpected response). Safe to retry.

Tips

For browser code, treat all 401s as “re-bootstrap the session”:
try {
  return await calm.wallets.get(wallet);
} catch (err) {
  if (err instanceof CalmApiError && err.status === 401) {
    await calm.session();        // re-bootstrap, sets a fresh cookie
    return await calm.wallets.get(wallet);
  }
  throw err;
}
Don’t branch on err.message. We may change wording without notice. Branch on err.code only.