npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

x402-xrpl

v0.2.0

Published

XRPL x402 v2 SDK (exact presigned Payment tx scheme)

Downloads

185

Readme

x402-xrpl

TypeScript SDK for x402 v2 payments over XRPL using the exact presigned Payment tx blob scheme from this repository.

This package is intended to mirror the ergonomics of the Python SDK (x402_xrpl/) so developers can easily build:

  • Express x402-protected resource servers
  • TypeScript buyer clients that automatically handle HTTP 402 Payment Required

Install

Requires Node.js 18+.

npm install x402-xrpl

If you are building a resource server:

npm install express

Express resource server

import express from "express";
import { requirePayment } from "x402-xrpl/express";

const app = express();

app.use(
  requirePayment({
    path: "/ai-news",
    price: "1000", // XRP drops; for IOUs use the XRPL value string (e.g. "1.25")
    payToAddress: "rhaDe3NBxgUSLL12N5Sxpii2xy8vSyXNG6",
    network: "xrpl:1",
    asset: "XRP",
    facilitatorUrl: "http://127.0.0.1:8011",
    resource: "demo:ai-news",
    description: "AI news feed (paid)",
  }),
);

app.get("/ai-news", (_req, res) => res.json({ ok: true }));

app.listen(8080, () => console.log("listening on http://127.0.0.1:8080"));

XRPL SourceTag (analytics)

By default, this SDK issues extra.sourceTag = 804681468 in the 402 accepts[] requirements, and buyer clients will sign XRPL Payment transactions with SourceTag = 804681468 (so XRPL can query/aggregate these payments on-ledger).

To override the tag for your app, set extra.sourceTag:

app.use(
  requirePayment({
    // ...
    extra: { sourceTag: 123 },
  }),
);

IOU notes (non-XRP assets)

  • Set asset to a canonical XRPL currency code: 3 chars or 40-hex.
    • A symbol like RLUSD must be provided as its 40-hex currency code, unless you explicitly opt into UTF-8 encoding using the currency helpers.
  • Provide the issuer as issuer or extra.issuer.
  • Set price to the IOU value string (e.g. "1", "1.25").

For RLUSD, raw payment requirements should use 524C555344000000000000000000000000000000 as asset and include the issuer. If you want to start from a display symbol, convert it first:

import { resolveCurrencyCode } from "x402-xrpl";

const asset = resolveCurrencyCode("RLUSD", { allowUtf8Symbol: true });

Buyer client (fetch wrapper)

x402Fetch implements the standard x402 flow:

  • Make request
  • If 402 with accepts[], select a PaymentRequirements
  • Build PAYMENT-SIGNATURE
  • Retry once

Buyer clients call the protected resource URL and use XRPL WS plus network as a guard. They do not take a facilitator URL.

import { x402Fetch } from "x402-xrpl";
import { Wallet } from "xrpl";

const wallet = Wallet.fromSeed(process.env.XRPL_SEED!);

const fetchPaid = x402Fetch({
  wallet,
  network: "xrpl:1",
  // Optional: override the default public WS endpoint
  // wsUrl: "wss://s.altnet.rippletest.net:51233",
});

const resp = await fetchPaid("http://127.0.0.1:8080/ai-news");
console.log(resp.status, await resp.text());

Optional X402 Secure / Verifiable Intent

XRPL x402 payments can optionally carry an extensions.x402Secure envelope. When the hosted XRPL Facilitator receives that envelope, it calls X402 Secure internally; X402 Secure calls Trustline; and settlement only proceeds if the risk decision allows it. If a payment carries no x402Secure envelope, the SDK sends a normal XRPL x402 payment and the Facilitator can skip X402 Secure in optional mode.

Learn more about the product at X402 Secure.

The SDK exposes a verifiableIntentProvider seam. The provider receives the Facilitator-issued x402Secure envelope from the 402 Payment Required response and may return an x402SecurePatch. For full L1-L3 Verifiable Intent, attach the chain under verifiableIntentChain.

import { LocalProducerProvider, x402Fetch } from "x402-xrpl";
import { Wallet } from "xrpl";

const provider = new LocalProducerProvider({
  // Load a cached L1/L2 delegation from your trusted surface.
  // L1 is issued by Trustline for your org; L2 is owner-signed; L3 is signed fresh per payment.
  delegation: async () => ({
    l1Credential: { format: "sd+jwt", sdJwt: cachedL1, kid: issuerKid },
    l2Delegation: { format: "kb-sd-jwt+kb", sdJwt: cachedL2 },
    agentPrivateJwk,
    agentKid,
  }),
});

const fetchPaid = x402Fetch({
  wallet: Wallet.fromSeed(process.env.XRPL_SEED!),
  network: "xrpl:0",
  verifiableIntentProvider: provider,
});

If your agent cannot hold a Trustline issuer secret, use RemoteIssuerProvider with your own backend or the T54 issuer broker. The remote endpoint only issues L1. The SDK still signs L2 with the owner key and L3 with the agent key locally:

import { RemoteIssuerProvider, RemoteIssuerSource, x402Fetch } from "x402-xrpl";

const provider = new RemoteIssuerProvider({
  issuer: new RemoteIssuerSource({
    endpoint: "https://agent.example/api/vi/issue-l1",
    headers: () => ({ authorization: `Bearer ${shortLivedIssuerToken}` }),
  }),
  issueRequest: {
    subject: ownerAccountRef,
    ownerPublicJwk,
    allowedChains: ["xrpl"],
    allowedAssets: ["XRP"],
    spendingCeiling: "0.001",
    validitySeconds: 3600,
    ownerProof,
  },
  ownerPrivateJwk,
  ownerKid,
  agentPrivateJwk,
  agentPublicJwk,
  agentKid,
  constraints: { allowed_chains: ["xrpl"], allowed_assets: ["XRP"], per_transaction_max: "0.001" },
});

Important boundaries:

  • Do not put Trustline API keys or issuer secrets into the x402 payment payload. L1 issuance should happen in your trusted backend or issuer surface.
  • Keep issuer and verifier environments aligned. A staging-issued L1 should be verified by staging Trustline/X402 Secure; a production-issued L1 should be verified by production Trustline/X402 Secure.
  • The provider patch cannot overwrite Facilitator-issued fields such as requirementToken, decisionToken, or trustlineEvidenceSessionId.
  • If the provider returns requires_confirmation, the SDK does not sign or retry. This is the right response when the owner has not yet approved an L2 delegation.

Local development

From this package directory:

npm install
npm run build
npm test