Responses & Errors
Every endpoint across Checkout, Payout Embed, and Split returns one of two envelopes. This page is the shape reference — code samples elsewhere in these docs show only the contents of data to stay short.
Successful responses
A 2xxresponse body is always the endpoint's own payload wrapped in the same three fields:
response.json
{
"success": true,
"data": {
"orderId": "pay_...",
"provider": "STRIPE",
"checkoutMode": "REDIRECT",
"redirectUrl": "https://checkout.stripe.com/..."
},
"timestamp": "2026-08-24T18:02:11.482Z"
}success— alwaystruehere.data— the shape documented for that specific endpoint (e.g. Checkout'sorderId/redirectUrl, or a Split'sSplitResponse).timestamp— ISO 8601, when the response was generated, not when anything happened business-wise.
This envelope is for API responses only.
webhook delivery payloads (see Webhooks) are the raw event object with no { success, data } wrapper.Errors
A non-2xx response carries the same fields on every endpoint:
error.json
{
"success": false,
"statusCode": 422,
"timestamp": "2026-08-24T18:02:11.482Z",
"path": "/api/commerce/integration/checkout",
"method": "POST",
"message": "Subscriptions are only supported for Stripe checkout",
"error": "UnprocessableEntityException"
}success— alwaysfalse.statusCode— the HTTP status, duplicated in the body so you don't need to read response headers to branch on it.message— a string, or an array of strings for a request that failed multiple field validations at once (see below).error— the exception class name, useful for logging/grouping; not guaranteed to be stable across a refactor, so don't branch your integration's logic on it — branch onstatusCodeinstead.code— present on some errors as a stable machine-readable identifier; omitted when there isn't one.path/method— the request that failed, echoed back for logging.
Field validation (400)
A request body that fails validation (missing a required field, wrong type, a string over its max length) returns every failing field at once as an array, not just the first one:
validation-error.json
{
"success": false,
"statusCode": 400,
"timestamp": "2026-08-24T18:02:11.482Z",
"path": "/api/commerce/integration/checkout",
"method": "POST",
"message": [
"amountMinorUnits must be a positive integer string",
"returnUrl must be a URL address"
],
"error": "BadRequestException"
}Common status codes
- 400 — request body failed validation (see above).
- 401 — the
Authorizationheader is missing, or the API key is invalid/revoked. - 403— the API key is valid but isn't scoped for this route (e.g. calling Split without
split:write). - 404— the resource doesn't exist, or exists but belongs to a different company. Those two cases are intentionally indistinguishable — existence is never leaked across companies.
- 422 — the request was well-formed but rejected by a business rule (e.g. a subscription opt-in with
provider: "PAYPAL", or a Split roster row referencing acontractorPaymentProfileIdthat isn't an active creator). - 429— you've exceeded the per-route rate limit (each write endpoint documents its own limit). Back off using the
Retry-Afterresponse header. - 5xx — something failed on our end.
messageis always the generic "Something went wrong. Please try again." here — the real internal error is logged server-side, never sent to the client.
A 429response is built by the rate limiter itself, ahead of the rest of the API, so it doesn't carry the
success: false field the other error cases do — everything else on it (statusCode, message, error, etc.) is the same.rate-limit.json
{
"statusCode": 429,
"timestamp": "2026-08-24T18:02:11.482Z",
"path": "/api/commerce/integration/checkout",
"method": "POST",
"message": "Rate limit exceeded, retry in 1 Minute",
"error": "TooManyRequests"
}