What you can build with this

Four primitives cover almost everything: an invoice for a fixed amount, an address for an open one, a transfer between two BuxAPI wallets, and a send to anywhere else. The patterns below are those four arranged differently.

Choosing a primitive

What you needUseEndpointWhy
A customer pays a set amount, onceInvoicePOST /v1/invoicesLocks a per-token quote at creation, expires, and comes with a hosted checkout page.
A user tops up a balance whenever they likeAddressPOST /v1/addressesPermanent, accepts any amount, credits on confirmation. No invoice to create or expire.
Move money between two BuxAPI walletsTransferPOST /v1/transferA ledger move. Instant, free, no chain involved and no network fee.
Pay somebody outside BuxAPISendPOST /v1/sendBroadcasts on-chain from the hot wallet. Costs the network fee, no service fee on top.

Online store checkout

A cart total, one payment, a page the buyer is sent to and a webhook that tells you the order is paid.

  • Price in USD and let BuxAPI lock the token amounts. The buyer pays a fixed quantity of USDC even if the market moves while they are on the page; each locked quote is the USD amount plus that pair's estimated network fee, so the payer covers the sweep and you net the invoice amount minus only the 0.5% platform fee.
  • Pass your own order_id. It is unique per wallet, so creating the same invoice twice returns the first one instead of billing twice.
  • Take the result from the webhook, not from success_url. A buyer who closes the tab after paying never loads the success page.

Create the invoice

curl -X POST https://buxapi.com/v1/invoices \
  -H "authorization: Bearer $BUX_SEC" \
  -H 'content-type: application/json' \
  -d '{
    "amount": 4999,
    "currency": "usd",
    "accepted": ["base:usdc", "solana:usdc", "polygon:usdt"],
    "order_id": "order_10412",
    "success_url": "https://shop.example/thanks?order=10412",
    "cancel_url": "https://shop.example/cart",
    "metadata": { "cart_id": "c_88f1", "email": "buyer@example.com" }
  }'

What arrives when it is paid

POST https://shop.example/hooks/buxapi
X-Buxapi-Event: invoice.paid
X-Buxapi-Delivery: 90218
X-Buxapi-Signature: t=1786012800,v1=7d3a...

{
  "id": "inv_4kR2QpN7vXsB1mLdZaYc9F",
  "status": "paid",
  "currency": "usd",
  "amount": "4999",
  "received": { "base:usdc": "50010000" },
  "order_id": "order_10412",
  "metadata": { "cart_id": "c_88f1", "email": "buyer@example.com" },
  "deposit_id": 40219,
  "chain": "base",
  "token": "usdc",
  "tx_hash": "0x91c2..."
}

Already on WooCommerce, PrestaShop or OpenCart? The plugins do all of this for you, signature check included.

User account balances

Exchanges, trading apps, casinos and anything where a user funds an internal balance and spends it over time.

  • One address per user, allocated once and stored on their record. Deposit addresses are unlimited and cost nothing to hold.
  • One EVM address covers Base, Ethereum, Polygon and BNB Chain. Solana needs its own, derived from the same wallet.
  • Credit the user on deposit.confirmed, and use credited_amount rather than amount_raw: the network fee for the sweep and the 0.5% platform fee (taken on the amount after the network fee) are already out of it, and both appear on the deposit as network_fee_amount and fee_amount. Plain native ETH, BNB and SOL deposits carry no network fee.

Allocate the user an address, once

curl -X POST https://buxapi.com/v1/addresses \
  -H "authorization: Bearer $BUX_SEC" \
  -H 'content-type: application/json' \
  -d '{
    "family": "evm",
    "label": "user_88213",
    "callback_url": "https://app.example/hooks/deposits"
  }'

Response

{
  "family": "evm",
  "index": 41,
  "address": "0x7A1f...9cD2",
  "label": "user_88213",
  "callback_url": "https://app.example/hooks/deposits"
}

Credit them when it confirms

X-Buxapi-Event: deposit.confirmed

{
  "id": 40218,
  "chain": "base",
  "token": "usdc",
  "tx_hash": "0x91c2...",
  "amount_raw": "25000000",
  "credited_amount": "24855100",
  "credited_asset": "usdc",
  "fee_amount": "124900",
  "network_fee_amount": "20000",
  "address": "0x7A1f...9cD2",
  "invoice_id": null
}

Gaming and crypto casinos

A player funds a balance, plays against it, and withdraws what is left. The money moves twice and both directions have a way to go wrong.

  • One deposit address per player, allocated at signup and stored on their row, with the player id as the label. Credit on deposit.confirmed using credited_amount, so the balance you show is what you actually hold rather than what the chain said before fees.
  • Put the wallet in convert mode unless you want to run an FX book alongside the game. A house balance denominated in USD cents means a bet, a payout and a jackpot cap are all the same unit, and the exchange risk ends when the deposit lands rather than when someone remembers to sell.
  • Every withdrawal is a POST /v1/send with an idempotency_key derived from your own withdrawal row id. This is the single most important line on this page for an operator: a retry after a timeout is how a casino pays the same withdrawal twice, and the key is what makes the second call return the first result instead of sending again.
  • Tips between players, affiliate commission and rake settlement are transfers between BuxAPI wallets: instant, free and never broadcast. A site paying a few hundred affiliates a day touches a chain only when one of them withdraws.
  • Gambling is a regulated activity and a high-risk merchant category almost everywhere. Whether you may operate, and where, is your licensing question rather than a payments one, and taking crypto does not change the answer.

Marketplace and platform payouts

Money arrives for a seller, sits until it clears, then leaves to their own wallet.

  • Give each seller their own BuxAPI wallet. Settle to it with a transfer, which is instant, free and never touches a chain.
  • When the seller withdraws, POST /v1/send from their wallet. They pay the network fee, you pay nothing. A full withdrawal is amount "max", which resolves to the balance minus the network fee at debit time; GET /v1/send-fee quotes the fee, the balance and what "max" would resolve to before you commit.
  • Always pass an idempotency_key on a send. A retry after a timeout returns the original send instead of paying twice.

Settle to the seller's wallet, free and instant

curl -X POST https://buxapi.com/v1/transfer \
  -H "authorization: Bearer $BUX_SEC" \
  -H 'content-type: application/json' \
  -d '{
    "to": "bux_pub_7Yd4Qk9v2mTb8sXaLpR3ZnHc6JwEuFgKmQ2Ts9VbXe1Z",
    "asset": "usdc",
    "chain": "base",
    "amount": "50000000",
    "idempotency_key": "settle_2026_08_06_seller_312"
  }'

Subscriptions and recurring billing

Crypto has no card on file and nothing to charge on a schedule. Two shapes work.

  • Invoice per period: create one a few days before renewal with a long expires_in, and email the checkout_url. Simple, and the customer keeps control.
  • Prepaid balance: the customer funds an address, you debit their balance each period. No renewal step, and no failed payment at 3am.
  • The second is what most crypto-native products end up doing. It is the account-balance pattern above with a meter on top.

Bulk payouts

Affiliate commissions, creator revenue share, staff payroll, refunds.

  • One POST /v1/send per recipient, each with its own idempotency_key derived from the payout run and the recipient.
  • A re-run of the whole batch after a partial failure is safe: the sends that already went out return their original result and are not repeated.
  • Send on the cheapest chain the recipient accepts. The same USDC costs a fraction of a cent to move on Base and materially more on Ethereum; GET /v1/network-fees (public, no key needed) reports live per-pair fee estimates in USD cents, so cheapest is a lookup rather than folklore.

One send per recipient

curl -X POST https://buxapi.com/v1/send \
  -H "authorization: Bearer $BUX_SEC" \
  -H 'content-type: application/json' \
  -d '{
    "chain": "base",
    "token": "usdc",
    "to_address": "0x4B0e...81aF",
    "amount": "125000000",
    "idempotency_key": "payout_2026_08_seller_312"
  }'

Donations and tips

No amount to agree on and no checkout to expire.

  • Allocate one address per creator or campaign and show it as a QR code. It never expires, but a token tip smaller than about 1.2x the current network fee stays uncredited until gas drops far enough to sweep it profitably; GET /v1/network-fees publishes the live per-pair floor. Native ETH, BNB and SOL tips carry no network fee and only a small dust minimum.
  • Give each address its own callback_url and the webhook tells you which campaign was funded without a lookup.
  • Set the wallet to convert mode if you would rather see one USD figure than a column per token.

B2B invoicing

Larger amounts, longer to pay, a finance team on the other side.

  • Price in USD, set a long expires_in, and put your reference in order_id so reconciliation is a lookup rather than an amount match.
  • A partial payment lands as partially_paid with the running total in received. The invoice stays open until it expires.
  • metadata carries whatever your ledger needs, comes back on every webhook for that invoice, and is never shown to the payer.

Treasury in one currency

You want a balance, not a portfolio.

  • Set the wallet to convert mode. Every deposit is swapped to USDC on arrival and credited as USD cents.
  • The exchange risk ends at the deposit rather than lasting until you get around to selling.
  • Settlement mode can only change while the wallet is empty and nothing is in flight, so pick it when you create the wallet.

Two of these, running right now

We run two of these patterns ourselves. Our merch store is the convert-mode one, taking real crypto for real orders, and Bux Wallet is the raw-mode counterpart, where the user holds the coins they were sent. Between them they cover both settlement modes and most of this page.

See what we built: what each one does, how many calls it took, and a link to open it.

Verifying a webhook

Every pattern here ends with a webhook, and a webhook you do not verify is an endpoint anybody can call to mark an order paid. The signature is an HMAC-SHA256 over the timestamp and the raw body, keyed with the webhook secret from wallet creation.

import { createHmac, timingSafeEqual } from 'node:crypto'

// The raw body, before any JSON parsing. Re-serialising a parsed object
// changes the bytes and the signature will never match.
export const verify = (rawBody, header, secret) => {
  const parts = Object.fromEntries(
    header.split(',').map((kv) => kv.split('=').map((s) => s.trim()))
  )
  const expected = createHmac('sha256', secret)
    .update(`${parts.t}.${rawBody}`)
    .digest('hex')

  const a = Buffer.from(expected, 'hex')
  const b = Buffer.from(parts.v1 ?? '', 'hex')
  if (a.length !== b.length || !timingSafeEqual(a, b)) return false

  // Reject anything older than five minutes so a captured delivery cannot be
  // replayed later.
  return Math.abs(Date.now() / 1000 - Number(parts.t)) < 300
}

Deliveries are retried seven times over roughly 33 hours and can arrive more than once. X-Buxapi-Delivery is a stable id, so recording it and ignoring repeats is enough to make handling idempotent.

Not sure which shape fits

Describe what you are building and we will tell you which of these it is, or that it is none of them. Send us the details, or read the API reference and decide from the endpoints themselves.