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_XXXXXXXX

The 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.

Replay-safe retry
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 credit

Pagination

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_PAGE

Errors

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.

422 example
{
  "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.