Axiom Stack

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.