Guides
Authentication
Every request carries an API key as a bearer token. Keys are per-program, scoped (ingest, read, act, webhooks) and come in two modes: sticky_live_… writes to your production program; sticky_test_… writes to an isolated sandbox. Keys are shown once at creation and stored hashed — rotate from the admin (the old key keeps working for 24 hours) and revoke instantly if leaked.
Authorization: Bearer sticky_live_XXXXXXXXThe key alone determines which program you operate on — there is no tenant parameter anywhere. Requesting another program's resources simply returns 404.
Idempotency
Every write is idempotent. For single events, send an Idempotency-Key header (or let us derive one from the event refs — e.g. order.paid:ORDER-1001). For batches, each event's id is its key. Replaying returns the original result with replayed: true and never double-writes the ledger — retry on any network failure with the same key, always.
POST /v1/events
Idempotency-Key: order-1001-paid
# first call → 202 { "data": { "id": "…", "replayed": false } }
# retry → 200 { "data": { "id": "…", "replayed": true } } # same id, no double creditPagination
List endpoints return { data, pagination: { cursor } }. Pass the cursor back as ?cursor= for the next page; null means you've reached the end. Cursors are stable across inserts — you'll never skip or repeat rows mid-walk.
GET /v1/members?limit=100
GET /v1/members?limit=100&cursor=CURSOR_FROM_LAST_PAGEErrors
Errors are RFC 9457 application/problem+json: a type URL, human title/detail, the HTTP status, and for validation failures an errors array with paths. Rate limits (default 10 req/s, burst 50 per key) return 429 with Retry-After.
{
"type": "https://stickytier.com/docs/api/errors#validation",
"title": "Validation failed",
"status": 422,
"detail": "Event failed validation.",
"errors": [{ "path": "gross_cents", "message": "Required" }]
}Conventions
Money is always integer minor units (amount_cents — paise). Timestamps are ISO 8601 UTC. Member ids are the stable public form (M-…) — internal identifiers never leak. Ledger entries are append-only: corrections appear as new reverse entries pointing at their parent, never as edits, so your integrations can treat the ledger as an immutable stream.