Errors and retries
Interpret problem details and recover safely from validation, conflict, and rate-limit responses.
API v3 returns every non-2xx response as an RFC 9457 problem document with the media type application/problem+json. Branch on status and code, not on title or prose.
Problem shape
{ "type": "https://www.signcustomiser.com/help/api/problems/invalid-pricing-model", "title": "Invalid pricing model", "status": 422, "code": "invalid_pricing_model", "detail": "frame_fit customisers cannot use letter price lists.", "errors": [ { "pointer": "/pricing_model", "code": "unsupported_value", "allowed_values": ["simple_letter", "advanced_letter", "frame_fit"] } ], "request_id": "req_..."}Every problem has type, title, status, code, detail, and request_id.
typelinks to documentation for the problem class.codeis the stable machine identifier. Its meaning does not change within v3.detaildescribes this occurrence and can change. Do not parse it.request_idis safe to record and is the value to include when asking for support.errorsappears when the server has field-level details. A body field uses a JSON Pointer such as/pricing_model; a query error may identify aparameterinstead. Enum errors includeallowed_values.
Do not assume errors is present. Authentication, authorisation, rate-limit, conflict, and server problems often have enough information at the top level.
Decide by status and code
| Status | Meaning | Recovery |
|---|---|---|
400 | The request could not be parsed. | Fix its syntax or content type. Do not retry it unchanged. |
401 | The credential is missing, invalid, expired, or revoked. | Replace the key or bearer header. |
403 | The key is valid but lacks access. | For insufficient_scope, compare required_scopes with granted_scopes. |
404 | The resource is unknown or does not belong to this Store. | Refresh the Store-scoped resource list; do not use the response to infer another Store’s data. |
409 | The request conflicts with current state. | Resolve the named conflict. Idempotency conflicts have the special rules below. |
422 | The request is valid JSON but violates the contract. | Correct the fields named by errors; use allowed_values rather than guessing. |
429 | The key has reached a rate or workload limit. | Wait for Retry-After, then retry as described below. |
5xx | The server failed to complete the request. | Retry with backoff. Preserve the same idempotency key and body for writes. |
Retry reads
Retry a GET after a network failure, 429, or 5xx. Use capped exponential backoff with jitter. When a 429 includes a Retry-After header, wait at least that many seconds; the problem body also carries retry_after for clients that cannot inspect headers.
Do not automatically retry 400, 401, 403, 404, or 422 unchanged. Those responses need a credential, resource, or request correction first.
Retry writes with idempotency
Every v3 write with side effects accepts an Idempotency-Key header. Generate a unique value for one logical operation and keep it with that operation for at least 24 hours.
Idempotency-Key: order-018f2f16-7d52-7a66-bf71-0b90b9d6fce1If a write times out, loses its connection, returns 429, or returns 5xx, retry with the same key and byte-equivalent body. A completed operation replays its original response and includes Idempotency-Replay: true, so a transport failure does not create the resource twice.
Two conflict codes need different handling:
idempotency_key_in_flight: the first request is still running. Wait for itsretry_after, then send the same key and body again.idempotency_key_conflict: the key was already used with a different body. Do not overwrite its meaning. Correct the request, generate a new key, and submit it as a new logical operation.
A 422 validation response means the operation was not accepted. Correct the body and use a new idempotency key. The pricing validation endpoint is side-effect free and does not use idempotency.
Logging without leaking data
Record the HTTP method, path template, status, stable code, request_id, attempt number, and idempotency key identifier. Do not log API keys, bearer headers, or full request bodies. Redact customer text and personal data before attaching a problem response to a ticket.