Errors
Every error response uses the same envelope. Parse it once; handle every endpoint the same way.
Envelope
{
"error": {
"type": "https://alltogether.giving/developer/api/errors/not_found",
"code": "not_found",
"message": "Donor not found",
"request_id": "req_abc123...",
"doc_url": "https://alltogether.giving/developer/api/errors/not_found"
}
}codeis the stable, machine-readable identifier. Branch on this, not on HTTP status ormessage.messageis human-readable and may change between releases.typeanddoc_urlboth point at the documentation anchor for the code.request_idechoes thex-request-idresponse header and is always present. Quote it in any support enquiry.- Content-Type is
application/json, notapplication/problem+json. The envelope is Stripe-shaped.
Status codes
| Code | HTTP | When |
|---|---|---|
| invalid_request | 400 | Malformed input: missing required field, wrong type, unknown filter name, malformed JSON or empty body, unsupported Content-Type on a JSON endpoint, body too large. |
| validation_failed | 400 | Input parsed but failed validation: invalid enum value (e.g. an unknown `?status=`), value out of range, broke a business rule. Includes a `param` pointer at the offending field. |
| unauthorized | 401 | Missing or invalid credentials: no bearer token, unknown key, or revoked key. The bearer token is the only authentication signal; an `x-org-slug` header is rejected with `invalid_request` (400), not silently ignored. |
| forbidden | 403 | Authenticated but not allowed, e.g. a READ key calling a WRITE endpoint. |
| not_found | 404 | Resource does not exist or is not visible to this organisation. |
| method_not_allowed | 405 | Path exists but the HTTP verb is not supported. The response carries an `Allow` header listing the supported verbs. |
| conflict | 409 | State conflict, e.g. an Idempotency-Key is still in flight. |
| idempotency_conflict | 409 | Idempotency-Key was reused with a different request body. |
| rate_limited | 429 | Per-organisation rate limit exceeded. Honour Retry-After. |
| internal_error | 500 | Unexpected server failure. Retry with backoff; quote the request_id if it persists. |
This page is the shared shape. Every operation in the API reference lists exactly which of these codes it can return, with example envelopes.
Validation errors
Validation failures add a param pointing at the offending input path:
{
"error": {
"type": "https://alltogether.giving/developer/api/errors/validation_failed",
"code": "validation_failed",
"message": "amount_cents must be at least 100",
"param": "amount_cents",
"request_id": "req_xyz...",
"doc_url": "https://alltogether.giving/developer/api/errors/validation_failed"
}
}Request IDs and support
Every response, success or error, carries an x-request-id header, echoed as error.request_id. Values look like req_<cuid>. We log every call against this id. Quote it when you open a support ticket and we find the request instantly.
Supply your own
x-request-id on the way in and we echo it back unchanged. Otherwise we generate one for you.Retry policy
- 4xx: do not retry without changing something. Fix the payload, refresh the API key, or back off. The one exception is
429: honourRetry-Afterand retry. - 5xx: retry with exponential backoff plus jitter (e.g. 250ms, 500ms, 1s, 2s). Pair the retry with an Idempotency-Key on POST or PATCH so retries cannot double-write.
- Treat network errors the same as 5xx. The request may or may not have landed.