cantonDetails object on the transaction.
The webhook carries the identical
cantonDetails object, so a client that handles one needs no second parser for the other. See Canton Transaction Webhooks.
Identify a Canton transaction
The presence ofcantonDetails is the authoritative signal that a transaction is a Canton item. A transaction with no cantonDetails object is not one.
The three shapes of cantonDetails
At most one of these three keys is present on any transaction.
The split is not inbound versus outgoing. Every response transaction you create is outgoing and carries
offerResponse, and in the vault-to-vault transfer case a pre-existing outgoing transfer is stamped with a populated availableResponses.
If cantonDetails is present but none of the three keys are, the transaction is Canton-related but outside these shapes. Skip it rather than treating it as an error.
Decide whether an offer can be responded to
This is the rule the rest of the page depends on. One offer can flag two transactions withPENDING_RECEIVER_APPROVAL. In the vault-to-one-time-address transfer case you see this:
409 on the second. A client that filters on availableResponses.length > 0 posts once. Transaction B is neither broken nor a duplicate. It is a linked leg whose only job is to point at where the answer goes.
availableResponses means nothing is answerable here. It does not always mean the offer is closed: on a linked leg it means answer elsewhere, and originalTransactionId says where. The array going empty is also the terminal signal, covering answered, expired, and a response in flight. There is no separate resolved flag.
Fields on offerResponse
Not every offer has a deadline, so treat
expiresAt as optional. Where it is present and passes, the transaction moves to sub-status RECEIVER_APPROVAL_TIMEOUT and availableResponses empties.availableResponses carries identifiers, not argument shapes. What each value means, and which fields it requires, lives in the matching variant of the request schema on Answer an offer. Treat the enum as open: a new vendor flow adds a value, so tolerate values you do not recognize rather than failing to deserialize.
Answer an offer
Takeid from the answerable transaction. That is the offerId path parameter of Answer an offer.
cantonDetails.offerResponse.domain into the body’s domain, then pick a responseType from availableResponses.
Fields on call
Present on an outgoing transaction that carries a call you made with Make a Canton call. This makesGET /v1/transactions filterable into your Canton calls without a per-call-type collection endpoint.
domain is derivable from type, but it is published so that filtering for all your onboarding activity is one filter across offers and calls rather than an eight-entry mapping each client reimplements.
Fields on settlement
Present on the settlement receipt, the transaction that appears when a venue executes an allocation you had locked. It isCOMPLETED at creation and carries the cross leg: the asset and amount you receive, where the allocation transaction carried what you gave.
Without
originalTransactionId the credit side of a delivery-versus-payment is an unexplained incoming transfer, and the two halves of one trade cannot be reconciled through the API.
The ALLOCATED lifecycle
An accepted allocation is the one place a Canton transaction sits atCONFIRMING for an extended period rather than passing through it:
CONFIRMING with ALLOCATED is the only state in which ALLOCATION_WITHDRAW accepts the transaction, and that transaction’s id is what you pass as allocationTransactionId to Make a Canton call.
Amounts
amount is a decimal string, not a number. Token amounts exceed the precision of an IEEE 754 double, so a JSON number would round silently. Parse with a decimal library rather than parseFloat. Operations that move nothing, including onboarding, invites, and allow-list changes, carry "0".