Errors, limits, and configuration reference

Errors, limits, and configuration reference

This is the reference page you'll keep open in the other tab — error shapes, status codes, validation rules, and the deployment-level limits that shape what your integration can do.

For per-endpoint failure modes, see the topic docs (User Onboarding (users, KYC, terms), Market Orders (single-contract trades), Parlays (2–12 leg trades), Wallets, Webhooks (push events)).


1. Error response shapes

ErrorResponse — single business error

Returned for most 4xx and 5xx errors.

{ "error": "user already exists", "code": "user_already_exists" }

ValidationErrorResponse — per-field validation

Returned for 422 on body validation.

{
  "errors": [
    { "field": "firstName",   "message": "required" },
    { "field": "dateOfBirth", "message": "must be age 19-125" }
  ]
}

StaleTermsResponse — only on POST /users/USERID/terms 409

{ "error": "terms version stale", "code": "stale_terms", "currentTotalVersion": 8 }

Use currentTotalVersion to re-prompt the user with the right version. See User Onboarding (users, KYC, terms).


2. HTTP status codes

HTTPMeaningCommon triggers
200OKRead, or idempotent write that already happened
201CreatedPOST /users, POST /parlays, POST /push/register
202Accepted (async)POST /market-orders — poll refId
204No ContentDELETE, POST /users/USERID/terms first-time acceptance
400Bad RequestMalformed JSON, bad query params
401UnauthorizedJWT missing/invalid, subUSERID
402Payment RequiredInsufficient balance (parlays)
404Not FoundBad UUID, INDIVIDUAL ISV reading /wallets without sub
409ConflictDuplicate user, stale terms version, push already registered, non-zero balance on delete
422UnprocessableField validation, KYC pending, insufficient liquidity, immutable field touched
500Internal Server ErrorUnhandled backend failure

3. Common error codes

codeHTTPTriggered by
user_already_exists409POST /users — identity hash (name + DOB + SSN) collides
user_not_found404Any user-scoped path with an unknown UUID
user_pending_kyc409/422GET /users/USERID before the user is verified (409), or trying to trade before KYC has resolved (422)
non_zero_balance409DELETE /users/USERID while balance > 0 (INDIVIDUAL ISVs)
stale_terms409POST /users/USERID/terms with an out-of-date totalVersion
INVALID_CONTRACT400/422Unknown or stale contractId on order endpoints
internal_server_error500Unhandled backend failure

4. Request validation rules

CreateUserRequest

FieldRule
firstName, lastNameRequired, non-empty. Immutable.
dateOfBirthRequired. YYYY-MM-DD. Age 19–125. Immutable.
ssnLastDigitsRequired. Exactly 4 numeric digits. Immutable.
addressLine1, cityRequired.
stateRequired. 2-letter USPS code.
zipRequired. 5–10 chars.
countryCodeRequired. ISO 3166 alpha-2.
phoneNumberOptional. If given, 10 numeric digits, unformatted.
emailOptional. If given, valid email format.
emailVerifiedAtRequired. UTC timestamp.
phoneVerifiedAtOptional. UTC timestamp.

UpdateUserRequest

Same field-level rules as above, but all fields are optional, and firstName / lastName / dateOfBirth / ssnLastDigits must not appear. Including any of them returns 422.

EstimateMarketOrderRequest

FieldRule
contractIdRequired.
quantityRequired. >= 0 (use 0 to peek the best price).

SubmitMarketOrderRequest

FieldRule
contractIdRequired.
quantityRequired. > 0 (strict).

CreateParlayRequest

FieldRule
legsRequired. 2–12 items.
legs[].eventId, marketId, outcomeIdRequired. > 0.
legs[].contractIdRequired.
legs[].strikeOptional (spreads/totals).
quantityRequired. > 0.

ConfirmParlayRequest

FieldRule
quantityRequired. > 0. Must not exceed offer.maxQuantity from the quote.

AcceptTermsRequest

FieldRule
totalVersionRequired. > 0.

GET /wallets/transactions query

FieldRule
limitOptional. Integer in 1..200. Defaults to 50.
beforeOptional. Integer. Pass nextCursor from a previous response.

5. Auth-level constraints

ConstraintValue
JWT max exp - iat< 300 seconds
JWT nbf/iat clock skew±30 seconds
subUSERID match on user routesRequired
digest claimBase64URL(SHA256(body)), no padding
subsig claimBase64URL(HMAC-SHA256(secret, "::")), no padding

See Authentication.


6. Webhook delivery limits

SettingDefaultEffect
Delivery timeout5 sYour receiver must respond 2xx within this window.
Error threshold3 consecutive failuresReceiver gets paused; resumes when GET /health returns 200.
Retry delay10 sTime between retries.
Message max age24 hOlder messages are dropped, not delivered.

See Webhooks (push events).


7. Quick lookup: "what does this status code usually mean?"

A field guide for log triage.

You see...First look at...
401 on every callJWT generation — check alg=EdDSA, kid==iss, aud="prophetx", clock skew, base64 padding
401 on USERID routes onlysub claim ≠ USERID; or missing subsig
402 on parlay confirmUser balance vs. fee + quantity
404 on /wallets with no subYou're INDIVIDUAL, there's no pot — call with sub for the user wallet
409 user_already_existsSame person, different account — identity hash collision
409 stale_termsRe-fetch /terms, show the new version, re-prompt
409 non_zero_balanceSettle, refund, or withdraw before deleting (INDIVIDUAL)
422 INVALID_CONTRACTStale contractId — re-fetch markets
422 user_pending_kycWait for GET /kyc-status to read SUCCESS
Parlay failReason: "price moved"Re-quote with the same legs