Skip to main content
ConceptsMeta-tools

codespar_crypto_pay

Crypto-rail payments — stablecoin checkout on Coinbase Commerce, BR rails on Bitso and Foxbit, and cross-border-payout via UnblockPay.

4 min read

codespar_crypto_pay

Meta-tool

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.

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

Rails

RailCurrencyCountryProviderDirectionNotes
stablecoinUSDCINTLCoinbase CommercereceiveDefault for inbound. Returns hosted payment URL
stablecoinUSDCBRBitsosend/withdrawals. Outbound only
stablecoinUSDTBRFoxbitsend / receive/orders. Market or limit on usdtbrl
stablecoin-checkoutUSDCINTLCoinbase CommercereceiveReusable hosted checkout (vs one-shot /charges)
stablecoin-payoutUSDCINTLUnblockPaysendUSDC wallet → external address (web3 recipient)
onrampUSDCINTLUnblockPayreceiveFiat → USDC (Pix BRL / wire USD / SEPA EUR). Returns QR / wire instructions
offrampUSDCINTLUnblockPaysendUSDC → fiat on a pre-registered bank account (Pix / wire / SEPA)

Coinbase Commerce returns a hosted URL the agent surfaces to the buyer. Bitso and UnblockPay 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

// 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 (UnblockPay 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

FieldTypeRequiredDescription
amountnumberYesAmount in target currency major unit (decimal)
currencystringYesUSDC, USDT, BTC, ETH, MATIC
directionstringYessend (outbound) or receive (inbound)
counterpartyobjectFor sendRecipient 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.countrystringFor sendISO 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.addressstringFor sendDestination wallet address (outbound transfers)
railstringNoOverride rail selection. Defaults to stablecoin. Pass stablecoin-payout to land on UnblockPay; stablecoin-checkout for Coinbase reusable checkout
networkstringNoBlockchain network (ethereum, polygon, base, solana, bitcoin)
metadataobjectNoProvider-specific overrides (e.g. source_wallet_id, network, destination_tag)

counterparty.country is required for direction: send

Send-direction calls (Bitso withdrawal, UnblockPay 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, UnblockPay 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.

Result shape

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 Commerceapi_key auth with the X-CC-Api-Key header. Optional shared-secret for webhook verification.
  • Bitsohmac_signed auth. Operator stamps API key + API secret; runtime signs each request with HMAC-SHA256 over nonce + method + path + body.
  • Foxbithmac_signed auth (same pattern as Bitso). Operator stamps API key + secret.
  • UnblockPayapi_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 with UnblockPay

UnblockPay 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

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

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 → UnblockPay transaction id
// offramp.status → 'PROCESSING' (poll via paymentStatus until 'COMPLETED')

Stablecoin payout — USDC to external wallet

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:

// 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 end to end in minutes.

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.

See also

codespar_crypto_pay | CodeSpar