Proof of Transfer
Integrating Proof of Transfer capability into a Canton Network Explorer gives users a seamless interface to verify transaction statuses natively, while preserving privacy.
- Canton Network Explorer
- Canton Network Wallet
Integration Blueprint
To provide a seamless customer journey, the Explorer handles incoming payload information—anUpdateID and a Transfer Object payload—usually supplied via direct user copy-pasting or automated routing via a platform referral URL parameter. The platform then submits this data payload to the DA Registry API to render an indisputable confirmation receipt.Step-by-Step Implementation Flow
Follow this workflow sequence to build the verification stack inside your network explorer ecosystem.1
1. Configure the Target Inbound Route
Create a dedicated, public route in your application routing profile (e.g.,
/verify-transfer) designated to handle incoming cryptographic verification payloads. Ensure the handler is equipped to extract query string components seamlessly if redirected from external wallet histories.2
2. Construct the Payload Input Form Interface
Design a clean input card component. If parameters are present in the URL path, auto-populate the data fields for the user. If blank, provide a structured text area box allowing the user to paste their raw transaction JSON payload manually.
3
3. Query the DA Registry Endpoint
Dispatch an asynchronous network request from your application frontend layer directly to the live DA Registry network service infrastructure node using the structured body schemas.
Curl Request Signature
curl -X POST "[https://api.utilities.digitalasset.com/api/utilities/v0/registry/transfer/v0/proof](https://api.utilities.digitalasset.com/api/utilities/v0/registry/transfer/v0/proof)" \
-H "Content-Type: application/json" \
-d '{
"updateId": "1220b1223907e943aa24b52e874a78c86067bafcdb429958994cbd2b33fc41df5e1a",
"transfer": {
"sender": "issuer::12204b6be4677e1e110e63cb3dcd89c62025932458547a09e580458e29e822e9ee26",
"receiver": "holder::12204b6be4677e1e110e63cb3dcd89c62025932458547a09e580458e29e822e9ee26",
"amount": "1.0000000000",
"instrumentId": {
"admin": "registrar::12204b6be4677e1e110e63cb3dcd89c62025932458547a09e580458e29e822e9ee26",
"id": "INST"
},
"requestedAt": "2025-12-09T13:29:42.6187Z",
"executeBefore": "2025-12-12T13:28:53.7492Z",
"inputHoldingCids": [
"0020a2a23208de8d9fec1efd1c377d9a4343eac83f27b26b554f1c9e95c9653c05ca12122056c38daac3b523885fe8436215c72d0181e81e34379918246fc0ef75852990f9"
]
}
}'
4
4. Parse Outcomes & Render Visual Verification Status
Read the structured enum value returned from the API service. Update the client view container to reflect the deterministic ledger evaluation output cleanly using descriptive status layouts.
API Request Schema Specifications
Your interface layer must accurately frame the request body definitions before transmitting data packages to the network node validation server.Technical Payload Fields
updateId
string
required
The unique cryptographic ledger hash tracking indicator marking the target execution sequence window.
transfer
object
required
The private core transaction details package required to process cryptographic balance sheet verification.
Show Properties Block
Show Properties Block
sender
string
required
The specific identity fingerprint address origin string dispatching the digital asset.
receiver
string
required
The destination identity fingerprint address authorized to take legal custody of the asset.
amount
string
required
Alphanumeric decimal string specifying the absolute transfer token unit volume.
instrumentId
object
required
Identifies the core registry blueprint details governing the tokenized asset.
requestedAt
string (date-time)
required
ISO-8601 string mapping the exact timestamp historical moment the transfer workflow initialization sequence fired.
executeBefore
string (date-time)
required
The drop-dead expiration constraint timeline timestamp bounding the transaction validity lifecycle on-chain.
inputHoldingCids
array of strings
required
The explicit array of structural tracking contract identifiers used directly to fund the ledger movement.
UI Component States & Response Handling
To ensure alignment with network expectations, map the direct string responses from the DA Registry API into intuitive, color-coded dashboard indicators for your end users.- Success Resolution
- Pending Evaluation
- Failure Response
- Validation Error Handling
Rendering UI Target: Balanced Verification Badge
The transaction variables are authenticated against the ledger state and indicate successful contract finalization.Response Sample
{
"status": "Success"
}
Interface Suggestion: Render a prominent checkmark module highlighting an “Indisputably Settled” receipt statement. Users can confidently treat this transaction as settled.
Rendering UI Target: Progress Indicator Badge
The parameters represent a structurally valid ledger entry path, but the contract steps are still moving through live execution queues.Response Sample
{
"status": "Pending"
}
Interface Suggestion: Inform users that the asset transfer is in an intermediate lifecycle phase (e.g., a two-step transfer workflow where the destination party hasn’t formally accepted an open offer yet). Advise re-evaluating once final settlement commits.
Rendering UI Target: Terminated Execution Badge
The proof data successfully resolved to a historical ledger event path, but the workflow instructions failed execution or were rejected.Response Sample
{
"status": "Failure"
}
Interface Suggestion: Update the dashboard to inform the user that the transaction request was intentionally canceled, explicitly aborted by a counterparty, or simply expired on-chain.
Rendering UI Target: Input Mismatch Panel (HTTP 400)
The input fields failed lookup, are missing parameters, or contain structured mismatches against live on-chain transactional tracking parameters.Response Sample
{
"error": "invalid_request",
"error_description": "Something went wrong"
}
Data Privacy Guardrail Rule: The backend deliberately zero-discloses tracking details to prevent unwanted transaction state farming by unauthorized actors. Ensure your Explorer frontend handles errors elegantly with a general “Invalid Proof Credentials” module rather than displaying custom data logs.
Guide overview
To enable this transfer proofing capability, wallets must make the Transfer Object payload and UpdateID extractable, allowing end-users to easily locate and copy this data directly from their transaction history to use in proofing services or network explorers.This guide provides the technical specifications for locating and extracting the Transfer Object from the ledger via the JSON API.Exposing the Transfer Object and UpdateID
Technical Guidelines: What Constitutes the Transfer Object?
The UpdateID is the unique identifier for a transaction on the ledger. With it, you can fetch the Created, Exercised, and Archived events for that specific transaction. NOTE: The wallets need to ensure that they display the most recent update for a given transfer. For example, in the case of a 2 step transfer, Wallet Providers will need to explicitly refresh the updateID, after the transaction has been accepted, so that they display the transfer, not just the offer.The underlying schema defining the Transfer Object can be referenced in the DAML model here:Splice/Api/Token/TransferInstructionV1.damlThe Transfer Object can also be serialized into JSON format, as shown in the following example:- JSON
{
"sender": "issuer::122...",
"receiver": "holder::122...",
"amount": "2.0000000000",
"instrumentId": { "admin": "...", "id": "INST" },
"requestedAt": "2026-03-01T13:58:32.626Z",
"executeBefore": "2026-03-04T13:58:27.335Z",
"inputHoldingCids": ["005152f0eae9..."],
"meta": {
"values": {
"splice.lfdecentralizedtrust.org/reason": ""
}
}
}
UpdateID: GET /v2/updates/update-by-idLocating the Transfer Object (By Transaction State)
Depending on the lifecycle stage of the transaction, the Transfer Object is located in different event arguments. You will need to parse the events returned from the endpoint above based on these three scenarios:Scenario A: The Transfer Offer is CreatedIf the update represents the creation of a transfer offer, look for a Created event.- Template:
Utility.Registry.App.V0.Model.Transfer:TransferOffer - Location: Extract the Transfer Object directly from the
createArgumentof this event.
- JSON
{
"createdEvent": {
"templateId": "...:Utility.Registry.App.V0.Model.Transfer:TransferOffer",
"createArgument": {
"operator": "operator::122...",
"provider": "provider::122...",
"transfer": {
"sender": "issuer::122...",
"receiver": "holder::122...",
"amount": "2.0000000000",
"instrumentId": { "admin": "...", "id": "INST" },
"requestedAt": "2026-03-01T13:58:32.626Z",
"executeBefore": "2026-03-04T13:58:27.335Z",
"inputHoldingCids": ["005152f0eae9..."],
"meta": { "values": { "splice.lfdecentralizedtrust.org/reason": "" } }
}
}
}
}
- Template:
Utility.Registry.V0.Rule.Transfer:TransferRule - Triggering Choices: The event must be triggered by one of the following choices:
TransferRule_DirectTransferTransferRule_TwoStepTransferTransferRule_Transfer(This choice will be deprecated. It is only required for backwards compatibility)
- Location: Extract the Transfer Object from the
choiceArgumentof this event.
- JSON
{
"ExercisedEvent": {
"templateId": "...:Utility.Registry.V0.Rule.Transfer:TransferRule",
"choice": "TransferRule_DirectTransfer",
"choiceArgument": {
"transfer": {
"sender": "auth0...::122...",
"receiver": "auth0...::122...",
"amount": "12.0000000000",
"instrumentId": { "admin": "...", "id": "INST" },
"requestedAt": "2026-02-24T16:27:33.139Z",
"executeBefore": "2026-02-27T16:27:31.633Z",
"inputHoldingCids": ["0000c37c6..."],
"meta": { "values": { "splice.lfdecentralizedtrust.org/reason": "" } }
}
}
}
}
- Identify the Event: Look for an Exercised event matching the following:
- Interface ID:
Splice.Api.Token.TransferInstructionV1:TransferInstruction - Triggering Choices:
TransferInstruction_RejectORTransferInstruction_Withdraw
- Interface ID:
- Fetch the Contract ID: Extract the Contract ID of the transfer offer from this exercised event.
- Fetch the Original Offer: Query the JSON API using the extracted Contract ID:
GET /v2/events/events-by-contract-id - Location: Extract the Transfer Object from the
createArgumentof the original transfer offer (transfer instruction) returned by this secondary query.
- JSON
{
"CreatedEvent": {
"templateId": "...:Utility.Registry.App.V0.Model.Transfer:TransferOffer",
"createArgument": {
"operator": "operator::12209b02d...",
"provider": "provider::1220c07e7...",
"transfer": {
"sender": "issuer::1220c07e7...",
"receiver": "holder::1220c07e7...",
"amount": "2.0000000000",
"instrumentId": { "admin": "registrar::1220c07e7...", "id": "INST" },
"requestedAt": "2026-03-01T13:58:32.626Z",
"executeBefore": "2026-03-04T13:58:27.335Z",
"inputHoldingCids": ["005152f0eae9..."],
"meta": { "values": { "splice.lfdecentralizedtrust.org/reason": "" } }
}
}
}
}
Data Persistence and Pruning
Ledger data is subject to pruning. The JSON API queries described in previous section will only succeed if the transaction events have not yet been pruned from the participant node.Wallet Developer Action Required: To ensure end-users can always access their Transfer Objects for the proofing service, wallets MUST persist the Transfer Object and UpdateID data in their own backend databases at the time the transaction occurs. Relying strictly on real-time ledger queries for historical transactions will result in errors once the transactions are pruned. PQS can be considered as an option for storing ledger data.Locating the Transfer Object (as an end-user)
LabellingThere are two key items to be displayed within the transaction details:- UpdateID
- Transfer object
- Click to open a modal/side-panel component or an external browser window. Since the content is hidden to start, when a user clicks to open this component, the json object should by default be displayed fully. This component shows the label of “Transfer object”, contains the full json object for reviewing, and accessible copy button.
- If an external window is used, its domain must match the application domain from which the window was triggered.
- The icon or button for a user to click to review the json object must be accessible, alongside the copy icon/button. Users can copy the object without opening the review component.
- Click to open the accordion containing the content. The accordion is closed by default, and a copy button is accessible without opening the accordion.
The Proof of Transfer API is supporting the validation of multiple transaction within an UpdateID, that means also Batch Transfer can be validated. In order to enable it from a wallet perspective, ensure that end users can extract the
Transfer Object for each individual transaction of a batch.Was this page helpful?
YesNo