Docs
Quickstart
From nothing to a payment request another wallet can read, in about fifteen minutes.
This walks through the smallest useful integration: issue a payment request, read it back the way a foreign wallet would, and verify who signed it.
Nothing here requires network membership.
1. Install
npm install @pathprotocol/sdk2. Read an operator's discovery document
Always the first call. It tells you what an operator speaks, what it claims, and — the part worth reading before anything else — how its directory behaves.
import { PathClient } from '@pathprotocol/sdk';
const path = new PathClient({
baseUrl: 'https://api.example.com',
apiVersion: '2026-09-09.genesis',
});
const config = await path.discovery();
console.log(config.protocol_versions); // ["0.1.0"]
console.log(config.conformance); // ["PATH-ID.Core", "PATH-ADDR.Format", …]
console.log(config.finder.hashing); // "server_side" | "oblivious"finder.hashing says whether the network sees the identifiers being searched. server_side means
it does. You are entitled to know that before joining, and to decline. See Privacy.
3. Issue a payment request
This needs a member credential, since it creates an object signed in your name.
const path = new PathClient({
baseUrl: 'https://api.example.com',
apiVersion: '2026-09-09.genesis',
credential: {
kid: 'member_2026_01',
privateKeyHex: process.env.PATH_MEMBER_KEY!,
memberSlug: 'your-member',
},
});
const request = await path.createRequest({
amount: '5000',
currency: 'XOF',
orderReference: 'ord_10482',
expiresAt: new Date(Date.now() + 86_400_000).toISOString(),
feeDisclosure: { network_fee: '0', operator_fee: '25', currency: 'XOF' },
});
console.log(request.url); // https://api.example.com/p/7fk2m9pq3vx8
console.log(request.reference); // 7fk2m9pq3vx8Leave amount out and the payer chooses — a tip, a donation, an open invoice.
Include feeDisclosure and the fee travels with the terms, shown before the payer commits. A price
disclosed after the decision is not a disclosure.
4. Read it as another wallet would
No credential. This is the path a wallet at a different institution takes.
const anyWallet = new PathClient({ baseUrl: 'https://api.example.com' });
const req = await anyWallet.readRequest(request.url);
console.log(req.amount, req.currency); // "5000" "XOF"
console.log(req.status); // "created"
console.log(req.issuer); // "your-member"
console.log(req.fees); // { network_fee: "0", … }5. Verify the signature
The domain that served the link says where it was fetched from. The signature says who is responsible for it — and with delegated hosting those are routinely different parties.
import { verifyAgainstIssuer } from '@pathprotocol/sdk';
const { valid, reason } = await verifyAgainstIssuer(req, 'https://api.example.com');
if (!valid) throw new Error(`Refusing to display: ${reason}`);Do this before showing a payment screen. Then show the issuer's verified name, never the raw URL — the same reason a card terminal shows a merchant name rather than an acquirer's hostname.
6. Close the loop
When the payment lands, mark the request paid and issue a receipt.
await path.issueReceipt({
requestId: request.reference,
amount: '5000',
currency: 'XOF',
rail: 'mobile_money',
sourceReference: 'MM-8891-2231',
});The receipt is signed and publicly readable, so a third party — an auditor, a supplier, the payer's own institution — can verify it without an account anywhere.
What you just did without joining anything
Read an operator's terms, issued a signed request, read it as a stranger, and verified its origin.
That is the relationship profile, and it is a complete path.
The one thing it does not include is finding someone you have no prior relationship with. That needs a directory, and directories belong to networks.