data object is the standard transaction notification. The only Canton-specific thing on the wire is the cantonDetails key on data.
Which event fires
OnlyTRANSACTION_STATUS_UPDATED carries cantonDetails. A Canton integration can discard every other event type at the front door.
Route an incoming notification
data.id as offerId. Step 4 covers calls you submitted with Make a Canton call. Both are covered end to end in Write Canton Transactions.
The five states to tell apart
- 1. Actionable offer
- 2. Response in flight
- 3. Allocation locked
- 4. Linked leg
- 5. Settlement receipt
An inbound DTCC end-investor onboarding offer.
availableResponses carries both DTCC values, so this transaction ID is the one to answer.Sub-status reference
Note that
CONFIRMING is not transient for Canton. An accepted allocation sits at CONFIRMING with ALLOCATED until the venue settles it.
Delivery semantics
Delivery is at-least-once and unordered. Two notifications for the same transaction can arrive out of timestamp order, andtimestamp is not a sequence number.
Treat every notification as a state snapshot rather than a transition. There is no previousStatus field, by design. Re-read availableResponses on each notification instead of tracking transitions yourself, and make handling idempotent on data.id plus data.status plus data.subStatus.
Parse permissively. Both the envelope and data carry fields beyond this contract, and a strict parser breaks on the next unrelated platform addition.
What your endpoint should return
Return
5XX for a transient failure, because redelivery is what you want. Do not return 4XX for a payload you will never accept, such as one with no cantonDetails, because that becomes a retry loop. Return 200 and drop it instead.
Reconciling without webhooks
The webhook is the push half of the read side.GET /v1/transactions/{txId} is the pull half, and both carry the identical top-level cantonDetails object. Use the pull path at startup, after downtime, or when a delivery fails. See Read Canton Transactions.