Errors
Every failure returns JSON with a message, and nothing else is guaranteed:
{ "message": "Vendor not found"}Two optional fields appear depending on how the request failed:
{ "message": "Invalid payment payload", "errors": [ { "path": "allocations", "code": "custom", "message": "Allocation total cannot exceed amountCents" } ]}| Field | When it appears |
|---|---|
message |
Always. Safe to show to a user for 4xx; generic for 5xx. |
errors |
Field-level validation detail. path is a dotted path into the request body. |
code |
A stable machine-readable code, on the errors that have one — for example rate_limited. |
Status codes
Section titled “Status codes”| Code | Meaning |
|---|---|
400 |
The request body, query, or path parameter did not validate. Check errors. |
401 |
Missing, malformed, or expired access token. Refresh it. |
403 |
Authenticated, but your role cannot perform this action. |
404 |
No such resource in your organization. Also returned for resources that exist elsewhere. |
405 |
The endpoint exists but the resource is system-managed — chart of accounts categories, for example. |
409 |
The request conflicts with current state: an invalid status transition, a payment that cannot be edited, a resource still in use. |
412 |
A precondition is unmet — most often online payments not yet configured for the organization. |
429 |
Rate limited. See Rate limits. |
502 |
An upstream provider (Stripe, QuickBooks, Gmail) failed. Safe to retry. |
503 |
A capability is not configured on this deployment, such as online payments or a webhook secret. |
Conflicts are not retryable
Section titled “Conflicts are not retryable”409 means the API rejected the request on purpose, and repeating it unchanged will fail
the same way. Two common cases:
- Status transitions. Work orders move
open → in_progress → completed, withcancelledreachable from either open state. Anything else is a409. - Immutable records.
PUT /api/payments/{id}always returns409; payments are reversed and recreated rather than edited.
502 and 503, by contrast, are about the environment rather than the request, and are
worth retrying with backoff.