Reference
REST API.
Read campaigns, customers, cancel sessions, and aggregate stats. JSON in, JSON out. Bearer-token auth. Rate-limited per token. The intended use case is custom dashboards and one-off scripts — for most workflows the dashboard or webhooks are easier.
Auth
Mint a token under Settings → API tokens. Each token is scoped to a single workspace and is shown once at creation — copy it, store it safely. Lost tokens can't be recovered, only revoked + re-minted.
curl https://www.trybackstop.com/api/v1/customers \
-H "Authorization: Bearer sk_live_xxxxxxxxxxxx"Endpoints
GET /api/v1/customers— paginated list of mirrored customers. Filters:?email=,?tag=,?cursor=.GET /api/v1/customers/:id— single customer with their subscriptions + recent campaigns embedded.GET /api/v1/campaigns— recovery campaigns. Filters:?status=in_flight|recovered|lost|abandoned,?cursor=.GET /api/v1/campaigns/:id— campaign with its dunning sends and payment attempts.GET /api/v1/cancel_sessions— paginated list of cancel sessions. Filters:?outcome=(one ofsaved_discount,saved_pause,saved_downgrade,saved_other,canceled,abandoned),?cursor=<ISO timestamp>.GET /api/v1/stats— aggregate counts and rates. Same numbers as the dashboard KPIs, in JSON.
Rate limits
Default limit is 60 requests per minute per token. Need more? Hit reply on any Backstop email — we raise limits case-by-case rather than tiering.
Every response includes:
X-RateLimit-Limit— your per-minute ceilingX-RateLimit-Remaining— requests left in the current windowX-RateLimit-Reset— seconds remaining until the window refills
Hitting the limit returns HTTP 429 with a Retry-Afterheader. Backoff and retry; we don't auto-ban tokens for 429s.
Errors
All errors return JSON in the same nested shape (mirroring Stripe). Read error.type to branch programmatically and error.message for a human-readable reason:
{
"error": {
"type": "rate_limit_exceeded",
"message": "60 requests per minute. Retry in 12s."
}
}On a 429 the wait time is also returned as a Retry-After response header (seconds) — there is no retry_after_seconds field in the body. Other error.type values you may see include authentication_required, invalid_token, and invalid_param.
Want it broader?
We deliberately ship a small surface today. If you're missing an endpoint, hit reply on any Backstop email and tell us what you'd build with it — we add what actual use cases ask for, not theoretical completeness.
Related
- Webhooks — push events instead of pulling.