obol-x402-sdk
v0.1.1
Published
Stripe-like x402 payments for XRPL — protect any API endpoint with one line of code
Downloads
21
Maintainers
Readme
obol-x402-sdk
Stripe-like x402 payments for XRPL. Protect any API endpoint with one line of code.
Obol handles the entire x402 payment flow — issuing 402 challenges, verifying signed transactions, settling on the XRPL ledger, and logging everything to your dashboard.
Install
npm install obol-x402-sdk
# or
pnpm add obol-x402-sdkQuick start
1. Create a client (once)
// lib/obol.ts
import { Obol } from "obol-x402-sdk";
export const obol = new Obol(process.env.OBOL_API_KEY!);2. Protect an endpoint
// app/api/weather/route.ts (Next.js App Router)
import { obol } from "@/lib/obol";
export async function GET(request: Request) {
const payment = await obol.protect("your-endpoint-uuid", request);
if (!payment.verified) return payment.response; // 402
try {
const data = { goodWeather: true };
await payment.settle();
return Response.json(data);
} catch (error) {
await payment.fail(error);
return Response.json({ error: "Something went wrong" }, { status: 500 });
}
}That's it. No headers to parse, no facilitator URLs to manage, no payment logic to write.
How it works
Request arrives
|
v
obol.protect("endpoint-uuid", request)
|
|-- Fetches endpoint config from Obol API (cached 5 min)
|
|-- No payment header?
| -> Returns 402 Response with x402 payment instructions
|
|-- Has PAYMENT-SIGNATURE header?
| -> Verifies with XRPL facilitator
| -> If invalid: returns 402 with error
| -> If valid: returns gate with settle() and fail()
|
payment.settle() -- Submits tx to XRPL ledger + logs success
payment.fail(err) -- Skips settlement + logs failure (buyer keeps funds)The key insight: payment is verified before your business logic runs, but only settled after it succeeds. If your code throws, the buyer keeps their money.
API
new Obol(apiKey, options?)
| Parameter | Type | Description |
|-----------|------|-------------|
| apiKey | string | Your Obol API key (from the dashboard) |
| options.baseUrl | string | Override the Obol API URL. Default: https://api.obol.dev |
| options.cacheTtl | number | Config cache TTL in ms. Default: 300000 (5 min) |
obol.protect(endpointId, request)
Returns a PaymentGate — either a 402 response to return, or a verified payment to settle.
type PaymentGate =
| { verified: false; response: Response }
| {
verified: true;
payer: string; // XRPL address
network: string; // "xrpl:1" (testnet) or "xrpl:0" (mainnet)
amount: string; // Amount in drops
asset: string; // "XRP"
settle(): Promise<SettlementResult>;
fail(error?: unknown): Promise<void>;
};payment.settle()
Submits the transaction to the XRPL ledger and logs success to your dashboard.
const result = await payment.settle();
// { success: boolean, txHash: string | null, error: string | null }Safe to call multiple times — subsequent calls are no-ops.
payment.fail(error?)
Logs a failure to your dashboard without settling. The buyer's funds are never touched.
await payment.fail(new Error("Database write failed"));Free endpoints
Set price to "0" in the dashboard. protect() returns verified: true immediately with payer: null — no payment flow, just analytics logging.
const payment = await obol.protect("free-endpoint-uuid", request);
// payment.verified === true, payment.payer === nullFramework support
The SDK uses Web standard Request and Response objects. It works with any framework that supports them:
- Next.js App Router (route handlers)
- Hono
- Cloudflare Workers
- Deno
- Express (with req-to-Request conversion, see below)
Express adapter
import express from "express";
import { Obol } from "obol-x402-sdk";
const obol = new Obol(process.env.OBOL_API_KEY!);
const app = express();
app.get("/api/resource", async (req, res) => {
// Convert Express req to Web Request
const url = `${req.protocol}://${req.get("host")}${req.originalUrl}`;
const headers = new Headers();
for (const [key, val] of Object.entries(req.headers)) {
if (typeof val === "string") headers.set(key, val);
}
const webReq = new Request(url, { method: req.method, headers });
const payment = await obol.protect("endpoint-uuid", webReq);
if (!payment.verified) {
for (const [k, v] of payment.response.headers.entries()) res.set(k, v);
res.status(payment.response.status).send(await payment.response.text());
return;
}
const data = { message: "Paid content" };
await payment.settle();
res.json(data);
});Environment variables
| Variable | Required | Description |
|----------|----------|-------------|
| OBOL_API_KEY | Yes | Your project API key from the Obol dashboard |
Requirements
- Node.js 18+
- Zero runtime dependencies
