Customer state notification
customer.state_changed: the whole state of one buyer posted to your endpoint every time it changes — enable it, the triggers, the payload, coalescing, ordering by stateAt and test mode.
customer.state_changed is a notification about a BUYER, not about an order: whenever what GET /api/v1/customers/state returns for one of your account references changes, Norelio posts the whole new state to your webhook endpoint. Your server keeps its copy of each user's subscriptions, purchases and balances up to date without asking again and again. It is sent only for buyers with an account reference (clientReference): the state is keyed by it.
Turn it on
It is off by default. The partner turns it on with the "Customer state" checkbox on the cabinet's API and webhooks → Webhooks tab, once the endpoint is saved; the same tab has a button that sends a test notification of this kind with made-up data and test: true. It goes to the same endpoint, with the same three signature headers and the same secret as the order events, and it covers buyers of every product, whatever its delivery method — not only products delivered by webhook.
When it is sent
- a payment: a purchase, a top-up, a subscription's first payment;
- a refund, partial or full, and a dispute opened or resolved — including those Norelio records after a reconciliation, without a webhook from the payment provider;
- a subscription renewed, a failed charge, a cancellation (by the buyer, the partner or Norelio) and the end of a subscription;
- access changed by hand in the cabinet (extended or closed);
- any balance movement: a debit or grant through the API, the MCP server or the cabinet, credits added by a top-up, a refund share removed.
Payload
| Field | Description |
|---|---|
version | The payload version, the same as in the order events. |
event | Always customer.state_changed. |
test | true for test data (the test key's data or the test button); false for a real buyer. |
occurredAt | The moment of the snapshot — the same as stateAt. |
clientReference | Your account reference of the buyer whose state changed. |
stateAt | When the snapshot in state was taken (ISO 8601). Order notifications by it. |
state | The buyer's whole state at stateAt — exactly the response of GET /api/v1/customers/state?clientReference=… at that moment: subscriptions, purchases and balances, with the same fields and the same limits. |
eventId | Our id of this notification: the same on every retry of it. Deduplicate on it. |
{
"version": 1,
"event": "customer.state_changed",
"test": false,
"occurredAt": "2026-03-14T09:26:54.000Z",
"clientReference": "acc_10294",
"stateAt": "2026-03-14T09:26:54.000Z",
"state": {
"subscriptions": [
{
"id": "sub_4d5e6f",
"productId": "prod_1a2b3c",
"status": "active",
"validUntil": "2026-04-14T09:26:53.000Z",
"currentPeriodEnd": "2026-04-14T09:26:53.000Z",
"cancelAtPeriodEnd": false,
"clientReference": "acc_10294"
}
],
"purchases": [
{
"orderId": "ord_7k3m2p",
"productId": "prod_1a2b3c",
"paidAt": "2026-03-14T09:26:53.000Z",
"amount": 1990,
"currency": "EUR",
"status": "paid",
"clientReference": "acc_10294",
"refunded": false,
"credits": null,
"creditsUnit": null
},
{
"orderId": "ord_9z8y7x",
"productId": "prod_4d5e6f",
"paidAt": "2026-02-01T18:03:11.000Z",
"amount": 990,
"currency": "EUR",
"status": "refunded",
"clientReference": "acc_10294",
"refunded": true,
"credits": null,
"creditsUnit": null
}
],
"balances": [
{
"unit": "credits",
"balance": 250
}
]
},
"eventId": "cm8f5q1s40011kl8m3n6p9r2t"
}The fields of state are described in Customer state.
Several changes, one notification
Changes that come close together — within about 1 second of each other, such as a payment and the credits it adds — may arrive as ONE notification. The state is read when the notification is sent, so it already includes every change made before stateAt; you may get fewer notifications than changes, but no change is left out of the last one.
Take the latest by stateAt
Delivery and signature
Retries follow the same rules as the order events. When a newer state of the same buyer is sent while an older one is still waiting for its retry, the older one is not retried any more: the delivery log marks it as replaced by a newer state. Answer 2xx quickly and do the work afterwards. The signature and the retry schedule are those of Webhooks.
The order events (order.paid, refunds, disputes, subscription events) are sent exactly as before, whether customer.state_changed is on or off, and their payload does not change. This notification is an addition with a payload of its own: tell it apart by event, and do not read it as an order event.
Test mode
The same notification is sent for changes of test data — a test payment, an action on a test order, a test balance movement — with test: true and an eventId that starts with test_; its state is then the test customer state, as the test key reads it. See Test mode.
