Get started
Your first request
Ten minutes, no account, and nothing of ours running anywhere. By the end you will have a request, its identifier, and three ways to hand it to somebody.
Install
Two packages. @payvol/core encodes, decodes and validates; @payvol/qr
turns a request into the forms a payer can actually receive.
npm i @payvol/core @payvol/qr Both are on npm and install from the registry. Tested on Node 20. A party id and an instrument id are explained under Create a request, because a request that validates is not automatically one a wallet can pay.
Create a request
A request names who is being paid, in what, how much, and an optional reference that stays
yours. Encoding it produces a canton: URI, and that URI is the whole artifact:
there is no session, and nothing was stored anywhere.
import { encode } from '@payvol/core'
const uri = encode({
version: '0.1',
type: 'transfer',
recipient: 'payvol-demo-recipient',
instrument: 'DSO::1220be58c29e65de40bf273be1dc2b266d43a9a002ea5b18955aeef7aac881bb471a/Amulet',
amount: '1.5000000000',
reference: 'PAYVOL-DEMO-2026-08-01',
}) What those two identifiers are. A Canton party id is
name::fingerprint, where the fingerprint is 68 hex characters beginning
1220. You get yours from the validator or wallet that hosts the party: it is shown
when the party is allocated, and any wallet connected to it will display it. An instrument id is
admin/id, where admin is the party id of the registry that issues the
asset and id is its symbol. The DevNet Canton Coin admin above comes from the
network's own registry metadata endpoint, captured in this repository's fixtures rather than
typed by hand.
A valid request is not a settleable one. validate() answers
whether the artifact is the right shape. It returns warnings when the recipient
is not a full party id, or the instrument names no registry admin, because those are well
formed and unpayable. What settles a request is a wallet: the payer opens it, the wallet
builds a Canton Token Standard transfer, and the payer signs it. You can try that at
/app/pay.
That returns:
canton:payvol-demo-recipient?instrument=DSO%3A%3A1220be58c29e65de40bf273be1dc2b266d43a9a002ea5b18955aeef7aac881bb471a%2FAmulet&amount=1.5000000000&reference=PAYVOL-DEMO-2026-08-01 Seal it
The identifier is derived from the canonical bytes rather than assigned, so two independent implementations that agree on the profile produce the same identifier for the same request. Change one character and it changes completely.
import { decode, sha256, toCanonical } from '@payvol/core'
// the canonical bytes are what an identifier is derived FROM, never assigned
const canonical = toCanonical(decode(uri))
const identifier = sha256(canonical)
// change one character of the request and this changes completely
The digest is domain separated, so it cannot collide with a digest computed under another
profile over the same bytes. SPEC.md in the repository says exactly how.
Deliver it
The same bytes become a QR code, a link, or an NFC tap. Nothing is installed on the payer side and no page has to stay up for the code to keep working.
import { qrPayload, linkPayload, ndefUriRecord } from '@payvol/qr'
// the same bytes, three ways to hand them over
const forQr = qrPayload(uri)
const forLink = linkPayload(uri, { scheme: 'web+canton' })
const forTap = ndefUriRecord(uri) Read it back
A reader decodes the artifact and checks it against the profile. A request it cannot read is refused with a named reason rather than half understood.
import { decode, validate } from '@payvol/core'
const request = decode(scanned)
const result = validate(request)
// a refusal names its rule; it is never a bare false
result.valid // false
result.code // 'EXPIRED'
Profile 0.1 is pinned by 42 conformance vectors. Run them against
your own implementation with npx @payvol/cli conformance, which needs nothing
installed and no repository checkout.
What to do next
- What a wallet must check, and the one answer it cannot reach.
- Reading settlements off a participant you already run.
- What has been established, and what has not, before you plan around any of it.