The payment rail that cannot freeze your money.

Beanie helps apps, merchants, bots, and agents accept stablecoin payments across supported EVM, Solana, and Sui routes without building chain-specific payment operations from scratch.

Fixed 0.3% fee

Collected only after funds reach the destination.

Gasless payment moments

Beanie can sponsor eligible transfers so gas does not interrupt checkout.

No custodial freeze point

Users keep control of funds until they intentionally spend.

Stop rebuilding checkout per chain

Create one lane flow for Base, Ethereum, Solana, Sui, and future supported routes.

Turn gas into your incentive

Sponsor eligible transfers so customers finish payment instead of leaving to solve gas.

Instant notification

Update checkout, order, agent, or bot state the moment Beanie sees payment movement.

Your own mini indexer

Read balances and transaction history from the same merchant-scoped lane token.

Payment Flow

01 · receive

Create a payment lane

Under 3 seconds. No signup. No KYC. Spin up a dedicated address controlled entirely by your wallet.

02 · route

Let them pay where they are

Customer can pay from any supported chain. Gas stops being their problem. No wrapped tokens. No synthetic risk.

03 · settle

Money lands, your app moves

Funds land in your wallet. Beanie collects the fixed 0.3% only after arrival. Done.

What your app needs to store

merchant_id

Use it in balance, history, and indexing.

api_token

Bearer token for reads and WebSocket subscription. Use it with the same fingerprint that created the lane.

deposit_lane_address

Show this to the payer or use it in your payment instructions.

Your product context

Attach the lane to the customer, checkout, bot, or agentic flow you want to update.

Getting Started

Start with the path most products need first: give a payer a lane, keep your own product context attached, then update the customer experience when Beanie reports movement.

1. Create a merchant lane

curl -X POST https://api.your-beanie-host.com/api/v1/accounts/init \
  -H 'content-type: application/json' \
  -H 'x-context-fp: checkout-or-agent-session-id' \
  -d '{
    "chain_id": "BASE",
    "source_eoa": "0x1111111111111111111111111111111111111111",
    "destination_chain": "BASE",
    "destination_eoa": "0x2222222222222222222222222222222222222222"
  }'

Response

{
  "merchant_id": "mch_...",
  "api_token": "eyJ...",
  "deposit_lane_address": "0x...",
  "receiver_config_address": null,
  "deploy_nonce": 42,
  "fee_bps": 30,
  "qr_data": null,
  "status": "PENDING"
}

2. Store the token with its fingerprint

Store the returned token with the same context fingerprint used to create the lane. That pair lets your product answer the question that matters: what happened to this payment lane?

3. Subscribe to payment events

const ws = new WebSocket("wss://api.your-beanie-host.com/v1/streaming");

ws.addEventListener("open", () => {
  ws.send(JSON.stringify({
    action: "subscribe",
    api_token: apiToken,
    context_fp: contextFingerprint
  }));
});

ws.addEventListener("message", (message) => {
  const event = JSON.parse(message.data);
  console.log(event.event, event.data);
});

API Reference

These endpoints are the small surface area your product needs to create lanes, remove gas friction, verify payment state, and react to events across supported chains.

Method Path Use it for Auth
POST /api/v1/accounts/init Create or retrieve a merchant deposit lane. Public, abuse-protected.
GET /api/v1/accounts/{merchant_id}/balance Read merchant balance state. Bearer token.
GET /api/v1/accounts/{merchant_id}/transactions Read merchant transaction history. Bearer token.
GET /api/v1/relay/quote Discover Solana sponsored relay sentinel keys and quote TTL. Public, abuse-protected.
POST /api/v1/relay/solana/prepare Prepare a Solana sponsored transfer transaction for user signature. Public, rate limited.
POST /api/v1/relay/authorize Queue a signed EVM TWA, Solana CO-SIGN, or Sui sponsored authorization. Public, rate limited.
WS /v1/streaming Subscribe to merchant payment and relay events. First frame includes API token.

Relay methods

Sponsored relay turns gas into a product decision: your app can pay the network cost for eligible transfers while Beanie records the authorization and final result.

Method Chain family What your user signs What Beanie queues
TWA EVM EIP-3009 style transfer authorization. Factory sponsored transfer.
CO-SIGN Solana Prepared sponsored transfer transaction. Sentinel co-sign.
SUI-SPONSORED Sui Signed transaction bytes and wallet signatures. Sponsored PTB submission.

Test the API

Try the exact calls your integration will use. Pick the endpoint, fill only the fields that matter for that call, and send it to your local, sandbox, or deployed Beanie API.

Request builder

Response

Select an endpoint and send a request.

Usage Examples

These examples are written for the real jobs your product needs to do: create a lane, read state, receive notifications, and sponsor a transfer when gas would interrupt payment.

Create a payment lane

Create a lane when a merchant, bot, customer session, or autonomous job needs an address that Beanie can track.

JavaScript
const baseUrl = "https://api.your-beanie-host.com";

async function createLane({
  sourceChain,
  destinationChain,
  ownerAddress,
  settlementAddress
}) {
  const contextFingerprint = crypto.randomUUID();
  const response = await fetch(`${baseUrl}/api/v1/accounts/init`, {
    method: "POST",
    headers: {
      "content-type": "application/json",
      "x-context-fp": contextFingerprint
    },
    body: JSON.stringify({
      chain_id: sourceChain,
      destination_chain: destinationChain,
      owner_address: ownerAddress,
      source_eoa: ownerAddress,
      destination_eoa: settlementAddress,
      dst_recipient: settlementAddress
    })
  });

  const payload = await response.json();
  if (!response.ok) throw new Error(payload.error || "Lane creation failed");

  // Store merchant_id, api_token, and contextFingerprint together.
  return { ...payload, contextFingerprint };
}
cURL
curl -X POST https://api.your-beanie-host.com/api/v1/accounts/init \
  -H 'content-type: application/json' \
  -H 'x-context-fp: checkout-or-agent-session-id' \
  -d '{
    "chain_id": "BASE",
    "destination_chain": "BASE",
    "owner_address": "0x1111111111111111111111111111111111111111",
    "source_eoa": "0x1111111111111111111111111111111111111111",
    "destination_eoa": "0x2222222222222222222222222222222222222222",
    "dst_recipient": "0x2222222222222222222222222222222222222222"
  }'

Read balance and history

Use the token returned by lane creation to read merchant state. Most products call this from their backend or protected dashboard.

JavaScript
async function readMerchantState({ merchantId, apiToken, contextFingerprint, chainId = "BASE" }) {
  const headers = {
    authorization: `Bearer ${apiToken}`,
    "x-context-fp": contextFingerprint
  };
  const historyQuery = `chain_id=${encodeURIComponent(chainId)}&limit=30&offset=0`;

  const [balanceResponse, historyResponse] = await Promise.all([
    fetch(`${baseUrl}/api/v1/accounts/${merchantId}/balance?chain_id=${chainId}`, { headers }),
    fetch(`${baseUrl}/api/v1/accounts/${merchantId}/transactions?${historyQuery}`, { headers })
  ]);

  if (!balanceResponse.ok) throw new Error("Balance unavailable");
  if (!historyResponse.ok) throw new Error("History unavailable");

  return {
    balance: await balanceResponse.json(),
    transactions: await historyResponse.json()
  };
}
cURL
curl 'https://api.your-beanie-host.com/api/v1/accounts/mch_example/transactions?chain_id=BASE&limit=30&offset=0' \
  -H "authorization: Bearer $BEANIE_API_TOKEN" \
  -H "x-context-fp: $BEANIE_CONTEXT_FP"

Subscribe to notifications

Use the WebSocket stream to keep checkout screens, merchant dashboards, bots, and agents synchronized without polling.

JavaScript
const socket = new WebSocket("wss://api.your-beanie-host.com/v1/streaming");

socket.addEventListener("open", () => {
  socket.send(JSON.stringify({
    action: "subscribe",
    api_token: apiToken,
    context_fp: contextFingerprint
  }));
});

socket.addEventListener("message", (message) => {
  const payload = JSON.parse(message.data);

  if (payload.event === "deposit_detected") {
    markOrderPending(payload.data);
  }

  if (payload.event === "sweep_completed" || payload.event === "relay_completed") {
    markOrderPaid(payload.data);
  }

  if (payload.event === "relay_failed") {
    showRetry(payload.data);
  }
});

Solana sponsored transfer

Ask Beanie to prepare the transaction, let the wallet sign it, then queue the signed authorization. The final result arrives through history reads and streaming events.

JavaScript
async function sponsorSolanaTransfer({
  merchantId,
  fromAddress,
  toAddress,
  value,
  provider
}) {
  const preparedResponse = await fetch(`${baseUrl}/api/v1/relay/solana/prepare`, {
    method: "POST",
    headers: { "content-type": "application/json" },
    body: JSON.stringify({
      merchant_id: merchantId,
      chain_id: "SOLANA-MAIN",
      direction: "outbound",
      from_address: fromAddress,
      to_address: toAddress,
      value
    })
  });
  const prepared = await preparedResponse.json();
  if (!preparedResponse.ok) throw new Error(prepared.error || "Solana relay unavailable");

  const transaction = solanaWeb3.Transaction.from(
    Uint8Array.from(atob(prepared.base64_transaction), (char) => char.charCodeAt(0))
  );
  const signed = await provider.signTransaction(transaction);
  const signedBytes = signed.serialize({
    requireAllSignatures: false,
    verifySignatures: false
  });

  return fetch(`${baseUrl}/api/v1/relay/authorize`, {
    method: "POST",
    headers: { "content-type": "application/json" },
    body: JSON.stringify({
      relay_method: prepared.relay_method || "CO-SIGN",
      merchant_id: merchantId,
      chain_id: prepared.chain_id || "SOLANA-MAIN",
      from_address: prepared.from_address,
      to_address: prepared.to_address,
      value: prepared.value,
      nonce: prepared.nonce,
      base64_transaction: btoa(String.fromCharCode(...signedBytes))
    })
  });
}
cURL
curl -X POST https://api.your-beanie-host.com/api/v1/relay/solana/prepare \
  -H 'content-type: application/json' \
  -d '{
    "merchant_id": "mch_example",
    "chain_id": "SOLANA-MAIN",
    "direction": "outbound",
    "from_address": "11111111111111111111111111111111",
    "to_address": "11111111111111111111111111111111",
    "value": "1000000"
  }'

EVM gasless transfer

For EVM chains, the user signs typed data. Beanie receives the signature parts and queues the relay.

JavaScript
async function authorizeEvmTransfer({
  merchantId,
  fromAddress,
  toAddress,
  value,
  chainId,
  usdcAddress,
  ethereum
}) {
  const validAfter = Math.floor(Date.now() / 1000);
  const validBefore = validAfter + 300;
  const nonce = crypto.getRandomValues(new Uint8Array(32));
  const hexNonce = `0x${[...nonce].map((byte) => byte.toString(16).padStart(2, "0")).join("")}`;

  const typedData = {
    types: {
      EIP712Domain: [
        { name: "name", type: "string" },
        { name: "version", type: "string" },
        { name: "chainId", type: "uint256" },
        { name: "verifyingContract", type: "address" }
      ],
      TransferWithAuthorization: [
        { name: "from", type: "address" },
        { name: "to", type: "address" },
        { name: "value", type: "uint256" },
        { name: "validAfter", type: "uint256" },
        { name: "validBefore", type: "uint256" },
        { name: "nonce", type: "bytes32" }
      ]
    },
    primaryType: "TransferWithAuthorization",
    domain: {
      name: "USD Coin",
      version: "2",
      chainId,
      verifyingContract: usdcAddress
    },
    message: {
      from: fromAddress,
      to: toAddress,
      value,
      validAfter,
      validBefore,
      nonce: hexNonce
    }
  };

  const signature = await ethereum.request({
    method: "eth_signTypedData_v4",
    params: [fromAddress, JSON.stringify(typedData)]
  });
  const { v, r, s } = splitEvmSignature(signature);

  return fetch(`${baseUrl}/api/v1/relay/authorize`, {
    method: "POST",
    headers: { "content-type": "application/json" },
    body: JSON.stringify({
      relay_method: "TWA",
      merchant_id: merchantId,
      chain_id: "BASE",
      from_address: fromAddress,
      to_address: toAddress,
      value,
      valid_after: validAfter,
      valid_before: validBefore,
      nonce: hexNonce,
      v,
      r,
      s
    })
  });
}
cURL
curl -X POST https://api.your-beanie-host.com/api/v1/relay/authorize \
  -H 'content-type: application/json' \
  -d '{
    "relay_method": "TWA",
    "merchant_id": "mch_example",
    "chain_id": "BASE",
    "from_address": "0x1111111111111111111111111111111111111111",
    "to_address": "0x2222222222222222222222222222222222222222",
    "value": "10.000000",
    "valid_after": 1710000000,
    "valid_before": 1710000300,
    "nonce": "0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
    "v": 27,
    "r": "0xbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
    "s": "0xcccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc"
  }'

Sui sponsored transfer

For Sui, the wallet builds and signs the PTB, then Beanie submits the signed bytes through the sponsored relay path.

JavaScript
async function authorizeSuiTransfer({
  merchantId,
  fromAddress,
  toAddress,
  value,
  nonce,
  txBytes,
  signatures
}) {
  const response = await fetch(`${baseUrl}/api/v1/relay/authorize`, {
    method: "POST",
    headers: { "content-type": "application/json" },
    body: JSON.stringify({
      relay_method: "SUI-SPONSORED",
      merchant_id: merchantId,
      chain_id: "SUI-MAIN",
      from_address: fromAddress,
      to_address: toAddress,
      value,
      nonce,
      tx_bytes: txBytes,
      signatures
    })
  });
  const payload = await response.json();
  if (!response.ok) throw new Error(payload.error || "Sui relay unavailable");
  return payload;
}
cURL
curl -X POST https://api.your-beanie-host.com/api/v1/relay/authorize \
  -H 'content-type: application/json' \
  -d '{
    "relay_method": "SUI-SPONSORED",
    "merchant_id": "mch_example",
    "chain_id": "SUI-MAIN",
    "from_address": "0x1111111111111111111111111111111111111111111111111111111111111111",
    "to_address": "0x2222222222222222222222222222222222222222222222222222222222222222",
    "value": "10.000000",
    "nonce": "0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
    "tx_bytes": "AA==",
    "signatures": ["AA=="]
  }'

Realtime Events

Use streaming events when polling would make the product feel late. Beanie pushes merchant-scoped payment and relay updates so your UI, bots, and backend jobs can move with the payment.

Subscribe frame

{
  "action": "subscribe",
  "api_token": "eyJ...",
  "context_fp": "checkout-or-agent-session-id"
}

Event envelope

{
  "event": "relay_completed",
  "data": {
    "chain_id": "BASE",
    "relay_tx_hash": "0xabc...",
    "value": "10.000000",
    "status": "CONFIRMED"
  },
  "merchant_id": "mch_example"
}
Event Meaning Product use
deposit_detected Beanie detected chain evidence for a deposit. Show pending or confirming state.
sweep_completed Funds reached a settled or fallback-routed state. Mark checkout/order as paid according to your policy.
sweep_failed A compliance hold or terminal sweep issue became visible. Pause fulfillment and surface support flow.
relay_completed Sponsored relay confirmed with a relay transaction hash. Show transfer complete.
relay_failed Sponsored relay reached terminal failure. Ask user to retry or contact support.

Contracts & Addresses

Use these onchain addresses to verify token, program, and relay assumptions across supported chains before moving value through a Beanie integration.

Public token and program addresses

Network Address Use Verify
Ethereum 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48 USDC token contract. Etherscan
Base 0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913 USDC token contract. Basescan
Solana EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v USDC mint. Solana Explorer
Solana TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA SPL Token program. Solana Explorer
Solana ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL Associated Token Account program. Solana Explorer
Solana CCTPV2Sm4AdWt5296sk4P66VBZ7bEhcARwFaaS9YPbeC Circle CCTP V2 Message Transmitter program. Solana Explorer
Solana CCTPV2vPZJS2u2BBsUoscuikbYjnpFmbFsvVuJdgUMQe Circle CCTP V2 Token Messenger Minter program. Solana Explorer

Beanie lane addresses

Value Where it comes from How to verify
deposit_lane_address Returned by POST /api/v1/accounts/init. Open it in the chain explorer for the lane chain.
receiver_config_address Returned by account init when the chain uses a separate config account or shared object configuration. Inspect it on the matching chain explorer.
sentinel_public_keys Returned by GET /api/v1/relay/quote for sponsored Solana flows. Compare the signer in the prepared transaction with the quote response.
tx_bytes and signatures Built and signed by the wallet for SUI-SPONSORED relay. Verify the transaction block and sender in a Sui explorer after relay completion.

Supported Chains

Beanie is built for multichain payment acceptance. Use canonical labels in production code and aliases only where your deployment explicitly supports them.

Canonical label Family Supported product flows
ETH-MAIN EVM Receiver lanes, balance/transaction reads, TWA relay where configured.
BASE EVM Receiver lanes, balance/transaction reads, TWA relay where configured.
SOLANA-MAIN Solana Receiver lanes, balance/transaction reads, CO-SIGN sponsored relay where configured.
SUI-MAIN Sui Receiver lanes, balance/transaction reads, SUI-SPONSORED relay where configured.

Chain aliases

ETH ETHEREUM ETH-MAIN BASE SOL SOLANA SOLANA-MAIN SUI SUI-MAIN

FAQ

What should I use Beanie for?

Use Beanie when your product needs to accept stablecoin payments, create reusable payment lanes, sponsor eligible transfers, read payment history, and receive instant payment notifications through HTTP and WebSocket API.

Does Beanie custody user funds?

No. Users control their assets until they spend. Beanie coordinates lanes, indexing, relay intake, and notifications without turning your checkout into a custodial wallet flow.

Can one integration support multiple chains?

Yes. Beanie is built for multichain payment acceptance across supported EVM, Solana, and Sui routes, so your product can use one payment pattern instead of rebuilding checkout per chain.

How do fees work?

Beanie keeps pricing simple: the fee is a fixed 0.3%, and it is collected only after funds reach the destination. Eligible relay paths can also support gas sponsorship.

What does gasless mean for my product?

For eligible relay flows, your product can sponsor the network action so users do not have to pause checkout to solve gas. Treat it as a conversion tool: the payer signs, Beanie handles relay intake, and your product receives status updates.

When should I fulfill an order?

Fulfill when Beanie sends the completion signal for the flow you use. For lane deposits, sweep_completed means settlement reached your wallet. For sponsored transfers, relay_completed means the relay confirmed with a transaction hash. Use transaction history as your audit trail.

Should I call Beanie from my frontend or backend?

Use the frontend for wallet connection, lane creation, deposit display, signatures, and realtime status. Use your backend for durable order records, fulfillment actions, and any workflow where you do not want the browser to hold the lane token. Beanie tokens are merchant-scoped and expiring, while request fingerprints and rate limits reduce replay and abuse.

Does a relay response mean the payment is final?

No. A successful relay request means Beanie accepted the authorization for processing. Use realtime notifications or transaction history to know when the payment is confirmed, settled, failed, or needs attention.