Integration Guides
Quick Start
Get up and running with BillMyAgent in minutes. This guide walks you through creating your first payment. For a guided, language-switchable version see the Quickstart.
Step 1: Get Your API Key
First, you'll need to obtain an API key. Visit our Get API Key page for detailed instructions. This key authenticates all your API requests.
Step 2: Install the SDK
Choose the SDK for your framework or language:
Step 3: Initialize the SDK
To pay x402-gated APIs, build a client with a signer. On a server or agent, create one from a private key (it never leaves your process); in a browser, pass a viem wallet client backed by the user's wallet instead.
import { PaymentClient, createSigner } from '@billmyagent/payments-core'; // Server / agentconst signer = await createSigner('base', process.env.PRIVATE_KEY);const client = new PaymentClient({ signer });
Step 4: Pay an x402-gated API
client.http is an axios instance. Any HTTP 402 it hits is paid automatically (the SDK signs an EIP-3009 transferWithAuthorization and the facilitator settles it on-chain) and the request is retried β no manual handling.
const res = await client.http.get('https://api.example.com/paid-resource'); console.log(res.data, 'paid:', Boolean(res.headers['x-payment-response']));
Merchant REST API
To manage your own account (record payments, payout addresses, fees, invoices), pass an apiKey (and an authToken JWT for /merchant/*) and call the client methods directly:
const client = new PaymentClient({ apiKey: 'your-api-key', authToken: jwt }); await client.getPayoutSettings();await client.updatePayoutSettings({ base_address: '0xβ¦' });await client.listPayments();
React Integration
For React applications, use the provided PaymentButton component or the usePayment hook:
Using PaymentButton Component
import { PaymentButton, PaymentClient, createSigner } from '@billmyagent/payments-react'; // In a browser, build the signer from the user's wallet (e.g. window.ethereum).const client = new PaymentClient({ signer: await createSigner('base', PRIVATE_KEY) }); function App() { return ( <PaymentButton client={client} url="https://api.example.com/premium-article" onSuccess={(data) => console.log('unlocked', data)} onError={(error) => console.error('payment failed', error)} > Read article </PaymentButton> );}
Using the usePayment Hook
import { usePayment } from '@billmyagent/payments-react'; function PremiumContent({ client }) { const { pay, data, loading, error, paid } = usePayment(client); return ( <div> <button onClick={() => pay('https://api.example.com/premium')} disabled={loading}> {loading ? 'Loadingβ¦' : 'Load premium'} </button> {error && <p>Error: {error.message}</p>} {data && <p>Loaded{paid ? ' (paid)' : ''}</p>} </div> );}
Vue Integration
For Vue applications, use the PaymentButton component:
<template> <PaymentButton :client="client" url="https://api.example.com/premium-article" label="Read article" :onSuccess="handleSuccess" :onError="handleError" /></template> <script setup>import { PaymentButton, PaymentClient, createSigner } from '@billmyagent/payments-vue'; const client = new PaymentClient({ signer: await createSigner('base', PRIVATE_KEY) }); const handleSuccess = (data) => console.log('unlocked', data);const handleError = (error) => console.error('payment failed', error);</script>
How HTTP 402 Payment Required Is Handled
When an API endpoint requires payment, it returns HTTP 402 with the x402 payment requirements. A client built with a signer handles this automatically β there is no separate adapter to configure:
const client = new PaymentClient({ signer: await createSigner('base', process.env.PRIVATE_KEY),}); // When the API returns 402, client.http automatically:// 1. reads the x402 payment requirements (the `accepts` challenge)// 2. signs an EIP-3009 transferWithAuthorization with your wallet// 3. retries the request with the X-PAYMENT header// 4. the facilitator settles it on-chain const res = await client.http.get('https://api.example.com/premium');if (res.headers['x-payment-response']) { console.log('paid and unlocked:', res.data);}
Charge for Your API (Seller Side)
The SDKs above pay x402 paywalls. To charge β put your own endpoint behind a 402 β use the official x402 middleware. A request gets 402 Payment Required with machine-readable payment instructions until a valid payment is presented; the facilitator settles it and your payout address receives the funds directly (non-custodial). Runnable examples live in examples/seller-express and examples/seller-next.
Express
import express from 'express';import { paymentMiddleware } from 'x402-express'; const app = express(); // PAY_TO is your payout wallet (the same address you set in Payouts).app.use( paymentMiddleware(process.env.PAY_TO, { 'GET /premium': { price: '$0.01', network: 'base' }, })); app.get('/premium', (_req, res) => res.json({ unlocked: true }));app.listen(4021);
Next.js (App Router)
// middleware.tsimport { paymentMiddleware } from 'x402-next'; export const middleware = paymentMiddleware(process.env.PAY_TO, { '/premium': { price: '$0.01', network: 'base' },}); export const config = { matcher: ['/premium/:path*'] };
Networks are limited to those the facilitator can settle: base, base-sepolia (for testing), and polygon. Mainnet settlement requires a facilitator with CDP credentials; the public x402.org facilitator is testnet-only.
Payment Links / Hosted Checkout
When you want a buyer to pay without building any checkout UI, create a payment intent and share the hosted checkout_url it returns. The buyer opens the link, sees your merchant branding, connects a wallet, and pays USDC on-chain. Because BillMyAgent is strictly non-custodial, funds settle directly to your payout wallet β the platform never holds them. The 1% platform fee (0.5% at volume) is recorded and billed monthly out-of-band; you keep 100% on-chain. Links are single-use and expire (default 7 days, max 30). Settlement is on base and polygon (USDC), plus base-sepolia for testing; Ethereum is not currently supported for settlement.
Prerequisite: configure a payout address for the intent's network (Payouts page or PUT /merchant/payout-settings), or intent creation returns 422 no_payout_address.
Step 1: Create the intent and share the link
The SDK (v2.2.0) exposes createPaymentIntent, getPaymentIntent, listPaymentIntents, cancelPaymentIntent, and a getCheckoutUrl(id) helper. Python uses the snake_case equivalents plus checkout_url(id).
import { PaymentClient } from '@billmyagent/payments-core'; const client = new PaymentClient({ apiKey: process.env.BILLMYAGENT_API_KEY }); const intent = await client.createPaymentIntent({ amount: '25.00', // decimal string, [0.01, 1000000] network: 'base', // 'base' | 'base-sepolia' | 'polygon' currency: 'USDC', // optional, defaults to USDC description: 'Pro plan β March', expires_in_seconds: 604800, // optional; default 7 days, max 30 days}); // Share this hosted link with your buyer:console.log(intent.checkout_url); // or client.getCheckoutUrl(intent.id)
Step 2: Poll for settlement
The intent moves requires_payment β processing β settled. Poll getPaymentIntent (or listen for webhooks) until it is settled; watch for expired and canceled too.
async function waitForSettlement(id) { for (;;) { const intent = await client.getPaymentIntent(id); if (intent.status === 'settled') return intent; // funds are in your payout wallet if (intent.status === 'expired' || intent.status === 'canceled') { throw new Error(`intent ${intent.status}`); } await new Promise((r) => setTimeout(r, 5000)); }}
import timefrom billmyagent import PaymentClient client = PaymentClient(api_key=os.environ['BILLMYAGENT_API_KEY']) intent = client.create_payment_intent( amount='25.00', network='base', description='Pro plan β March')print(intent['checkout_url']) # or client.checkout_url(intent['id']) while True: current = client.get_payment_intent(intent['id']) if current['status'] == 'settled': break if current['status'] in ('expired', 'canceled'): raise RuntimeError(current['status']) time.sleep(5)
Refunds: payment links are non-refundable through the platform. If a buyer needs a refund, handle it directly (merchantβbuyer) off-platform. To stop an unpaid link early, call cancelPaymentIntent(id).
Webhook Integration
To receive payment events, set up a webhook endpoint in your application and register it with BillMyAgent. Webhooks will be sent for events like:
- Payment created
- Payment verified
- Payment completed
- Payment failed
- HTTP 402 responses (when payment is required)
Next Steps
Check out our Code Examples for more detailed implementation examples, or build requests interactively in the API Explorer.