@telaro/x402
v0.1.1
Published
x402 payment gate for Solana. Verifies the paying agent's Telaro bond before settlement. Adapters for Express, Hono, and Next.js.
Maintainers
Readme
@telaro/x402
Telaro bond/score gate for x402 services on Solana.
x402 answers "did the agent pay." It does not answer "should I trust
this agent to transact." @telaro/x402 closes that gap — it pulls the
paying wallet out of the x402 payment payload and runs a Telaro
bond + score check on it before the payment settles.
Install
npm install @telaro/x402Use it (Express)
Mount the gate in front of your existing x402 payment middleware. A failing agent is rejected before settlement — you never take the money.
import express from "express";
import { expressX402Gate } from "@telaro/x402";
const app = express();
app.post(
"/premium",
expressX402Gate({
minBond: 1_000_000_000n, // 1,000 USDC (atomic, 6dp)
minScore: 700,
}),
yourX402PaymentMiddleware, // only reached if the gate passes
(req, res) => {
// res.locals.telaro = { ok, payer, trust }
res.json({ ok: true });
},
);A rejected request gets a JSON body and an HTTP status:
| Status | When |
| ------ | ---- |
| 402 | payment missing / unusable (NO_PAYMENT, MALFORMED_PAYMENT, NO_TRANSFER, UNSIGNED_PAYER) |
| 403 | agent identified but fails the policy (NOT_BONDED, BOND_BELOW_MIN, SCORE_BELOW_MIN, FROZEN) |
| 502 | the Telaro lookup itself failed (LOOKUP_FAILED) |
Pass onReject to render the rejection in your own shape (Express only).
Use it (Hono)
import { Hono } from "hono";
import { honoX402Gate } from "@telaro/x402";
const app = new Hono();
app.use("/premium", honoX402Gate({ minBond: 1_000_000_000n, minScore: 700 }));
app.post("/premium", (c) => {
const { payer, trust } = c.get("telaro"); // set by the gate on success
return c.json({ ok: true, payer });
});Use it (Next.js route handler)
fetchX402Gate wraps any Fetch-API handler — a Next.js App Router route
handler, Bun, Deno, or a Cloudflare Worker.
// app/api/premium/route.ts
import { fetchX402Gate, getX402Result } from "@telaro/x402";
export const POST = fetchX402Gate(
async (req) => {
const { payer, trust } = getX402Result(req)!; // gate passed
return Response.json({ ok: true, payer });
},
{ minBond: 1_000_000_000n, minScore: 700 },
);A failing agent gets the 402/403 Response and the handler never runs.
Use it (any framework)
Every adapter is a thin wrapper over the framework-agnostic core:
import { evaluateX402Payment } from "@telaro/x402";
const result = await evaluateX402Payment(
xPaymentHeaderValue,
{ minBond: 1_000_000_000n, minScore: 700 },
);
// result.ok === true → result.payer, result.trust
// result.ok === false → result.code, result.reasonextractPayer(serializedTransactionBase64) is also exported if you only
need to identify the paying wallet.
How identity works (v1)
The agent is identified by the SPL transfer authority that signs the x402 payment transaction — and must hold its Telaro bond under that same Solana wallet. The authority is read from the transfer instruction (not the fee payer), so it works whether the agent pays its own gas or a fee-free facilitator does.
A delegated transfer signs with a key that is not the agent's wallet, so
it simply fails the gate as NOT_BONDED rather than passing as someone
else.
v1 scope
- This package does not verify or settle x402 payments. It runs the trust gate and hands control back; compose it with any x402 stack.
- Solana
exactscheme only. Legacy transactions, and versioned transactions without address lookup tables. - See
docs/internal/x402-solana-spike.mdfor the design rationale.
License
MIT
