Skip to content
Payvol

Get started

Install

Four packages, all Apache-2.0, all published to npm. None of them opens a network connection, holds a key, or needs a server.

The four packages

PackageWhat it is for
@payvol/core The data model: encode and decode the canton: URI, validate a request, canonicalise it and hash it. A /draft02 subpath carries the newer profile, its observation adapter and the reconciler.
@payvol/qr The carriers: QR payload text, web+canton links, and NFC NDEF records. Drawing the QR image and writing the tag are your renderer's job, not this package's.
@payvol/conformance The vectors and the runner, so an independent implementation can be checked rather than trusted.
@payvol/cliThe same operations from a terminal, and the conformance runner as a command.

Installing

npm install @payvol/core @payvol/qr

# the conformance suite, when you are checking an implementation
npm install --save-dev @payvol/conformance

# the CLI needs no install at all
npx @payvol/cli conformance

Proving the install

Everything below ran in an empty directory against the published packages.

// Everything the four packages give you, from a clean install.
import { encode, decode, validate, toCanonical, sha256 } from '@payvol/core';
import { qrPayload, ndefUriRecord, parseNdefUriRecord } from '@payvol/qr';
import { runBundledVectors, loadAllVectors } from '@payvol/conformance/node';
import { formatSummary } from '@payvol/conformance';

const request = {
  version: '0.1',
  type: 'transfer',
  recipient: 'payee::1220aabbcc',
  instrument: 'DSO::1220be58/Amulet',
  amount: '12.50',
  reference: 'INV-2026-0042',
};

const uri = encode(request);
console.log('uri        ', uri);
console.log('round trip ', decode(uri).reference === request.reference);
console.log('valid      ', validate(request).valid);
console.log('digest     ', sha256(toCanonical(request)).slice(0, 32), '…');
console.log('qr payload ', qrPayload(request) === uri);
console.log('ndef round ', parseNdefUriRecord(ndefUriRecord(request)) === uri);
console.log('vectors    ', loadAllVectors().length);
console.log(formatSummary(runBundledVectors()).split('\n').pop());
Output, captured from a real run
uri         canton:payee%3A%3A1220aabbcc?instrument=DSO%3A%3A1220be58%2FAmulet&amount=12.50&reference=INV-2026-0042
round trip  true
valid       true
digest      e3cdfb5a334a25089851d9515b12d20a …
qr payload  true
ndef round  true
vectors     146
PASS: 146 passed, 0 failed, 0 skipped (146 total)

Output from @payvol/core version 0.4.0 and its sibling packages, installed from npm, on 2026-10-18.

Node and the browser

engines.node is >=20.19.0 on all four, which is what the resolved @noble/hashes requires. Below that an engine-strict install refuses.

@payvol/core and @payvol/qr are dependency-light and run unchanged in a browser: no node:crypto, no filesystem. @payvol/conformance splits deliberately — the root entry takes vectors as data and runs anywhere, while @payvol/conformance/node carries the file loaders and needs Node.

Which version is which

The npm version and the profile version are different numbers and move independently. The packages are on one npm version; the shipped data profile is 0.1 and the profile under development is 0.2-draft. A recent package writing a 0.1 artifact is normal. Versioning and deprecation has the full account.