---
title: Crypto Pay Agent
description: Generate a stablecoin payment URL via codespar_crypto_pay (Coinbase Commerce default), share with the user, watch for settlement webhook or paymentStatus.
---

<ActionBar githubPath="content/docs/cookbooks/crypto-pay-agent.mdx" markdownPath="/api/docs-md/cookbooks/crypto-pay-agent" />

<MetaStrip items={[
  { label: "TIME", value: "~10 min" },
  { label: "PROVIDER", value: (<><ServerChip name="OpenAI" accent /><span style={{ color: "var(--color-fd-muted-foreground)", fontSize: 12 }}>gpt-4o</span></>) },
  { label: "SERVERS", value: (<><ServerChip name="coinbase-commerce" /><ServerChip name="z-api" /></>) },
]} />

The simplest crypto-rail agent. The operator wants to accept stablecoin (USDC) for a B2B invoice. The agent calls `codespar_crypto_pay`, gets back a hosted Coinbase Commerce payment URL, shares it via WhatsApp, and waits for settlement.

<PixFlow
  steps={[
    { label: "Generate payment URL", tool: "codespar_crypto_pay", description: "Routed to Coinbase Commerce — returns hosted_url + tool_call_id", iconKey: "card" },
    { label: "Share with buyer", tool: "codespar_notify", description: "Routed to Z-API — WhatsApp message with the payment URL", iconKey: "send" },
    { label: "Wait for settlement", tool: "session.paymentStatusStream", description: "SSE stream until terminal — on-chain confirmation lands in seconds", iconKey: "search" },
  ]}
/>

## Prerequisites

```bash
npm install @codespar/sdk @codespar/openai openai
```

```bash title=".env"
CODESPAR_API_KEY=csk_live_...
OPENAI_API_KEY=sk-...
```

<Callout>
You need an active **Coinbase Commerce** account (default rail for stablecoin USD) and a **Z-API** connection for WhatsApp notification. Bitso is the BR fiat-onramp alternative — see Variations below.
</Callout>

## Full agent code

```typescript title="crypto-pay-agent.ts"
import { CodeSpar } from "@codespar/sdk";

const cs = new CodeSpar({ apiKey: process.env.CODESPAR_API_KEY });

async function cryptoInvoice(
  userId: string,
  amountUSD: number,
  buyer: { name: string; phone: string }
) {
  const session = await cs.create(userId, {
    servers: ["coinbase-commerce", "z-api"],
  });

  try {
    // 1. Generate a Coinbase Commerce hosted payment URL
    const charge = await session.execute("codespar_crypto_pay", {
      amount: amountUSD.toFixed(2),
      currency: "USDC",
      method: "stablecoin",
      metadata: { buyer_name: buyer.name },
    });

    console.log("Payment URL:", charge.payment_url);
    console.log("tool_call_id:", charge.tool_call_id);

    // 2. Share the payment URL with the buyer via WhatsApp
    await session.execute("codespar_notify", {
      recipient: buyer.phone,
      channel: "whatsapp",
      message:
        `Olá ${buyer.name}, sua fatura de ${amountUSD} USDC está pronta. ` +
        `Pague em qualquer rede suportada: ${charge.payment_url}`,
    });

    // 3. Wait for settlement
    let status = await session.paymentStatus(charge.tool_call_id);
    while (status.status === "pending") {
      await new Promise((r) => setTimeout(r, 5000));
      status = await session.paymentStatus(charge.tool_call_id);
    }

    if (status.status === "succeeded") {
      await session.execute("codespar_notify", {
        recipient: buyer.phone,
        channel: "whatsapp",
        message: `Recebido! Obrigado, ${buyer.name}.`,
      });
      return { ok: true, settled_at: status.settled_at };
    }

    return { ok: false, reason: status.status };
  } finally {
    await session.close();
  }
}
```

## Why crypto?

Two real reasons LATAM operators reach for the crypto rail:

1. **Cross-border B2B settlement** — a Brazilian SaaS billing a US customer wants USDC instead of paying Stripe's 4-6% on a card transaction. Coinbase Commerce hosts the payment page, the operator gets stablecoin, can hold or off-ramp later.
2. **Bitso fiat-onramp** — a Brazilian operator wants to accept BRL on the front end but settle internally in crypto for treasury reasons. Bitso bridges BRL ↔ crypto natively.

## Settlement model

Crypto settles on-chain, latency varies by chain:

| Chain | Typical settlement |
|---|---|
| USDC on Polygon / Arbitrum | seconds |
| USDC on Ethereum L1 | 1-5 minutes |
| BTC | 10-30 minutes (3 confirmations) |

Coinbase Commerce normalizes all of these — its webhook fires once the chain has reached the configured confirmation depth. CodeSpar's `paymentStatus` returns `pending` until that webhook lands.

For long settlement windows (BTC), prefer the streaming variant:

```typescript
await session.paymentStatusStream(charge.tool_call_id, {
  onUpdate: (s) => {
    if (s.status === "succeeded") releaseGoods();
  },
});
```

## Variations

### Bitso (BR fiat-onramp)

Swap the server to `bitso`. Bitso uses an `hmac_signed` auth pattern — see [hmac_signed auth](/docs/concepts/hmac-signed-auth) for the operator setup. The args shape is the same; pass `currency: "BRL"` and the buyer pays BRL while the operator's settlement lands in crypto.

### Outbound stablecoin payout

Pass `recipient.wallet_address` to send stablecoin OUT to a vendor wallet — the agent receives the on-chain transaction once broadcast. Useful for paying remote contractors in USDC.

### Webhook-triggered ship

After settlement, chain `codespar_ship` to generate a label automatically. The same pattern as the [Webhook Listener cookbook](/docs/cookbooks/webhook-listener), just with `codespar_crypto_pay` as the upstream.

## Next steps

<NextStepsGrid items={[
  { label: "CONCEPT", title: "codespar_crypto_pay", description: "Rails, args, result, operator setup details.", href: "/docs/concepts/meta-tools/crypto-pay" },
  { label: "CONCEPT", title: "hmac_signed auth", description: "Bitso auth pattern. Required for the BR fiat-onramp variant.", href: "/docs/concepts/hmac-signed-auth" },
  { label: "CONCEPT", title: "Async settlement", description: "Correlation chain + per-provider idempotency-key shapes.", href: "/docs/concepts/async-settlement" },
  { label: "COOKBOOK", title: "Webhook Listener", description: "Trigger downstream actions on settlement.", href: "/docs/cookbooks/webhook-listener" },
]} />
