Skip to main content

Platform Event

A Platform Event tells an integration what happened through a named, versioned message, so it need not interpret raw chain logs.
One chain fact becomes one row for each subscriber.An indexed chain fact enters at the top, identified by chain, block number and log index. It passes through the catalogue, the focal element: a fixed set of named events, one payload shape for each name and version, with machine-readable definitions generated from the registry. From the catalogue the fact fans out into one row for each subscribed endpoint. Every row carries its own identifier, unique across the whole platform. Its sequence number is scoped to the endpoint, so two endpoints can both hold sequence one for the same fact. Rows commit in the same transaction as the indexed fact, ordered by chain position and then each endpoint's own sequence. At the bottom, a later chain reorganisation never edits a row already sent: a retracted event arrives instead, naming the identifier it replaces.One chain fact becomes one row for each subscriber.The same figure as the desktop variant, drawn portrait for phone widths. An indexed chain fact passes through the catalogue, which fixes each event's name and payload shape and supplies the generated machine-readable definitions. Below the catalogue, a single stem splits into two equal branches, one per subscribed endpoint, and the branches rejoin below both endpoints into one row per endpoint. Rows commit with the indexed fact, ordered by chain position and then endpoint sequence. A chain reorganisation never edits a row already sent: a retracted event names the identifier it replaces.

The catalogue decides what an event is called and what it contains, and everything downstream copies that decision.

  • An integration reads what happened, and how settled that fact is, without polling the chain or running its own indexer: one registry binds each event name and version to exactly one payload shape.

  • Every event names its lifecycle state. Read it with the event type: final can mean chain finality or a committed platform outcome. A final transaction-request event does not itself confirm a token movement.

  • Delivery retries can produce duplicates. Deduplicate on the event identifier and reconcile missing or retracted events.

Why an integration needs a catalogue, not raw logs

A platform event is how an integration learns what happened on the platform: what occurred, when, and how settled that fact is. A chain log answers the first two on its own. It says nothing about the third, because the block behind it can still be reorganised.

The alternative to the platform's event vocabulary is an integration that reads raw logs itself. It decides, on its own, how deep a block must sit before a fact counts as final, and what to do when a block it already trusted gets replaced. Made once, by the platform, that decision is the same for every subscriber, and the envelope states it. Made independently by every integration, it is a second reading of the same chain, on that integration's own schedule and its own judgment of depth.

Each handoff between separate systems is a reconciliation. A platform event pins the handoff to one record: what the integration was told, checked against what the platform's own indexed record says happened. The platform keeps that delivery record for 30 days after it settles, so retain what your reconciliation needs.

That list is not tied to one stage of an instrument's life the way a coupon payment belongs to servicing. Issuance, servicing and an eventual retirement each produce their own facts, and each one reaches an integration through this same catalogue, tagged with one of five lifecycle states.

Why this catalogue lives on the platform, not in a tenant's own indexer

The alternative to a platform-run catalogue is a tenant indexer running beside the platform: watching the same chain, choosing its own reorganisation depth, and turning raw logs into its own vocabulary. That second indexer answers the same question the platform already answers, from a read of the chain that only the tenant sees.

This catalogue holds no second reading, because the same indexer that decides a chain fact for the platform's own record is the one that derives the outbox row a subscriber later receives. The event and the indexed fact it describes come from that one decision, not from two.

A vocabulary that cannot move under you

A platform event is one entry in a vocabulary defined by a single registry. Each entry binds an event name and version to one payload shape. The build rejects a second registration of the same name and version.

That guarantee targets the two quiet ways an integration built on notifications usually breaks. A field changes shape and the consumer keeps parsing the old one. Or a name starts covering a slightly different occurrence and nobody tells the consumers. Both fail silently, and a reconciliation turns them up weeks later.

The platform generates the machine-readable event manifest, event types for the TypeScript SDK, and sample payloads from that registry. The event catalogue is written by hand and checked against the registry. It explains when each event is sent and what a receiver does with it. Payload schemas and examples stay in the machine-readable definitions. Registration alone does not prove the platform sends an event. The catalogue separates live events from reserved names.

An integration selects the published payload contract by event name and version. Read both fields before interpreting the payload.

The envelope states how settled a fact is

Every platform event has a lifecycle_state: pending, provisional, final, retracted, or recalled. Recalled is reserved. No live event uses it. Many names end in a state, such as token.transfer.final, but others end in a word such as raised or published. Read the envelope's state and event type together. The lifecycle reference describes the live sequences and reserved states.

Lifecycle vocabulary includes one reserved state.The vocabulary has five states. Recalled is reserved. The platform does not send it. A pending event reports a transaction request that was broadcast and is not confirmed. A provisional chain event reports an observation that a reorganisation may remove. A final chain event follows the configured finality depth. Retractions withdraw earlier facts after a reorganisation or a business reversal. A state change is a separate event, not an edit to a delivery already sent.Lifecycle vocabulary includes one reserved state.The same vocabulary in a portrait layout. Recalled is reserved. The platform does not send it. A pending event reports a transaction request that was broadcast and is not confirmed. Provisional chain observations may be removed by a reorganisation. Final chain events follow the configured finality depth. A retraction withdraws an earlier fact after a reorganisation or a business reversal. A later event never edits a delivery already sent.

A state change is a new event and so is a correction, and nothing edits a delivery already sent.

For chain observations, provisional means included but still within the network's configured confirmation depth, and final means the source block has passed that depth. A platform administrator sets that depth for each network. The platform emits provisional at inclusion and final after the depth is reached. A chain reorganisation within the depth can retract a delivered provisional event. A reorganisation deeper than the configured depth is outside what a final event promises.

A fact does not change state in place. The same movement reported first as provisional and later as final reaches you as separate events with separate identifiers. Watch for the later event rather than for a field changing on the earlier one.

A retraction reports that an earlier fact no longer stands. It can follow a chain reorganisation or a business reversal, such as a trade bust. The platform leaves the earlier delivery intact. The consumer contract defines how to match the correction, including when its supersedes field is absent or names an event you never received.

Pending reports a transaction request that the platform broadcast and that is not confirmed. A request outcome uses final, including a failure or cancellation. This is the request's outcome, not a token movement's chain finality. Recalled is a reserved state, and no live event uses it.

From one log to one row per subscriber

For an event derived from a chain log, the platform records one pending delivery for every endpoint whose subscription matches the event name, in the same database transaction as the indexed fact. No queue sits in memory between the two, so the event and the indexed state it describes commit together or not at all.

Transaction-request events describe a different source: a state change recorded inside the platform. The platform records the event together with that state change, rather than deriving it from an indexed chain log.

The fan-out is per subscriber, not per fact. Ten subscribed endpoints mean ten rows from one log, each signed on its own and each with its own identifier, so one endpoint's delivery history says nothing about another's.

Every subject area the indexer writes, token movements and identity and role changes alike, handles a failure to write those rows the same way. A failure to record the deliveries blocks the indexed write, so the whole unit retries together. When the retry succeeds, the indexed change and its notification land in that same commit, so a caller never sees one without the other. No gap can open between the indexed fact and its recorded delivery, and Webhook Delivery moves that delivery to your endpoint. The cost is that a delivery-recording problem delays the indexed record too.

Each endpoint has its own delivery sequence. A later eligible event waits while an earlier event remains pending, including during retry backoff. A linked correction waits until its cause was delivered or can no longer be delivered. Events waiting for chain finality do not block later events. A Replay can deliver an older observation after a newer one, so keep the newest state you hold. The ordering contract states the limits.

Writing a consumer that stays correct

A correct consumer subscribes only to the states it handles, deduplicates on the event identifier, and applies a superseding event by looking up the identifier that event names instead of assuming order.

An endpoint subscribes with patterns. A pattern matches a name prefix, as in token.transfer.*, a name suffix, as in *.final, or one exact name. The defaults match names ending in .provisional, .final, and .retracted, not the envelope's lifecycle state. The subscriptions reference lists live events these defaults skip. A *.pending pattern delivers nothing, because no live event name ends in .pending. A subscription change replays no earlier events. Replay is a separate request.

The webhook-id header carries the event identifier. Store each identifier and check it before you act. Delivery, the signed HTTPS POST that carries one event to one subscribed endpoint, uses bounded retries: a retry after a lost acknowledgement can repeat a delivery your endpoint already processed. Nothing on the platform side deduplicates for you.

Treat an event as an append-only record rather than as an update. When a later event supersedes an earlier one, it includes a supersedes field naming the identifier it replaces, and the platform never rewrites the original delivery. That field holds one identifier, never a list, so a superseding event always points at exactly one predecessor. A consumer that applies a retraction by looking up the superseded identifier and reversing its effect stays correct through a reorganisation. A consumer that overwrites in place cannot tell the difference between a correction and a fresh occurrence.

The platform publishes machine-readable definitions as a subscription manifest, the DALP events manifest, with a version marker that identifies the inventory it describes. Pin that marker if you generate code from the manifest, so an inventory change is a decision you make rather than one that arrives during a deploy.

Frequently asked questions

Does subscribing to an event name guarantee the platform sends it?

No. The published manifest lists only the event names the platform sends, and schemas for names it does not send stay available for historical decoding. The live names include the access-control role events, asset creation, burn, issuance and pause events, compliance freeze and unfreeze events, identity registration events, the transfer events token.transfer.provisional, token.transfer.final version 2, and token.transfer.retracted versions 1 and 2, the identity claim events, the provider verdict event, the trading venue order status event, token sale events, identity status, custody events, and the eleven XvP settlement events under xvp.*.final. Compliance recall, settlement retraction, and pre-inclusion pending names have no active producer.

Can a retracted or recalled event itself be retracted later?

No. A retraction caused by a chain reorganisation supersedes a provisional observation, or a stored version 1 token.transfer.final event, a legacy event the platform sent at inclusion. A retracted or recalled event is not itself retracted by a later chain reorganisation.

Do two endpoints see the same identifier for the same occurrence?

No. An identifier names one endpoint's delivery record, not the occurrence itself, which is why deduplication works per endpoint rather than across endpoints.

Was this page helpful?