Stable Pro API · v1
Events
How to stay in sync: read what happened after your cursor, in order, with nothing lost.
Every economic fact of a stable has an event, an event object: a charge is created, an adjustment is made, a payment arrives, a receipt is issued or voided, a customer's details change. Events are written by the database in the same transaction as the fact, and they are numbered in the order they become visible.
GET /events?after=<cursor>&limit=100
The guarantee
If an event is visible, every earlier event of the same stable is already visible, or will never exist.
So reading "everything after my cursor" never skips anything: no earlier event can appear later. Gaps in the numbering can exist (a cancelled transaction) and are harmless, because you never ask for "the next number".
How to read
- The first time, call
GET /eventswithoutafter: you start from the stable's first event, history included. - Process each event in order: read the object it points to (
data.url) and do your work. - When the page is processed, save
next_cursor. - Call again with
after=<next_cursor>. Repeat whilehas_moreistrue; when it isfalse, wait and ask again later (for example every few minutes).
{
"object": "list",
"data": [
{
"object": "event",
"id": "6f1d1e0c-…",
"type": "adjustment.created",
"data": { "object": "adjustment", "id": "8d0c2f6e-…", "url": "/api/v1/adjustments/8d0c2f6e-…" },
"occurred_at": "2026-12-05T09:14:03.512Z",
"recorded_at": "2026-12-05T09:14:03.540Z",
"historical": false
}
],
"has_more": false,
"next_cursor": "6f1d1e0c-…"
}
- Events are lean: they say which object was created or changed, never the amounts. Read the object.
- At least once: after an interruption you start again from the last cursor you saved, and you may read a page twice. Processing an event again does no harm — it points to a fact that does not change, or to a customer's current details — and the event
idlets you recognise events you already processed. Event ids are unique across all stables. next_cursormay be the id of an event you are not shown: always save it as it is.has_more: truewith fewer thanlimitevents — even none — means some events were not for you and the log goes on: ask again.- A cursor that is not an event of this stable is a
400onafter.
Event types
| Type | Points to | Permission |
|---|---|---|
customer.updated | the customer | customers:read |
charge.created | the charge | charges:read |
charge.due_date_changed | the charge (read its new due_date) | charges:read |
charge.tax_changed | the charge (read its new taxes) | charges:read |
adjustment.created | the adjustment | charges:read |
payment.created | the payment | payments:read |
allocation.created | the allocation of a payment to a charge | payments:read |
credit_entry.created | the credit entry | payments:read |
receipt.issued | the receipt | receipts:read |
receipt.voided | the receipt | receipts:read |
Each event is shown only with the permission of the object it points to. Only the side to be collected is shown, that is what customers owe the stable, paid or not: staff pay never appears. There is no customer.created: a customer is born with their first charge, and charge.created carries their customer_id. The list of types is open: accept a type you do not know yet. Names in every language are in /codes (event_type).
If your key gains a permission, the events it did not see before are behind your cursor: read again from the start (without after) to get them.
History
When a stable starts using the API, its whole history is already in the log: events of facts from before carry historical: true, are ordered by the date of the fact, and come before every event of the present. occurred_at is always the date of the fact; recorded_at is when the event was written.
While a stable's history is being loaded, /events answers 503 with type: …/events-not-ready and Retry-After. It takes seconds.
One event
GET /events/{id} returns one event, with the same rules. An event of another stable, of a type your key cannot read, or one that does not exist: 404.