---
title: codespar_crypto_pay
description: Crypto-rail payments — stablecoin checkout on Coinbase Commerce, BR rails on Bitso and Foxbit, and cross-border payout via our on/offramp partner.
---

import { Callout } from "fumadocs-ui/components/callout";

# codespar_crypto_pay

<Callout title="Meta-tool" type="info">
**Buy-side.** Your agent is the spender: money leaves the wallet/account your agent governs, under a signed mandate.

`codespar_crypto_pay` is the crypto-rail meta-tool. Use it when the buyer or recipient settles in stablecoin or another crypto asset rather than fiat — typical for stablecoin checkout, BR fiat-onramp via crypto, and cross-border B2B payouts.
</Callout>

There is no typed wrapper yet — call via `session.execute()`.

<Callout title="Testnet status" type="warn">
Crypto settlement runs on testnets today (e.g. Base Sepolia for USDC); mainnet is gated behind production keys.
</Callout>

## Rails

| Rail | Currency | Country | Provider | Direction | Notes |
|---|---|---|---|---|---|
| `stablecoin` | USDC | INTL | Coinbase Commerce | receive | Default for inbound. Returns hosted payment URL |
| `stablecoin` | USDC | BR | Bitso | send | `/withdrawals`. Outbound only |
| `stablecoin` | USDT | BR | Foxbit | send / receive | `/orders`. Market or limit on `usdtbrl` |
| `stablecoin-checkout` | USDC | INTL | Coinbase Commerce | receive | Reusable hosted checkout (vs one-shot `/charges`) |
| `stablecoin-payout` | USDC | INTL | On/offramp partner | send | USDC wallet → external address (web3 recipient) |
| `onramp` | USDC | INTL | On/offramp partner | receive | **Fiat → USDC** (Pix BRL / wire USD / SEPA EUR). Returns QR / wire instructions |
| `offramp` | USDC | INTL | On/offramp partner | send | **USDC → fiat** on a pre-registered bank account (Pix / wire / SEPA) |

Coinbase Commerce returns a hosted URL the agent surfaces to the buyer. Bitso and the on/offramp partner are outbound rails: the agent stamps a counterparty address and the provider executes a transfer. Foxbit hits the order book — operators chain `create_pix_deposit` / `create_crypto_withdrawal` separately for full ramp loops.

## Direct execute

```ts
// Receive (Coinbase Commerce hosted checkout) — counterparty omitted
const charge = await session.execute("codespar_crypto_pay", {
  amount: 49.9,
  currency: "USDC",
  direction: "receive",
  metadata: { order_id: "1234" },
});
console.log(charge.hosted_url, charge.id);

// Send (cross-border payout, USDC → external address)
const payout = await session.execute("codespar_crypto_pay", {
  rail: "stablecoin-payout",
  amount: 100,
  currency: "USDC",
  direction: "send",
  counterparty: {
    address: "0xRecipientWalletAddress...",
    country: "MX",
  },
  metadata: {
    // Optional override of the operator's default source wallet
    source_wallet_id: "wallet_abc123",
  },
});
console.log(payout.id, payout.status);
```

## Args shape

| Field | Type | Required | Description |
|---|---|---|---|
| `amount` | `number` | Yes | Amount in target currency major unit (decimal) |
| `currency` | `string` | Yes | `USDC`, `USDT`, `BTC`, `ETH`, `MATIC` |
| `direction` | `string` | Yes | `send` (outbound) or `receive` (inbound) |
| `counterparty` | `object` | For send | Recipient envelope. Required when `direction: "send"`. For `receive` flows the buyer is anonymous until they hit the hosted URL, so this field can be omitted. |
| `counterparty.country` | `string` | For send | ISO 3166-1 alpha-2 country code of the recipient (e.g. `"US"`, `"BR"`, `"MX"`). Required when `direction: "send"` — powers cross-border tracking and audit. |
| `counterparty.address` | `string` | For send | Destination wallet address (outbound transfers) |
| `rail` | `string` | No | Override rail selection. Defaults to `stablecoin`. Pass `stablecoin-payout` to land on the on/offramp partner; `stablecoin-checkout` for Coinbase reusable checkout |
| `network` | `string` | No | Blockchain network (`ethereum`, `polygon`, `base`, `solana`, `bitcoin`) |
| `metadata` | `object` | No | Provider-specific overrides (e.g. `source_wallet_id`, `network`, `destination_tag`) |

<Callout title="counterparty.country is required for direction: send" type="warn">
Send-direction calls (Bitso withdrawal, stablecoin payout, offramp) must include `counterparty.country` (ISO 3166-1 alpha-2). The platform uses it to track cross-border flows end-to-end — recipient country lands in the audit log and is propagated to provider request metadata when the rail supports it. Receive-direction calls (Coinbase Commerce charge, onramp) may omit it — the buyer is anonymous until they hit the hosted URL. Missing the field on a send call surfaces as a validation error before the call is dispatched.
</Callout>

## Result shape

```ts
type CryptoPayResult = {
  id: string;                    // Provider-side identifier (charge id, withdrawal id, transfer id)
  status: string;                // 'PENDING' | 'COMPLETED' | 'NEW' (uppercased for cross-provider parity)
  amount: number;
  currency: string;
  network?: string;
  direction: string;
  hosted_url?: string | null;    // Coinbase Commerce hosted URL (receive flows)
  addresses?: Record<string, string>;  // Per-asset deposit addresses (Coinbase Commerce)
  raw?: unknown;                 // Full provider response for reconciliation
};
```

## Operator setup

- **Coinbase Commerce** — `api_key` auth with the `X-CC-Api-Key` header. Optional shared-secret for webhook verification.
- **Bitso** — `hmac_signed` auth. Operator stamps API key + API secret; runtime signs each request with HMAC-SHA256 over `nonce + method + path + body`.
- **Foxbit** — `hmac_signed` auth (same pattern as Bitso). Operator stamps API key + secret.
- **On/offramp partner** — `api_key` auth with raw `Authorization: <api_key>` header (no Bearer prefix). Operator pre-funds a USDC wallet via onramp or external deposit; the wallet id is stored in the connection metadata and the runtime injects it as `sourceWalletId` automatically.

## Cross-border flows (onramp / offramp / payout)

Our BRL↔USDC on/offramp partner ships three rails covering the cross-border lifecycle end to end. Pick the rail by what side of the conversion the operator is on:

- **`onramp`** — fiat enters the platform: a buyer sends Pix BRL / US wire / EUR SEPA, the operator's USDC wallet receives the stablecoin leg.
- **`offramp`** — fiat leaves the platform: the operator sends USDC, the recipient receives Pix BRL / US wire / EUR SEPA on a pre-registered bank account.
- **`stablecoin-payout`** — USDC stays on-chain: the operator sends USDC directly to a web3 wallet address (no fiat conversion).

### Onramp — fiat to USDC

```ts
const onramp = await session.execute("codespar_crypto_pay", {
  rail: "onramp",
  amount: 6480,              // BRL the payer will Pix
  currency: "USDC",          // stablecoin received
  direction: "receive",
  counterparty: {
    country: "BR",           // origin country of the fiat
  },
  metadata: {
    fiat_currency: "BRL",    // required — selects the fiat side
  },
});
// onramp.hosted_url → Pix QR code the agent surfaces to the payer
// onramp.status → 'AWAITING_DEPOSIT' (poll via paymentStatus)
```

### Offramp — USDC to fiat

```ts
const offramp = await session.execute("codespar_crypto_pay", {
  rail: "offramp",
  amount: 1200,              // USD the recipient receives
  currency: "USDC",          // stablecoin sent
  direction: "send",
  counterparty: {
    country: "US",
    bank_account_id: "ext_merchant_us",  // pre-registered via add_bank_account
  },
  metadata: {
    fiat_currency: "USD",
  },
});
// offramp.id → partner-side transaction id
// offramp.status → 'PROCESSING' (poll via paymentStatus until 'COMPLETED')
```

### Stablecoin payout — USDC to external wallet

```ts
const payout = await session.execute("codespar_crypto_pay", {
  rail: "stablecoin-payout",
  amount: 250,
  currency: "USDC",
  direction: "send",
  counterparty: {
    address: "0xSupplierWallet...",
    country: "US",
  },
});
```

The recipient country is mandatory across all three rails and is propagated to the request metadata so downstream tools (compliance, FX-aware reporting, audit) can identify cross-border flows without re-querying the meta-tool args.

### Cross-border purchase (compra) — BR buyer → US merchant

The agent chains onramp + offramp in a single intent:

```ts
// Step 1 — buyer sends Pix, operator receives USDC
const buyer_in = await session.execute("codespar_crypto_pay", {
  rail: "onramp", amount: 6480, currency: "USDC", direction: "receive",
  counterparty: { country: "BR" },
  metadata: { fiat_currency: "BRL" },
});

// Step 2 — operator sends USDC, US merchant receives USD wire
const merchant_out = await session.execute("codespar_crypto_pay", {
  rail: "offramp", amount: 1200, currency: "USDC", direction: "send",
  counterparty: { country: "US", bank_account_id: "ext_merchant_us" },
  metadata: { fiat_currency: "USD" },
});
```

No card flag, no IOF, no SWIFT — Pix → USDC → US wire in one chained flow (running on testnets today, see the note at the top).

## Async settlement

Crypto rails settle on-chain; latency varies by chain (seconds on Polygon/Arbitrum, minutes on Bitcoin). The flow mirrors `codespar_charge`:

1. `codespar_crypto_pay` returns the `id`, `status: "PENDING"`, and (for receive flows) the `hosted_url`.
2. Buyer pays on the hosted page or the on-chain transfer executes.
3. Provider webhook lands — backend correlates by `idempotency_key` ↔ provider transaction id.
4. `session.paymentStatus(id)` returns `succeeded` (or `expired` if abandoned, `failed` on chain error).

See [async settlement](/docs/concepts/async-settlement).

## See also

- [codespar_charge](/docs/concepts/meta-tools/charge) — fiat counterpart
- [hmac_signed auth](/docs/concepts/hmac-signed-auth) — Bitso + Foxbit authentication pattern
- [Crypto Pay Agent cookbook](/docs/cookbooks/crypto-pay-agent) — end-to-end stablecoin example
- [Tools & meta-tools](/docs/concepts/tools) — full meta-tool list
