Axiom Stack · Payment Factory · Integrations
Third-party service integrations
Recipes for integrating Payment Factory into your stack. Each example shows how an existing service can accept agent payments — and how an agent can consume any Payment-Factory-compatible service via @axiom-stack/sdk. Settlement is end-to-end on Solana; Axiom backend is not in the path for non-Axiom counterparties.
1. Existing API server (Express, FastAPI)
The smallest integration footprint: publish a .well-known/x402 manifest + add an HTTP 402 path to your priced endpoint. The pattern is identical across frameworks — only the language idioms differ.
Manifest endpoint (Express / Node)
// /.well-known/x402 — publish at <your-domain>/.well-known/x402
import express from "express";
const app = express();
app.get("/.well-known/x402", (_req, res) => {
res.json({
x402Version: 1,
accepts: [{
scheme: "exact",
network: "solana-devnet",
asset: "<your-USDC-mint>",
maxAmountRequired: "50000", // $0.05 atomic units (6 decimals)
payTo: "<YOUR_TREASURY_OWNER>", // owner pubkey, NOT ATA
resource: "https://yourapi.dev/api/v1/inference",
extra: { feePayer: "<facilitator>", decimals: 6, symbol: "USDC" },
}],
});
});402 handler on the priced endpoint
// Priced endpoint with 402 handling
app.post("/api/v1/inference", async (req, res) => {
const sig = req.header("PAYMENT-SIGNATURE") ?? req.header("X-PAYMENT");
if (!sig) {
// No payment header → return 402 with accepts list
return res.status(402).json({
x402Version: 1,
accepts: [/* same shape as .well-known */],
error: "X-PAYMENT header is required",
});
}
// Verify + settle via your x402 facilitator of choice (Coinbase, etc.)
const settled = await facilitator.verifyAndSettle(sig, req.body);
if (!settled.ok) return res.status(402).json({ error: "payment invalid" });
// Execute your real handler
const result = await runInference(req.body);
res.setHeader("PAYMENT-RESPONSE", settled.responseHeader);
res.json({ data: result, meta: { tx_hash: settled.tx_hash } });
});Same pattern in Python (FastAPI)
# FastAPI equivalent — same .well-known/x402 manifest shape
from fastapi import FastAPI, Header, HTTPException, Request
from fastapi.responses import JSONResponse
app = FastAPI()
WELLKNOWN = {
"x402Version": 1,
"accepts": [{
"scheme": "exact",
"network": "solana-devnet",
"asset": "<your-USDC-mint>",
"maxAmountRequired": "50000",
"payTo": "<YOUR_TREASURY_OWNER>",
"resource": "https://yourapi.dev/api/v1/inference",
}],
}
@app.get("/.well-known/x402")
async def wellknown():
return WELLKNOWN
@app.post("/api/v1/inference")
async def inference(
request: Request,
payment_signature: str | None = Header(default=None, alias="PAYMENT-SIGNATURE"),
):
if not payment_signature:
return JSONResponse(status_code=402, content={
**WELLKNOWN,
"error": "X-PAYMENT header is required",
})
# ... verify, settle, execute
return {"data": ..., "meta": {"tx_hash": ...}}Facilitator choice (Coinbase CDP, your own x402 verifier, etc.) is orthogonal — the manifest + 402 surface is the same. Settlement lands in your payTo on Solana directly.
2. Streaming endpoint (SSE / websockets) via MPP-charge
For session-style billing where a single charge authorizes a streaming window (N events / M seconds / B bytes), use an MPP-charge voucher instead of per-call x402. The agent pre-authorizes the spend; settlement on Solana clears async after the session ends or the cap is reached.
# Streaming endpoint (SSE) priced via MPP-charge voucher
# MPP fits session-style billing: one voucher authorizes a stream
# session up to N events / M seconds; charge settles async.
@app.post("/api/v1/stream")
async def stream(
voucher: str | None = Header(default=None, alias="X-MPP-Voucher"),
):
if not voucher:
raise HTTPException(status_code=402, detail="mpp voucher required")
parsed = parse_mpp_voucher(voucher) # validate signature + expiry
if not parsed.ok:
raise HTTPException(status_code=402, detail="voucher invalid")
# Open the stream; each event ticks against the voucher's authorized cap.
async def event_source():
async for event in your_stream():
if parsed.exceeded():
break
parsed.charge(event)
yield f"data: {event.json()}\n\n"
return StreamingResponse(event_source(), media_type="text/event-stream")
# Charge settles async; receipt appears in your treasury ledger.Suits LLM streaming completions, real-time data feeds, agent-to-agent chat sessions, and any workflow where the unit of work is a session, not a request.
3. Agent framework consumer (LangChain, AutoGen, ElizaOS)
From the agent side, any Payment-Factory-compatible service is a single call. @axiom-stack/sdk client.discover() reads the counterparty's manifest; client.pay() handles the x402 / MPP / AP2 dance with the facilitator. Your wallet signer is the only credential — no per-service API keys.
TypeScript (LangChain tool, AutoGen agent, ElizaOS action)
// Agent code consuming any Payment Factory service
import { AxiomClient } from "@axiom-stack/sdk";
const client = new AxiomClient({
// No API key required for pay() against third-party services —
// your own wallet signer handles settlement end-to-end.
walletSigner: yourSolanaWalletSigner,
});
// 1. Discover the service's payment terms
const manifest = await client.discover("https://yourapi.dev");
const target = manifest.endpoints[0];
// 2. Pay + invoke in one call
const res = await client.pay({
to: target.payTo,
amount_micros: parseInt(target.price_atomic_units),
protocol: "x402",
network: target.network,
asset: target.asset,
resource: target.resource,
signer: yourSolanaWalletSigner,
});
// 3. Use the result
console.log(res.tx_sig, res.settled_amount_micros);Python (LangChain tool, autogen agent)
# Same shape in Python — LangChain / AutoGen / ElizaOS tool
from axiom_stack import AxiomClient
client = AxiomClient(wallet_signer=your_solana_wallet)
manifest = client.discover("https://yourapi.dev")
target = manifest.endpoints[0]
result = client.pay(
to=target.pay_to,
amount_micros=int(target.price_atomic_units),
protocol="x402",
network=target.network,
asset=target.asset,
resource=target.resource,
signer=your_solana_wallet,
)
print(result.tx_sig, result.settled_amount_micros)client.pay() ships in SDK 0.5.0 (live on npm + PyPI). Default safety cap max_payment_usdc_micros = 1_000_000 ($1) bounds the blast radius of an accidental loop; override per-call.
4. Wire your signer (reference adapter)
If you build the payment envelope yourself instead of using client.pay(), the pattern is a v0 VersionedTransaction with a transfer_checked instruction, wrapped in the V1 exact envelope. The fee payer is the facilitator (read from /supported), so you pay 0 gas. When the counterparty is Axiom, customers need no Coinbase / CDP credentials — Axiom settles server-side against the facilitator; you only construct and sign the transfer.
// Reference signer adapter — build the x402 'exact' payment envelope.
// You sign a v0 VersionedTransaction; you do NOT need CDP credentials —
// when the counterparty is Axiom, Axiom settles server-side against the
// facilitator. You only construct + sign the transfer.
import {
VersionedTransaction,
TransactionMessage,
} from "@solana/web3.js";
import {
createTransferCheckedInstruction,
} from "@solana/spl-token";
async function buildExactEnvelope({ accepts, signer, connection }) {
const { blockhash } = await connection.getLatestBlockhash();
// transfer_checked: payer ATA → payTo OWNER's ATA, in the asset's mint.
const ix = createTransferCheckedInstruction(
signer.usdcAta, // source ATA
accepts.assetMint, // USDC mint
accepts.payToAta, // destination ATA (owner-derived)
signer.publicKey, // authority
BigInt(accepts.maxAmountRequired), // atomic units
accepts.decimals, // 6 for USDC
);
// Fee payer = facilitator (from /supported); you pay 0 gas.
const msg = new TransactionMessage({
payerKey: accepts.feePayer,
recentBlockhash: blockhash,
instructions: [ix],
}).compileToV0Message();
const tx = new VersionedTransaction(msg);
tx.sign([signer.keypair]); // sign to_bytes_versioned
// V1 'exact' envelope — base64 the signed tx into the X-PAYMENT header.
return {
x402Version: 1,
scheme: "exact",
network: accepts.network,
payload: Buffer.from(tx.serialize()).toString("base64"),
};
}Both the x402 client-settle path and the MPP client-settle path are now verified end-to-end on Solana devnet against the Coinbase facilitator. The same exact envelope is what @axiom-stack/sdk builds for you under client.pay() — this adapter is for teams that need to own the signing path.
Where to next
- Payment Factory reference — protocol semantics, composition, .well-known schema.
- SDK reference —
client.pay()+client.discover()primitives, installation, typed exceptions. - Themra API — the canonical dogfood example. Same Payment Factory plumbing, hosted by Axiom.