Tail the ordered feed from a cursor to see everything that happened, or take signed webhooks for the control events your systems act on. The feed holds every event a webhook carries. Examples use $ENGINE for the engine’s URL and $TOKEN for a bearer.

The event feed

GET /v1/events answers events in the order they were recorded, of two kinds:
  • journal, the ledger’s facts as NodeAsset reads them: a subscription created, an admission offered or granted, a NAV published, a settlement proposed. Each payload names the record your systems key on beside the contract: the subscription a lot is (subscriptionId, with its appliedNav and claimedAt), the registered holder an admission is for (holderId).
  • control, what NodeAsset announces: its own acts (an operation that finished, an approval requested or decided, a reconciliation finding or hold, a restriction, a distribution that became payable, a reserve’s mint, redemption, report or change of terms), and each step of an order or a dealing cycle, below.
The engine reads the journal only while your deployment sets venue.events.tail-interval, which is off by default; until then the feed holds control events alone. The order and dealing-cycle steps are read off the ledger by the same reader, so they need it too. See Configuration reference. Narrow it by kind, type and instrumentId, to one holder’s events with holderId, or to one record’s with resourceKind and resourceId, and window it by from and to. Page oldest first after a cursor: send each page’s next back as after, and keep the last one you processed, so a restart resumes where it stopped. An empty page keeps the cursor it was asked with.
curl
One event:
For a screen’s history, order=desc pages newest first, with the same after. A bearer with the monitor role reads control events only, each redacted to its ids, codes and counts.

Lifecycle events

Each step is announced once per record, at the ledger time and offset of the transaction that made it, with the record’s ids, its units, its price and what it pays, and the transaction’s updateId. amount and paymentInstrumentId are null for an order paid off the ledger. A step announced again, as when the reader goes over a range twice, is not stored twice: a redemption priced again keeps its first redemption.priced, and GET /v1/redemptions/{redemptionId} has the latest price.

Webhooks

The engine posts its announcements, the control events below, to each webhook that takes their type; operations and approvals stay in the feed. The venue configures a webhook on the engine (venue.recon.webhooks): an id, the url, a secret of at least 32 bytes, and the event types it takes (events; none listed takes every type). POST /v1/webhooks creates one under four eyes, naming a key file in the engine’s webhook secret directory (secretFile) so that no key crosses the API, and GET /v1/webhooks lists them all. POST /v1/webhooks/{webhookId}:test sends one test delivery and answers whether the receiver took it. The engine posts only to a public address, or to an address in a network the venue allows for an internal receiver (Configuration). It checks the address at every delivery, so a name that later resolves to a private address is refused there. Each delivery is a JSON POST: Answer 2xx once you have taken it. Anything else, or no answer, is retried with exponential backoff until the webhook’s attempts run out. Deliveries are at least once, so dedupe on X-NodeAsset-Delivery. Keep the last seq you took: after an outage, GET /v1/events?after=<seq> reads on from it, so nothing a webhook missed is lost. Each type’s body is in the OpenAPI document, under x-webhooks. A type your code does not know comes from a newer engine: treat it as a case of its own, never as an error.

Verify a delivery

Check every delivery before you act on it:
  1. Verify the signature: the HMAC-SHA256, under the webhook’s secret, of the timestamp header, a ., and the body’s bytes as received, never re-serialized. Compare in constant time.
  2. Refuse a timestamp more than five minutes from your own clock, so a captured delivery cannot be replayed later.
  3. Drop a delivery whose id you have already handled.
Java
The check needs only the JDK, and a check in another language follows it step for step. It covers the signature and the timestamp; the dedupe is left to you.