GitHub

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/sdk

2. 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-10-04.genesis',
});

const config = await path.discovery();

console.log(config.protocol_versions);   // ["0.2.0", "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-10-04.genesis',
  credential: {
    kid: 'member_2026_01',
    privateKeyHex: process.env.PATH_MEMBER_KEY!,
    memberSlug: 'your-member',
  },
});

const request = await path.createRequest({
  amount: { value: '5000', asset_type: 'fiat', asset_code: 'USD' },
  accepts: [
    {
      rail: 'book',
      asset_type: 'fiat',
      asset_code: 'USD',
      fees: [{ kind: 'operator', amount: { value: '25', asset_type: 'fiat', asset_code: 'USD' }, paid_by: 'payer' }],
    },
  ],
  orderReference: 'ord_10482',
  expiresAt: new Date(Date.now() + 86_400_000).toISOString(),
});

console.log(request.url);       // https://api.example.com/path/7fk2m9pq3vx8
console.log(request.reference); // 7fk2m9pq3vx8

Pass amount: null and the payer chooses — a tip, a donation, an open invoice.

Fees sit on each accepts entry and travel 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);  // { value: "5000", asset_type: "fiat", asset_code: "USD" }
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.markPaid(request.reference);

await path.issueReceipt({
  issuedBy: 'payee',
  request: request.reference,
  via: { rail: 'book', asset_type: 'fiat', asset_code: 'USD' },
  received: { value: '5000', asset_type: 'fiat', asset_code: 'USD' },
  railReferences: [{ type: 'book_entry', value: 'LE-8891-2231' }],
});

railReferences is required on a settled receipt. A receipt nobody can trace back to a movement on a rail is an assertion, and the point of a receipt is that a stranger can go and check.

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.

On this page