Errors
Errors from the v1 API follow RFC 9457 (Problem Details for HTTP APIs). They're returned with Content-Type: application/problem+json and a machine-readable type URL whose trailing fragment is a stable error code you can switch on in your client.
Envelope
Section titled “Envelope”{ "type": "https://docs.buildworkpro.com/docs/api/concepts/errors#validation_failed", "title": "Validation failed", "status": 422, "detail": "email must be a valid address", "request_id": "req_8f3c1b2a", "errors": [{ "field": "email", "code": "invalid_format", "message": "must be a valid address" }]}| Field | Description |
| ------------ | ---------------------------------------------------------------- |
| type | URL pointing to docs for the specific error code. Stable. |
| title | Short human-readable summary. Same for every error of this code. |
| status | HTTP status code (also returned in the response status line). |
| detail | Human-readable explanation of this specific occurrence. |
| request_id | Echo this in support tickets to let us trace the request. |
| errors | Optional. Per-field validation breakdown on validation_failed. |
Error code catalog
Section titled “Error code catalog”| Code | HTTP | When | Retry? |
| ------------------------ | ---- | -------------------------------------------------------------------------- | ---------------------------------------- |
| bad_request | 400 | Malformed request, bad query parameter, invalid JSON. | No. Fix the request. |
| unauthorized | 401 | Missing, malformed, or invalid bearer token. | No. Re-authenticate. |
| token_expired | 401 | OAuth access token has expired. | No. Refresh the token, then retry. |
| forbidden | 403 | Authenticated, but the role lacks permission for this action. | No. The user can't do this. |
| scope_insufficient | 403 | Token is valid but doesn't carry the required scope. | No. Request a broader scope at consent. |
| subscription_inactive | 403 | The tenant has no active subscription (trial expired, payment failed). | No. The customer must update billing. |
| tenant_suspended | 403 | The tenant is suspended by platform admin. | No. Contact support. |
| not_found | 404 | Resource doesn't exist or doesn't belong to the calling tenant. | No. |
| conflict | 409 | Generic state conflict (e.g., trying to delete something already deleted). | No without context change. |
| idempotency_key_reused | 409 | Same Idempotency-Key was used for a request with a different body. | No. Use a fresh key for a new operation. |
| validation_failed | 422 | Request body or fields failed schema validation. | No. Fix the body. |
| rate_limited | 429 | Tenant or per-key rate limit exceeded. | Yes. Honor Retry-After. |
| internal_error | 500 | Unexpected server error. | Once, with a short delay. |
| service_unavailable | 503 | Temporary outage or upstream dependency down. | Yes. Exponential backoff with jitter. |
| maintenance | 503 | Planned maintenance window. | Yes. Honor Retry-After. |
Sample 422 response
Section titled “Sample 422 response”{ "type": "https://docs.buildworkpro.com/docs/api/concepts/errors#validation_failed", "title": "Validation failed", "status": 422, "detail": "Request body failed validation", "request_id": "req_b91e44d0", "errors": [ { "field": "type", "code": "invalid_enum", "message": "must be one of customer, vendor, subcontractor, supplier, employee, partner, other" }, { "field": "email", "code": "invalid_format", "message": "must be a valid email" } ]}Recommended client behavior
Section titled “Recommended client behavior”- Switch on the trailing fragment of
type(e.g.#validation_failed), notstatusortitle. The codes are stable; titles may be reworded. - Treat
internal_error,service_unavailable, andmaintenanceas retriable (see the Retry column above). Retry once forinternal_error; use exponential backoff forservice_unavailableandmaintenance. - On
rate_limited, honorRetry-Afterexactly. Don't hammer. - On
unauthorizedortoken_expired, refresh credentials before retrying. Never retry blindly with the same expired token.