Documentation
Quickstart
Go from zero to your first card payment in under 5 minutes.
Prerequisites
- ✓Node.js 18+ installed
- ✓A Arispay account — sign up free
- ✓An API key from the dashboard → API Keys
Install the SDK
TypeScript types are included out of the box. No additional @types package needed.
npm install payagent
Initialise the client
Create a .env file with your API key, then initialise the SDK. Test keys start with ap_test_, live keys with ap_live_.
ARISPAY_API_KEY=ap_test_your_key_here
import { DelegationClient } from "payagent";
const client = new DelegationClient({
developerApiKey: process.env.ARISPAY_API_KEY!,
// arispayUrl defaults to https://api.arispay.app
});"production" when you're ready to process real cards.Register an agent
launchAgent provisions a CDP-custodied wallet on Base mainnet with the spend limits you specify. No private keys in your process — Coinbase CDP signs, Arispay enforces policy.
import { launchAgent } from "payagent";
const agent = await launchAgent({
name: "BookingBot",
limits: { perTx: 5000, daily: 50000, monthly: 200000 }, // cents
});
console.log(agent.agentId); // "cm..."
console.log(agent.walletAddress); // 0x... (Base mainnet)
console.log(agent.status); // "pending_funding" | "active"Create an end user
End users are your customers whose cards will be charged. Pass your ownexternalId to map them back to your system.
const user = await client.createEndUser({
externalId: "user_jane_123",
email: "[email protected]",
});
console.log(user.id); // "cm..."
console.log(user.externalId); // "user_jane_123"Tokenize a card
Card tokenization is a two-step hosted flow. You never handle raw card numbers.
// Step 1: Get a hosted setup URL
const setup = await client.createCardSetupSession(user.id, {
returnUrl: "https://yourapp.com/card-added",
});
// Redirect end user to setup.setupUrl to enter their card
console.log(setup.setupUrl);
// Step 2: Poll until the session resolves (completed or failed).
// Fires the user.payment_method.attached webhook on success.
const status = await client.pollCardSetup(setup.sessionId);
console.log(status.state); // "completed" | "failed"
console.log(status.cardLast4); // "4242"sess_ ID and call the complete endpoint directly.Set spend limits
Control how much each agent can spend per user. All amounts are in cents. Optionally restrict by merchant category code (MCC).
await client.setUserLimits(user.id, agent.agentId, {
maxPerTx: 50000, // $500.00
maxDaily: 100000, // $1,000.00
maxMonthly: 500000, // $5,000.00
allowedMcc: ["5812", "5813"], // optional: restaurants only
});Make a payment
This is the main event. agent.pay() picks the right rail server-side — card, crypto, x402, MPP, or balance — based on the intent, enforces spend limits, and returns a unified PaymentResponse.
const payment = await agent.pay({
userId: user.id,
amount: 2999, // $29.99 in cents
merchantUrl: "https://restaurant.com",
merchantName: "Luigi's Pizza",
memo: "Table for 2, Friday 8pm",
idempotencyKey: "order_abc123", // optional — auto-generated if omitted
});
console.log(payment.status); // "succeeded" | "requires_action" | "failed"
console.log(payment.id); // "cm..."
console.log(payment.rail); // "card" | "crypto" | "x402" | "mpp" | "balance"agent.fetch(url) instead. pay() is for server-side settled transactions via /v1/payments. fetch() handles the 402 challenge + signing transparently.Listen for webhooks
Register a URL to receive real-time events. All payloads are signed with HMAC-SHA256. Verify using the X-ArisPay-Signature header. Registered via the REST API (no SDK helper yet).
const res = await fetch("https://api.arispay.app/v1/webhooks", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.ARISPAY_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
url: "https://yourapp.com/webhooks/arispay",
events: ["payment.succeeded", "payment.failed"],
}),
});
const webhook = await res.json();
// Save webhook.secret — use it to verify the HMAC signature
console.log(webhook.secret);Full example
Here's the complete flow in a single file you can copy and run.
import { launchAgent, DelegationClient } from "payagent";
const client = new DelegationClient({
developerApiKey: process.env.ARISPAY_API_KEY!,
});
// 1. Launch an agent (CDP wallet + spend limits)
const agent = await launchAgent({
name: "BookingBot",
limits: { perTx: 50000, daily: 100000, monthly: 500000 },
});
// 2. Create an end user
const user = await client.createEndUser({
externalId: "user_123",
email: "[email protected]",
});
// 3. Tokenize card (two-step hosted flow)
const setup = await client.createCardSetupSession(user.id, {
returnUrl: "https://yourapp.com/done",
});
// → redirect user to setup.setupUrl, then:
await client.pollCardSetup(setup.sessionId);
// 4. Set spend limits
await client.setUserLimits(user.id, agent.agentId, {
maxPerTx: 50000,
maxDaily: 100000,
maxMonthly: 500000,
});
// 5. Make a payment (rail picked server-side)
const payment = await agent.pay({
userId: user.id,
amount: 2999,
merchantUrl: "https://restaurant.com",
merchantName: "Luigi's Pizza",
memo: "Table for 2",
});
console.log(`Payment ${payment.status} on ${payment.rail}: $${(payment.amount / 100).toFixed(2)}`);API reference
The SDK wraps these REST endpoints. You can also call them directly with any HTTP client using Bearer token auth.
| Method | Endpoint | Description |
|---|---|---|
POST | /v1/agents | Register an agent (generates Ed25519 TAP keypair) |
GET | /v1/agents/:id | Get agent details |
POST | /v1/agents/:id/rotate-keys | Rotate TAP keypair |
POST | /v1/users | Create end user |
GET | /v1/users/:id | Get end user |
POST | /v1/users/:id/payment-methods | Start card tokenization (returns hosted URL) |
POST | /v1/users/:id/payment-methods/complete | Complete tokenization (store card token) |
PUT | /v1/users/:id/limits | Set spend limits per agent-user pair |
POST | /v1/payments | Create and process a payment |
GET | /v1/payments/:id | Get payment status |
GET | /v1/transactions | List payments (filter by user, agent, date) |
POST | /v1/webhooks | Register webhook |
GET | /v1/webhooks | List webhooks |
Key concepts
- Visa TAP (RFC 9421)
- Every payment is cryptographically signed with the agent's Ed25519 private key using HTTP Message Signatures. This proves to the card network that the payment was initiated by a known, registered agent.
- Amounts in cents
- All monetary values (payment amounts, spend limits) are integers in cents. $29.99 = 2999. This avoids floating-point rounding issues.
- Idempotency keys
- Pass a unique
idempotencyKeyon every payment. If the same key is sent twice, the second request returns the original payment instead of creating a duplicate. - Sandbox vs Production
- Sandbox uses a mock payment provider — no real money moves. Switch to production to process real card payments via Fiserv. The SDK, API, and dashboard work identically in both modes.
Ready to build?
Grab your API key and start processing sandbox payments in minutes.
