Customer timeline
Everything a store did with one customer, newest first, plus what plugins recorded about them: orders, returns, the emails the store sent, abandoned checkouts, live chat conversations and support tickets, and the events your plugin and others posted. One list, one shape, one call.
The scopes
customer-events:readlists a customer's timeline. A session token carries it only for a dashboard user who may read customers, the same waycustomer:readworks.customer-events:createrecords your plugin's own events. It is plugin-bound: no dashboard permission stands behind it, so every session token carries it once the store has granted it.
Reading the timeline
GET /v1/customers/{customerId}/events?limit=50&types=order,plugin HTTP/1.1
Host: api.myorbitcommerce.net
Authorization: Bearer <access-token>| Parameter | Purpose |
|---|---|
limit | 1 to 100 events a page, 50 by default. |
types | A comma list of the kinds wanted: order, return, email, checkout, chat, ticket, plugin. Every kind when left out. plugin covers what every plugin recorded. |
before | Only events before this instant (ISO 8601). Pass the previous page's meta.nextBefore to read on. |
The customer must belong to the store (404 otherwise). The answer, in the data field of the standard response envelope, is { items, meta: { limit, nextBefore } }; nextBefore is null on the last page. Every event has the same shape:
{
"id": "0f3c8b2a-1d4e-4a6b-9c2f-7e5a1b2c3d4e",
"type": "order.placed",
"occurredAt": "2026-10-01T10:00:00.000Z",
"title": "Order #1001",
"summary": "paid, processing",
"link": "/orders/0f3c8b2a-1d4e-4a6b-9c2f-7e5a1b2c3d4e/detail",
"data": {
"orderNumber": "1001",
"total": 12.5,
"currency": "GBP",
"status": "processing",
"paymentStatus": "paid"
}
}| Type | What it is | data |
|---|---|---|
order.placed | An order the customer placed | orderNumber, total, currency, status, paymentStatus |
return.requested | A return they asked for | returnNumber, status, orderId |
email.sent | An email the store sent them | template, status, openedAt, clickedAt |
checkout.abandoned | A checkout they left | total, currency |
chat.started | A live chat conversation they started | status, lastMessageAt |
ticket.opened | A support ticket they opened | number, status |
plugin.<pluginId>.<type> | What a plugin recorded, with plugin: { pluginId } beside it | Whatever that plugin attached |
link is a path in the store dashboard where there is one, null otherwise. id is the id of the order, return, email, checkout, conversation, ticket or event itself, so it is stable across pages.
Recording your own events
POST /v1/customers/{customerId}/events HTTP/1.1
Host: api.myorbitcommerce.net
Authorization: Bearer <access-token>
Content-Type: application/json
{
"type": "deal.won",
"title": "Deal won",
"summary": "Acme renewal, 12,000 a year",
"route": "/deals/42",
"occurredAt": "2026-10-06T09:00:00.000Z",
"externalId": "deal-42-won",
"data": { "dealId": "d-1" }
}| Field | Purpose |
|---|---|
type | Your name for the event: lower-case dotted segments such as deal.won, each starting with a letter and then letters, digits, _ or -, up to 60 characters. It may not start with plugin., which Orbit adds: listed as plugin.<pluginId>.<type>. Required. |
title | One line, up to 255 characters. Required. |
summary | The detail under it, up to 2000 characters. |
route | Where inside your plugin page a click lands, as a path such as /deals/42. Listed as the event's link, /plugins/<pluginId>?route=%2Fdeals%2F42 (the route URL-encoded). |
occurredAt | When it happened (ISO 8601). Now when left out. |
externalId | Your own id for the event, up to 100 characters, unique within your plugin for the store (not per customer). A second post with the same id records nothing and answers the first, even under another customer, so a retried webhook handler never records twice. |
data | An object your plugin wants back with the event, up to 4000 characters as JSON. |
The answer is { created, event }; created is false when externalId matched. Other plugins holding customer-events:read see your events too, so record what a person would want to see on the customer's page, not a log.
Limits
- Reading counts as a read on this API (600 a minute per install); recording is held to 120 a minute.
- The timeline reads the store's live data each time and is not a search. Narrow with
typeswhen you only need some kinds, and page withbefore. - When a store deletes a customer, their timeline answers
404and takes no new events.