Skip to main content
Together
Sign in

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"
  }
}
  • code is the stable, machine-readable identifier. Branch on this, not on HTTP status or message.
  • message is human-readable and may change between releases.
  • type and doc_url both point at the documentation anchor for the code.
  • request_id echoes the x-request-id response header and is always present. Quote it in any support enquiry.
  • Content-Type is application/json, not application/problem+json. The envelope is Stripe-shaped.

Status codes

CodeHTTPWhen
invalid_request400Malformed 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_failed400Input 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.
unauthorized401Missing 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.
forbidden403Authenticated but not allowed, e.g. a READ key calling a WRITE endpoint.
not_found404Resource does not exist or is not visible to this organisation.
method_not_allowed405Path exists but the HTTP verb is not supported. The response carries an `Allow` header listing the supported verbs.
conflict409State conflict, e.g. an Idempotency-Key is still in flight.
idempotency_conflict409Idempotency-Key was reused with a different request body.
rate_limited429Per-organisation rate limit exceeded. Honour Retry-After.
internal_error500Unexpected 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: honour Retry-After and 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.