Receipts and viewing keys
A receipt is a link that opens one transfer. Its owner makes it, and anyone holding it can verify that transfer in a browser.
The transaction viewing key
Every transfer is sealed under its own transaction viewing key, drawn by the sender for that transfer alone. The key opens that transfer and nothing else: no other transfer, no balance, no history.
account.receipt(id) exports the key as a link. Making a receipt changes nothing on chain.
| Made by | Link | Opens |
|---|---|---|
| The sender | /receipt/<signature>#sender.<key> | Every output of the transfer. |
| A recipient | /receipt/<signature>#recipient.<slot>.<key> | The one output paid to them. |
The key stays in the browser
The key is the fragment of the link, the part after #. A browser keeps the fragment to itself: it is not part of the request, so no server receives it, Offrecord included.
The receipt view asks the API for one thing, the transfer’s public chain data by signature. Opening and checking happen locally.
What a reader sees
The reader opens the link in any browser, with no wallet and no account. The view then:
- Fetches the transfer’s public chain data by its signature.
- Opens the sealed outputs with the key from the fragment.
- Rebuilds each output’s commitment from what it opened.
- Compares it with the commitment published on chain.
When they match, the transfer shows as verified with its amount, asset, sender, recipient and time.
The transfer in the Ring
- Sender
- Recipient
- Asset
- Amount
- Commitment
- 9c41e0…b7d2
Opened with the receipt
- Sender
- 7Fq2…mK9d
- Recipient
- Bx4T…e1Zr
- Asset
- USDC
- Amount
- 250.00
- Commitment
- 9c41e0…b7d2
A key that does not open the transfer gives “This receipt does not open this transfer”. A signature the Ring has no transfer for gives “No such transfer”.
Receipts in code
// The owner: a link for one transfer.
const link = await account.receipt(transfer.id)
// The reader: no wallet, no account.
const receipt = await offrecord.verifyReceipt(link)
receipt.amount // base units, as a decimal string
receipt.asset.symbol
receipt.sender
receipt.recipient
receipt.time
receipt.commitment // the published commitment the rebuilt one matchedparseReceiptLink and formatReceiptLink read and write the link without touching the network. Both are in the SDK reference.
The account viewing key
For someone who should see everything, an accountant for instance, the owner exports the account viewing key as a file. Its holder scans the Ring and reads every transfer of that account. The key reads. It does not spend.
const contents = await account.exportViewingKey()In the app, the export is on the view of any transfer in activity, beside Create receipt.