Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.adipredictstreet.com/llms.txt

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

Authentication

CodeHTTPMeaning
auth_required401X-Api-Key header missing on an authenticated endpoint
api_key_bad_format401X-Api-Key header didn’t match ps_<env>_<keyId>_<secret> shape
api_key_unknown_key401keyId not found in the registry (typo, wrong environment, or revoked long ago and garbage-collected)
api_key_bad_secret401Stored hash didn’t match — wrong secret
api_key_revoked401Key was explicitly revoked via admin
api_key_expired401Key’s expiresAt has passed
api_key_suspended401Partner was suspended — all their keys stop working until reactivation
api_key_ip_denied401Caller IP not in the key’s ipAllowlist
api_key_no_associated_wallet401single_wallet partner has no associatedWallet attached — admin must attach one before authenticated endpoints work
api_key_user_wallet_required401multi_wallet partner: X-User-Wallet header missing on an authenticated request
api_key_user_wallet_invalid401multi_wallet partner: X-User-Wallet header value isn’t a 0x + 40-hex address
api_key_scope_missing403Key lacks the scope required by this endpoint; response body includes requiredScope + have[]
wallet_banned403The request’s effective wallet (associated or X-User-Wallet) is on the banned list

Trading

CodeHTTPMeaning
invalid_amounts400price or quantity ≤ 0 or bad format
invalid_tif400MARKET+GTC rejected
bad_signature400EIP-712 recover failed (see diagnostic hints below)
order_signed_with_floor_notional400BUY.makerAmount was FLOOR-rounded; CEIL is required to keep matcher math from overflowing the maker cap on chain. details carries signedMakerAmountWei + expectedCeilMakerAmountWei — re-sign with the latter. See diagnostic hints below.
fee_too_high400feeRateBps > MAX_FEE_RATE_BIPS (1000)
expired400Order expiration in the past
invalid_outcome400Outcome index out of range
maker_mismatch400Order.maker doesn’t equal the authenticated wallet OR its bound vault — for multi_wallet partners using X-User-Wallet, maker MUST be the sub-account’s wallet (or the vault auto-deployed for it). See diagnostic hints below
wallet_mismatch401Legacy alias of maker_mismatch still surfaced by some withdrawal / vault / position endpoints — same semantics. Treat identically; we are converging the order surface on maker_mismatch and the rest of the API will follow
insufficient_funds200 (envelope)Balance overdraft
market_not_open409Market status ≠ OPEN
idempotency_race500Internal race on (wallet, clientOrderId)
matcher_error200 (envelope)Matcher returned a business error
exchange_unavailable503Exchange-service / matcher unreachable

Orders

CodeHTTPMeaning
order_not_found404Order ID doesn’t exist for this wallet
not_cancellable409Order already terminal
forbidden403Order belongs to a different wallet

Withdrawals

CodeHTTPMeaning
invalid_amount400Amount ≤ 0
bad_signature400User EIP-712 signature invalid
destination_not_cleared200 (envelope)New destination below EDD threshold
new_destination_edd200 (envelope)New destination above EDD → MLRO review
wallet_banned200 (envelope)Destination on banned-wallets list
aml_blocked200 (envelope)Destination failed AML screen
invalid_state409Tried to cancel after SUBMITTED
withdrawal_not_found404Withdrawal ID doesn’t exist (or doesn’t belong to the authenticated wallet). Same code on GET /api/me/withdrawals/{id} and POST /api/me/withdrawals/{id}/cancel.

Rate limits

CodeHTTPMeaning
rate_limited429Bucket exhausted; retry after retryAfterSec

Service-level

CodeHTTPMeaning
exchange_unavailable503Upstream service temporarily unavailable — retry with backoff
exchange_transport_error503Connection failed
exchange_malformed_response503Non-JSON response
not_implemented501Feature disabled in this env

Handling strategy

  • 4xx codes — fix the client.
  • 200 with code — business logic reject; surface to user.
  • 429 — wait retryAfterSec then retry.
  • 5xx — exponential backoff with jitter; 3 attempts max for idempotent calls. Non-idempotent writes use clientOrderId / nonce
    • deadline for safe retries.

bad_signature diagnostic hints

When POST /api/orders/place rejects with code: bad_signature, the response body’s details block carries enough context to diff your client struct against what the platform reconstructed. This turns a 24-hour blind debug into a 30-second visual diff:
{
  "code": "bad_signature",
  "message": "EIP-712 signature invalid",
  "details": {
    "recovered":        "0xRecoveredFromYourSig",
    "expected_signer":  "0xYourAuthenticatedWallet",
    "platform_canonical_struct": {
      "salt":          "12345...",
      "maker":         "0xVaultAddr",
      "signer":        "0xYourEoa",
      "taker":         "0x0000000000000000000000000000000000000000",
      "tokenId":       "999...",
      "makerAmount":   "55000000",
      "takerAmount":   "100000000",
      "expiration":    "0",
      "feeRateBps":    "140",
      "side":          0,
      "signatureType": 1
    }
  }
}
recovered ≠ expected_signer ⇒ the digest you signed differs from what the platform reconstructs. Compare your client-side struct field-by-field against platform_canonical_struct. The most common mismatch is feeRateBps: per-market value lives at market.feeTakerBps (GET /api/markets/{slug}) and MUST be signed verbatim — signing 0n while the platform reconstructs with 140 gives different digests and recovers a different address. recovered: null ⇒ signature wasn’t a valid EIP-712 sig at all (missing, malformed hex, wrong length). Re-sign and resend. Both addresses are checksum-cased — partner clients can compare with recovered === expected_signer directly. Every value in platform_canonical_struct is either user-supplied (already known to the partner) or platform-public market metadata, so no privacy concerns from logging the response.

maker_mismatch diagnostic hints

maker_mismatch (and its legacy alias wallet_mismatch on the non-order surfaces) is the platform’s authorization check that the off-chain order signer can actually instruct the on-chain custody contract that will be debited at settlement. Specifically:
order.maker MUST equal EITHER
  - the authenticated wallet (X-User-Wallet, lowercased), OR
  - VaultFactory.vaultOf(authenticated wallet) on this chain
Three patterns produce this rejection in the wild: 1. Signing-wallet ↔ authenticated-wallet drift. The most common. You’re signing as EOA A while authenticating as wallet B. This always fails — even when A === VaultFactory.vaultOf(B) on chain. The check is per-request: X-User-Wallet is the principal, order.maker is the counterparty in the signed payload, and the two are compared after resolving the principal’s vault. Reuse of an operator’s session to sign for another user’s vault is rejected by design — signer-of-record and authenticated-of-record are bound 1:1 even when the EOA is technically authorised on multiple vaults on-chain. Each end-user vault must be addressed under its own authenticated session. 2. Stale local vaultOf cache during the deploy/observe race. If you’ve recently rotated to vault-direct signing (order.maker == vault), make sure your local vaultOf(wallet) cache is fresh. Order placement happens during a brief window where the on-chain vault may already exist but the off-chain mirror hasn’t yet observed the VaultDeployed event. The placement handler re-reads the chain on cache miss, so the platform-side resolution is correct — but a stale value held by your client will pre-fail the check on your side before the request even reaches us. 3. Vault-not-yet-deployed. Legitimate maker_mismatchVaultFactory.vaultOf(wallet) resolves to null and only the plain-wallet form of order.maker is accepted. Deploy the vault first, then retry. The vault-deploy signedOp flow lives at POST /api/me/vault/deploy/signPOST /api/me/vault/deploy/submit. The HTTP status differs by surface:
  • POST /api/orders/place returns 400 (current order endpoint) — rejected at the EIP-712 maker resolution step before the order ever reaches the matcher.
  • Legacy withdrawal / vault / position endpoints still throw the alias wallet_mismatch as 401 (UnauthorizedException).
Treat both as the same condition. Diagnose with the three patterns above; the fix in all three cases is on the client side.

order_signed_with_floor_notional diagnostic hints

When POST /api/orders/place rejects with code: order_signed_with_floor_notional, the user signed a BUY order whose makerAmount was computed with integer FLOOR division ((priceWei * qtyWei) / 1_000_000n in JS — BigInt division truncates toward zero). For boundary tuples where price × qty doesn’t divide cleanly into 6-decimal wei, FLOOR underflows the canonical CEIL by 1 wei. Why we reject: FLOOR-signed BUY orders sit on the book with zero wei of headroom against the matcher’s per-fill CEIL math. On the closing tail fill of a multi-leg cross-outcome batch, the cumulative maker_fill_amount_wei overshoots the signed makerAmount by 1 wei → chain reverts MakingGtRemaining (selector 0xe2cc6ad6) → the TAKER absorbing this order (a different user, not the FLOOR signer) sees the failure. Rejecting at placement prevents the poison from reaching the book at all. Response envelope shape:
{
  "status": "REJECTED",
  "code": "order_signed_with_floor_notional",
  "message": "Order signed with FLOOR-rounded BUY notional (makerAmount=34999999 wei). CEIL is required to keep matcher math from overflowing your maker cap on chain — re-sign with makerAmount=ceil(price × qty / 1e6) = 35000000. See the EIP-712 signing reference for the canonical formula.",
  "details": {
    "signedMakerAmountWei": "34999999",
    "expectedCeilMakerAmountWei": "35000000",
    "signedRounding": "FLOOR",
    "expectedRounding": "CEIL"
  }
}
Fix: patch the makerAmount to details.expectedCeilMakerAmountWei and re-sign + re-submit. The SDK shouldn’t need to recompute the formula client-side — details carries the exact integer to use. Canonical CEIL formula (TypeScript / Python identical semantics):
const product     = priceWei * qtyWei;
const notionalWei = (product + 999_999n) / 1_000_000n; // CEIL
The +1 wei vs FLOOR is sub-cent and economically meaningless, but the chain math cares about every wei. See Rounding rule section for the full asymmetric CEIL-BUY / FLOOR-SELL story. SELL orders are unaffectedSELL.makerAmount is the exact outcome-token quantity (qtyWei), no rounding involved. Only BUY hits this gate.