Skip to main content
Offergrid uses conventional HTTP status codes. A 2xx means the request succeeded, a 4xx means something about the request needs fixing, and a 5xx means the failure was ours.

Error format

Almost every error returns the same envelope:
message is not always a string. Request-body validation failures return an array, and two endpoints return a richer shape (see Validation errors below). Normalize before displaying: Array.isArray(body.message) ? body.message.join('; ') : body.message.

Status codes

404 is used for authorization failures on resources. Every provider and reseller endpoint is scoped to your team, so requesting an offer or order belonging to another team returns 404 Not Found rather than 403 Forbidden. This is deliberate — a 403 would confirm the resource exists.403 means something different: your API key is valid but your team role does not grant access to that whole class of endpoint — a reseller team calling /provider/*, or vice versa.

Validation errors

Request-body validation

Every endpoint that accepts a body validates it before any work happens. Unknown properties are rejected rather than ignored, so a typo in a field name is a 400, not a silently dropped value.
Each entry names the offending field first, so they can be mapped back to form fields by prefix.

Publish validation

POST /provider/offers/{id}/publish checks an offer against the publish-readiness rules, which are richer than field-level validation. Its 400 carries a different, structured shape:
This response has no statusCode field — the status is on the HTTP response only. Branch on the HTTP status, not on the presence of statusCode in the body.
The CSV bulk endpoints (/provider/offers/bulk-upload, /bulk-update, and their /validate variants) report per-row problems in their 200/201 body rather than as an error — a partially-valid file is a successful request with a results breakdown, not a failure.

Handling errors

Retry only what is retryable. A 400, 401, 403, 404, or 409 will return the same result no matter how many times you send it; retrying wastes your budget and ours.
Non-idempotent writes need care. POST /reseller/orders creates an order; a blind retry after a timeout can create a second one. If a write times out without a response, reconcile with GET /reseller/orders before retrying rather than sending it again.

Next steps

Rate limits

What is limited, and what is not

API conventions

List responses, identifiers, timestamps, and money

Authentication

Keys, headers, roles, and rotation

Versioning

How the API changes, and what we promise not to break