Skip to main content
A single-page briefing for AI agents, code generators, and anyone building an integration in one sitting. Everything here is stated explicitly rather than implied, and every claim reflects the API as it is today.

Essentials

OpenAPI specs

Stable URLs, regenerated from the API source on every change. Generate a typed client from these rather than hand-writing request code.

Roles decide what you can call

A team is a provider, a reseller, or hybrid, and the API key carries that role. Calling the wrong family of endpoints returns 403, not 404.
  • Provider/provider/* — publish offers, fulfill orders, manage markets, webhooks, and brands.
  • Reseller/reseller/* — browse the catalog, check address availability, place and track orders, manage links, customers, and webhooks.
  • Hybrid → both, with the same key.
  • Public/public/* — no key at all.
Full endpoint tables: Provider · Reseller · Public

Minimal working request

Gotchas

These are the things that most often make a first integration fail. None of them are inferable from the endpoint list. Unknown request fields are rejected. Sending a property an endpoint does not define returns 400 with "property <name> should not exist". You cannot take a response object and PATCH it back — send only the fields you are changing. List endpoints are not paginated. They return a complete array. There are no page, limit, offset, or cursor parameters, and adding one is a 400. Filter server-side with the documented query parameters instead. Money is a string, not a number. "monthlyPrice": "79.99". Parse with a decimal library — parseFloat introduces rounding drift into customer-visible totals. message is not always a string. On body-validation failures it is an array of strings. Normalize before displaying. 404 covers authorization on resources. Another team’s offer or order returns 404, not 403. 403 means your team role is wrong for that endpoint family. There is no idempotency key. POST /reseller/orders is not idempotent — two identical requests create two orders. If a write times out, reconcile with GET /reseller/orders before retrying. No rate limits on the authenticated API today. Only the two public /shop write endpoints are limited (per IP, per minute). Handle 429 anyway; do not build a tight polling loop. Webhook signatures have no separate timestamp header. The timestamp is the t= component of X-Offergrid-Signature, and the signed string is `${t}.${rawBody}`. Sign the raw body — re-serializing breaks the signature. See Verifying signatures. Both roles have webhooks, on separate paths. POST /provider/webhooks and POST /reseller/webhooks. Same four event types, same signed envelope — a provider receives events scoped to its own offers, a reseller to the orders its team placed. A hybrid team’s single webhook covers both and fires once per event. Offers carry a serviceType discriminator. Branch on it ("electricity", "internet", …) rather than probing for the grouped electricity / internet objects, which are absent when they do not apply.

Error handling

Full detail, including a retry-safe client: Errors. Something unclear or wrong? Email support@offergrid.io.