Introduction
periplo is a TypeScript client library for x402 payments on Stellar. It is built around upto: instead of paying a fixed price, a buyer signs a spending ceiling once, and a facilitator later settles only the amount actually used. The ceiling never moves; only the real usage does.
signed ceiling: [████████████████████████████████] 0.10 USDC
actually used: [████████░░░░░░░░░░░░░░░░░░░░░░░░] 0.05 USDC settled, 0.05 USDC refunded
That is the real shape of the first upto settlement on stellar:testnet: a buyer signed a ceiling of 0.10 USDC, the seller measured 0.05 USDC of real usage, and the UptoSettlement contract settled 0.05 USDC to the seller and refunded the other 0.05 USDC to the buyer in the same transaction. You can check it yourself on Stellar Expert, or watch it happen live on the demo page.
What periplo gives you
- Buyer side: sign an
uptoceiling (createUptoStellarPayer) or pay a fixedexactprice (createExactStellarPayer), then fetch a paid resource with retry built in (payAndFetch,discoverPayAndFetch). - Seller side: declare a paid resource's discovery metadata (
definePaidResource), advertise anuptoceiling (buildUptoRequirements), and settle real usage once it is known (settleUptoUsage).
Neither side reimplements payment verification or settlement: every call goes through HTTPFacilitatorClient, the same published client from @x402/core that any x402 facilitator understands.
What works today, honestly
exactis live on the public facilitator atperiplo-testnet.fly.dev(stellar:testnet), used throughout the full demo and conformance evidence.uptosettles against a deployedUptoSettlementSoroban contract, but requires a facilitator configured with that contract's address. The public facilitator's ownGET /supporteddoes not advertiseuptotoday, onlyexact; check it yourself before assuming otherwise. Running your own facilitator (self-facilitation) or pointing at one that supportsuptois required to settle it end to end.- Everything here is
stellar:testnetonly. Periplo does not operate on mainnet yet, andcreateUptoStellarPayerthrowsUptoMainnetNotSupportedErrorfor any other network, includingstellar:pubnet.
Requirements
Node.js 22 or newer (the package's engines.node field). No other runtime dependency beyond what npm installs.
Installation
npm i periplo
Verified from a clean folder outside this repository: npm install periplo, then npm install --save-dev typescript @types/node, resolves and installs with no errors, and npx tsc type-checks a file importing from periplo with no errors, given "types": ["node"] in compilerOptions (the package's own types reference Buffer, through @x402/core).
Requirements
- Node.js 22 or newer. Declared in the package's own
engines.nodefield; npm warns on an older Node. @types/node, as a dev dependency, if you use TypeScript. Without it,tscfails withCannot find name 'Buffer'inside@x402/core's own type declarations, whichperiplore-exports through.- Network: everything in this package that talks to Stellar targets
stellar:testnet. There is no mainnet support; see Introduction.
Verifying the install
This checks that the package's error types actually work, without needing any network access or credentials:
import { createUptoStellarPayer, UptoMainnetNotSupportedError } from "periplo";
try {
createUptoStellarPayer("S" + "A".repeat(55), "stellar:pubnet", {
facilitatorBaseUrl: "https://periplo-testnet.fly.dev",
maxSpendPerAuthorization: 1_000_000n,
});
} catch (error) {
console.log(error instanceof UptoMainnetNotSupportedError, (error as Error).message);
}
Real output, from that exact script, run against the package installed from its published tarball:
true upto is only supported on stellar:testnet today; stellar:pubnet (including any pubnet/mainnet network) is not yet supported.
That confirms two things at once: the package is installed and its types resolve, and upto genuinely refuses any network other than stellar:testnet, rather than silently doing the wrong thing.