API reference
Everything under /api/v1. Generated from the surface the API actually serves, so it cannot describe an endpoint that does not exist.
Versioning
Adding a field or an endpoint is additive and does not bump the version. Removing one, renaming one, or changing what an existing field means does. You are outside our control and cannot be migrated, which is why the line is drawn there.
Scopes
| Scope | Covers |
|---|---|
events.read events.write | Send behaviour and commerce events, and read what you have sent. |
eligibility.read eligibility.write | Ask which offer a shopper should see. |
offers.read offers.write | Read and manage campaigns, offers and their rules. |
trials.read trials.write | Read and manage trial products, journeys and fulfilment. |
credits.read credits.write | Read and issue trial credit. |
referrals.read referrals.write | Read and create referral links. |
analytics.read analytics.write | Read attribution, profit and experiment results. |
webhooks.read webhooks.write | Manage where we send you events. |
write does not imply read. A key that may issue credit but not list it is a real and useful thing.
Rate limits
Per key, per minute. Limits follow cost, not resource: the eligibility call sits between a shopper and a page, and throttling it to protect the reports would cost you sales.
| Tier | Per minute |
|---|---|
hot | 600 |
standard | 120 |
expensive | 20 |
Errors
Every error is { ok: false, code, error } with an optional details. Branch on code; the sentence is for your logs. A 409 means the request was fine and the state refused it, which is different from a 400 when you are deciding whether to retry.
| Code | Status | Meaning |
|---|---|---|
unauthorized | 401 | That key is not valid. |
forbidden_scope | 403 | This key is missing a scope this endpoint needs. |
rate_limited | 429 | Too many requests. |
invalid_request | 400 | The request body is not what this endpoint expects. |
idempotency_key_required | 400 | This endpoint needs an idempotency key. |
batch_too_large | 400 | Too many items in one request. |
not_found | 404 | No such thing, or not yours. |
offer_not_available | 409 | That offer is not running. |
not_eligible | 409 | This shopper is not eligible for that offer. |
already_claimed | 409 | This shopper already has that trial. |
trial_sold_out | 409 | That trial has run out. |
blocked_by_risk | 409 | That claim was stopped. |
invalid_address | 400 | The shipping address could not be used. |
credit_exhausted | 409 | That credit has nothing left on it. |
credit_expired | 409 | That credit has expired. |
internal_error | 500 | Something went wrong on our side. |
Endpoints
events
| Endpoint | Scope | Rate | Idempotent |
|---|---|---|---|
POST /api/v1/eventsSend one or more events. Behaviour, commerce or custom. | events.write | hot | yes |
GET /api/v1/eventsRead events you have sent, newest first. | events.read | standard | · |
eligibility
| Endpoint | Scope | Rate | Idempotent |
|---|---|---|---|
POST /api/v1/eligibility/decideWhich offer, if any, this shopper should be shown. | eligibility.read | hot | · |
offers
| Endpoint | Scope | Rate | Idempotent |
|---|---|---|---|
GET /api/v1/offersList offers. | offers.read | standard | · |
GET /api/v1/offers/:idOne offer, with its rules. | offers.read | standard | · |
POST /api/v1/offersCreate an offer. | offers.write | standard | · |
PATCH /api/v1/offers/:idChange an offer, or publish and pause it. | offers.write | standard | · |
GET /api/v1/campaignsList campaigns. | offers.read | standard | · |
trials
| Endpoint | Scope | Rate | Idempotent |
|---|---|---|---|
GET /api/v1/trialsList trial products and their stock. | trials.read | standard | · |
GET /api/v1/journeysTrial journeys, filterable by state. | trials.read | standard | · |
POST /api/v1/journeysClaim a trial on a shopper’s behalf. | trials.write | standard | yes |
POST /api/v1/journeys/:id/fulfillmentRecord shipping or delivery yourself. | trials.write | standard | yes |
credits
| Endpoint | Scope | Rate | Idempotent |
|---|---|---|---|
GET /api/v1/creditsTrial credit and what remains of it. | credits.read | standard | · |
POST /api/v1/creditsIssue credit to a shopper. | credits.write | standard | yes |
referrals
| Endpoint | Scope | Rate | Idempotent |
|---|---|---|---|
GET /api/v1/referralsReferral links and how they have performed. | referrals.read | standard | · |
POST /api/v1/referralsCreate a referral link for a shopper. | referrals.write | standard | yes |
analytics
| Endpoint | Scope | Rate | Idempotent |
|---|---|---|---|
GET /api/v1/analytics/programmeRevenue, cost and contribution profit over a period. | analytics.read | expensive | · |
GET /api/v1/analytics/attributionAttributed orders and why each was attributed. | analytics.read | expensive | · |
GET /api/v1/analytics/experiments/:idAn experiment’s cohorts and incrementality. | analytics.read | expensive | · |
webhooks
| Endpoint | Scope | Rate | Idempotent |
|---|---|---|---|
GET /api/v1/webhooksWhere we currently send your events. | webhooks.read | standard | · |
POST /api/v1/webhooksSubscribe an endpoint to event types. | webhooks.write | standard | · |
DELETE /api/v1/webhooks/:idStop sending to an endpoint. | webhooks.write | standard | · |