For AI agents: visit https://isv-docs.prophetx.co/llms.txt for an index of all pages formatted in Markdown and endpoints in OpenAPI. Append .md to any documentation page URL to get its markdown version.
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.
DELETE, POST /users/USERID/terms first-time acceptance
400
Bad Request
Malformed JSON, bad query params
401
Unauthorized
JWT missing/invalid, sub ≠ USERID
402
Payment Required
Insufficient balance on POST /parlays/{id}/confirm. Not used by POST /market-orders — that endpoint accepts the order with 200 status=pending and lets the matching engine cancel it. See Market Orders.
403
Forbidden
IP geo-gate denial (GEO_BLOCKED) or a required permission not granted for the user (x-required-permission on the endpoint). Surface as ForbiddenError.
404
Not Found
Bad UUID, INDIVIDUAL ISV reading /wallets without sub
409
Conflict
Duplicate user, stale terms version, push already registered, non-zero balance on delete
422
Unprocessable
Field validation, KYC pending, insufficient liquidity, immutable field touched
500
Internal Server Error
Unhandled backend failure
3. Common error codes
code
HTTP
Triggered by
user_already_exists
409
POST /users — identity hash (name + DOB + SSN) collides
user_not_found
404
Any user-scoped path with an unknown UUID
user_pending_kyc
409/422
GET /users/USERID before the user is verified (409), DELETE /users/USERID on any user who hasn't reached SUCCESS (409 — the code says "pending" but the check is "not verified", so FAILURE / MORTALITY / PEP / OFAC users hit this too), or trying to trade before KYC has resolved (422)
non_zero_balance
409
DELETE /users/USERID while balance > 0 (INDIVIDUAL ISVs)
stale_terms
409
POST /users/USERID/terms with an out-of-date totalVersion
kyc_not_retryable
409
POST /users/USERID/kyc-retry when the user isn't in FAILURE status or when the per-ISV retry limit has been exhausted. Check GET /kyc-status to tell them apart — a FAILURE user that still returns this code means retries are exhausted. See User Onboarding.
address_not_found
422
POST /validate-address — Smarty could not find a match for the submitted US address. Ask the user to correct and re-validate before you try to create the user.
limit_exceeded
4xx
Surfaces on the embedded UI's AeroPay or PayNearMe deposit/withdraw calls when the requested amount would exceed a configured per-user cap (daily, pending, or per_tx). Body includes kind (which cap), limit, and remaining. Not called from the ISV backend — the embedded UI reads limits and enforces this itself. See Embedded UI.
INVALID_CONTRACT
400/422
Unknown or stale contractId on order endpoints
GEO_BLOCKED
403
The client_ip claim resolves to a non-licensed jurisdiction. Surface to the user as a region notice, not an auth error. See Authentication.
permission_denied
403
The user lacks a permission required by the endpoint (x-required-permission on the spec). Inspect GET /users/USERID/permissions to see which permissions are granted and any denyReason. The response body may include pending_gates: ["<gate>", …] — the specific gates blocking the permission. A pending_gates: ["not-suspended"] value specifically means the user is currently suspended (see User Onboarding).
internal_server_error
500
Unhandled backend failure
4. Request validation rules
CreateUserRequest
Field
Rule
firstName, lastName
Required, non-empty. Immutable.
dateOfBirth
Required. YYYY-MM-DD. Age 19–125. Immutable.
ssnLastDigits
Required. Exactly 4 numeric digits. Immutable.
addressLine1, city
Required.
state
Required. 2-letter USPS code.
zip
Required. 5–10 chars.
countryCode
Required. ISO 3166 alpha-2.
phoneNumber
Optional. If given, 10 numeric digits, unformatted.
email
Optional. If given, valid email format.
emailVerifiedAt
Required. UTC timestamp.
phoneVerifiedAt
Optional. 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
Field
Rule
contractId
Required.
quantity
Required. >= 0 (use 0 to peek the best price).
SubmitMarketOrderRequest
Field
Rule
contractId
Required.
quantity
Required. > 0 (strict).
expectedAveragePrice
Required. Integer (American price). Echo back from the /estimate response.
priceList
Required. Non-empty list[int]. Echo back from the /estimate response — at least one level required. The backend rejects the submit if the live price has moved off these levels.
CreateParlayRequest
Field
Rule
legs
Required. 2–12 items.
legs[].eventId, marketId, outcomeId
Required. > 0.
legs[].contractId
Required.
legs[].strike
Optional (spreads/totals).
quantity
Required. > 0.
ConfirmParlayRequest
Field
Rule
quantity
Required. > 0. Must not exceed offer.maxQuantity from the quote.
AcceptTermsRequest
Field
Rule
totalVersion
Required. > 0.
GET /transactions query
Field
Rule
limit
Optional. Integer in 1..200. Defaults to 50.
before
Optional. Integer. Pass nextCursor from a previous response.
5. Auth-level constraints
Constraint
Value
JWT max exp - iat
< 300 seconds
JWT nbf/iat clock skew
±30 seconds
sub ↔ USERID match on user routes
Required
digest claim
Base64URL(SHA256(body)), no padding
subsig claim
Base64URL(HMAC-SHA256(secret, "::")), no padding
client_ip claim
Required on user-scoped routes when geofencing is enabled. Plain IPv4/IPv6 string of the end user's IP, not your server's. Missing / private / non-licensed → 403 GEO_BLOCKED.
Inbound webhook signing
EdDSA (Ed25519). Verify with the ProphetX public key.