user.data.change
A user ledger still has balance after usage. Repeated changes for the same user/order/package key may be coalesced into the latest balance before delivery.
This page documents the outbound structure produced by the current accountant service. It intentionally does not include event names that are absent from the sender implementation.
{
"events": [
{
"event": "user.data.change",
"date": "2026-08-01T10:15:00Z",
"user": {
"id": "user_42",
"username": "acme-customer",
"reseller_id": "reseller_01"
},
"package": {
"id": "package_9",
"alias": "residential"
},
"order": {
"id": "order_71",
"data": 5368709120,
"data_remaining": 2147483648,
"ledger_id": "ledger_12"
}
}
],
"date": "2026-08-01T10:15:01Z"
}null for root and unlimited orders.| Field | Type | Meaning |
|---|---|---|
events | array | One or more coalesced accounting events |
date | timestamp | Time the delivery batch was created |
Both timestamps are serialized by Go’s JSON time encoder and should be parsed as RFC 3339-compatible values rather than compared as arbitrary display strings.
Every element of events has three nested context objects. The event name and occurrence time remain at the event root.
| JSON path | Type | Meaning |
|---|---|---|
event | string | Delivered event name |
date | timestamp | Time the underlying accounting event occurred |
user.id | string | Affected user identifier |
user.username | string | Affected proxy username or user label |
user.reseller_id | string | Owning reseller identifier; an empty string means no reseller context |
package.id | string | Related package identifier |
package.alias | string | Package alias copied into the accounting event |
order.id | string | Related order identifier |
order.data | integer | Remaining shared-ledger balance in bytes; negative means overdraft |
order.data_remaining | integer or null | Remaining finite child-order balance; null for root or unlimited orders |
order.ledger_id | string | Ledger identifier whose shared balance is reported by order.data |
user.data.change
A user ledger still has balance after usage. Repeated changes for the same user/order/package key may be coalesced into the latest balance before delivery.
user.data.run_out
The user ledger reached zero or below. Repeated run-out signals are subject to the sender cooldown.
order.data.run_out
A finite child order’s order.data_remaining reached zero or below while
the accounting event was processed.
The sender can map an internal order.data.change event to user.data.change or user.data.run_out before delivery. Consumers should therefore implement only the public names above unless a later contract version adds another event.
{ "event": "user.data.change", "date": "2026-08-01T10:15:00Z", "user": { "id": "user_42", "username": "acme-customer", "reseller_id": "reseller_01" }, "package": { "id": "package_9", "alias": "residential" }, "order": { "id": "order_71", "data": 5368709120, "data_remaining": 2147483648, "ledger_id": "ledger_12" }}{ "event": "user.data.run_out", "date": "2026-08-01T10:25:00Z", "user": { "id": "user_42", "username": "direct-customer", "reseller_id": "" }, "package": { "id": "package_9", "alias": "residential" }, "order": { "id": "order_71", "data": 0, "data_remaining": null, "ledger_id": "ledger_12" }}{ "event": "order.data.run_out", "date": "2026-08-01T10:30:00Z", "user": { "id": "user_42", "username": "acme-customer", "reseller_id": "reseller_01" }, "package": { "id": "package_9", "alias": "residential" }, "order": { "id": "order_71", "data": 4294967296, "data_remaining": 0, "ledger_id": "ledger_12" }}| Property | Consumer expectation |
|---|---|
| Transport | HTTP POST with JSON |
| Signature | Base64 HMAC-SHA256 in X-Signature |
| Success | Return a direct 2xx; sender currently accepts any status below 400 |
| Retries | Possible for network, timeout, and error-status failures |
| Duplicates | Possible; make balance application idempotent |
| Ordering | Not guaranteed |
| Event ID | Not present |
| Completeness | Reconcile with analytics rather than assuming an event-only ledger |
For receiver code and webhook creation, return to webhook integration.