SDK reference
Settlement
Issuing receipts, reading them, and verifying one produced by someone else.
issueReceipt(input)
Requires a credential.
const receipt = await path.issueReceipt({
requestId: '7fk2m9pq3vx8',
payerMember: 'member-b',
amount: '5000',
currency: 'XOF',
rail: 'mobile_money',
sourceReference: 'MM-8891-2231',
});
receipt.reference; // "rcpt_9a41c8f2b731"
receipt.signature;
receipt.kid;| Field | Notes |
|---|---|
requestId | Optional — a spontaneous payment has no request |
sourceTxHash | For rails that have one |
sourceReference | For rails that do not. At least one of the two |
attestations | Optional signed claims travelling with the receipt |
Separate from marking a request paid, because payment and proof are two events that can be seconds or hours apart. Conflating them forces every integration to pretend a mobile-money transfer settles as fast as a signature.
readReceipt(reference)
No credential.
const receipt = await path.readReceipt('rcpt_9a41c8f2b731');Public because a receipt is only useful if a third party can check it — a supplier, an auditor, the payer's own institution. Behind a credential, the only people who could verify a settlement would be the two who already agree about it.
Verifying someone else's
import { verifyAgainstIssuer } from '@pathprotocol/sdk';
const { valid, reason } = await verifyAgainstIssuer(receipt, 'https://api.other-member.com');The key comes from the issuer's own discovery document. Not from whoever handed you the receipt, and not from a central registry: an operator vouching for another's key rebuilds the hierarchy the protocol avoids, and means compromising one operator compromises statements about others.
Offline
import { verifyEnvelope } from '@pathprotocol/sdk';
const valid = verifyEnvelope(receipt, cachedIssuerPublicKey);Once you hold the key, verification needs no network at all. That is what lets a receipt be shown as a QR code and checked by someone with no account anywhere — the concrete form of finality is a verifiable state, not a promise.
Unknown key id
const { valid, reason } = await verifyAgainstIssuer(receipt, issuerUrl);
// reason: 'Issuer publishes no key with kid "op_example_2026_02"'Reported distinctly from a bad signature, because it usually means a rotation you have not picked up. Refetch the issuer's document and try again before concluding anything.
The reserved field
receipt.route; // null, always, in v0.1Declared on every receipt and never populated. When liquidity routing is specified it will carry the legs, providers and shares.
Carry it through untouched. Do not strip it, and do not reject an object because a newer counterparty populated it — dropping unknown fields is the most common way to break forward compatibility, and it fails silently.