Bitrefill Plugin
[!IMPORTANT] Complete Base MCP onboarding first (SKILL.md). Path 1 (connect→JWT) is the default for agent-commerce. Fall back to Path 2 (pay-per-call x402) for multi-wallet or stateless agents. Use Path 3 (CLI) or Path 4 (Bitrefill MCP) only when the user has an existing Bitrefill account. Keepbuy-productsout of Bitrefill MCPautoApprove.
Overview
Turn USDC on Base into everyday spending — inside the conversation. Bitrefill is the world’s largest crypto-native storefront for digital goods: gift cards (Amazon, Apple, Steam, Uber, and 1,500+ more), mobile refills in 180+ countries, and data eSIMs for travel. Pay with USDC on Base from your Base Account; codes and install links land in chat — often in seconds, sometimes within a few minutes (see Business domain). Why agents love it: one session can go from “I need a $25 Amazon US card” to a delivered PIN — search, pick a denomination, confirm, pay, poll, redeem — without leaving the thread. No Bitrefill signup on the default path: sign in once with your wallet, browse fee-free, pay only at checkout. Already on Bitrefill? Link an existing account via CLI or the Bitrefill MCP and shop your usual catalog the same way. Path selection, API routes, and Base MCP wiring: Detection · SubmissionDetection
Path 1 — Connect → JWT (default): one wallet sign-in → session token (~2 h); browse/create/status without micro-fees; pay at checkout only. Path 2 — Pay-per-call x402: no session; HTTP 402 + micro-fee on each gated call. Path 3 — CLI: existing Bitrefill account via@bitrefill/cli (shell).
Path 4 — Bitrefill MCP: existing account via https://api.bitrefill.com/mcp (OAuth, shell-less).
After Base MCP is available (SKILL.md), pick a path:
Agent-commerce (USDC on Base, no Bitrefill account):
- Base MCP
sign+web_request+ x402 payment tools available, agent can persist a JWT → Path 1. - Otherwise, or multi-wallet / no session persistence → Path 2.
- Cannot run SIWX helpers (no shell/Node for checksum + message build) → Path 2 only; tell the user connect is unavailable.
- Shell +
npx @bitrefill/cli@latest --help→ Path 3. - Bitrefill MCP tools exposed (
search-products,buy-products, …) → Path 4. - Neither → install per Path 4 setup below; stop if both fail.
https://www.bitrefill.com (403 from datacenters). Paths 1–2: Base MCP web_request to allowlisted api.bitrefill.com (custom-plugins.md). Paths 3–4: Bitrefill CLI or Bitrefill MCP.
Path 4 setup (Bitrefill MCP)
https://api.bitrefill.com/mcp — OAuth at connector setup.
-
Cursor:
.cursor/mcp.jsonor~/.cursor/mcp.json:buy-productsout ofautoApprove. -
Claude Code:
claude mcp add bitrefill --url https://api.bitrefill.com/mcp -
Reconnect/restart after install. MCP tools (verified):
search-products,get-product-details,buy-products,submit-prepayment-step,list-invoices,get-invoice-by-id,update-order.
Auth and SIWX
Path 1 connect uses SIWX → JWT. Path 2 needs no auth. Post-purchase redemption codes oninvoice/status require SIWX from the paying wallet (Path 1 JWT covers browse/status polling; if codes are missing, run SIWX for codes below). Path 3/4 use CLI/MCP OAuth.
EIP-55 checksum (required)
The address in the signed message and SIWX payload must be EIP-55 checksummed (mixed case). Lowercase addresses fromget_wallets cause the API to reject the signature and return another 402. Always run toChecksumAddress before building the message.
Base Account signatures are ERC-1271/6492 wrapped (~224 bytes). Pass the full signature unchanged; header type stays "eip191". Wallet reads and write approvals follow approval-mode.md.
SIWX timing
Challenge nonce expires in 5 minutes and is single-use. Fetch challenge → build message →sign → send header within that window. If connect returns 402 again, fetch a fresh challenge and repeat — do not reuse a stale nonce or signature.
Connect → JWT (Path 1)
web_requestPOST https://api.bitrefill.com/x402/connectwith body{}and headerContent-Type: application/json→ 402 whose JSON body includesextensions["sign-in-with-x"].info(domain, uri, version, nonce, issuedAt, expirationTime, statement, resources) andsupportedChains.get_wallets→ wallet address.- Pick Base:
{ chainId: "eip155:8453", type: "eip191" }fromsupportedChains. - Build EIP-4361 message with SIWX helpers below (
toChecksumAddress→buildSiweMessage). Theuriin the challenge for connect ishttps://api.bitrefill.com/x402/connect. signwithtype: "personal_sign",data: { message: <exact string> }→ followapproval-mode.md→signature.- Build decomposed payload (not
{ message, signature }), base64-encode →sign-in-with-xrequest header (see payload shape below). web_requestPOST https://api.bitrefill.com/x402/connectwith body{},Content-Type: application/json, and headersign-in-with-x: <base64>→ 200 with{ token, token_header: "X-Access-Token", expires_in }(default ~7200 s).- Store
tokenin memory only. AttachX-Access-Token: <token>(raw JWT, noBearer) on every subsequent gatedweb_request. Re-connect when expired.
SIWX for codes (after invoice/pay)
When invoice/status returns delivery complete but no redemption_info, or Path 2 without JWT:
web_requestGET https://api.bitrefill.com/x402/invoice/status?invoice_id=<uuid>→ 402 with SIWX challenge (save the full JSON body).- Build message from challenge
info—urimust match the challenged route (includes?invoice_id=). sign→ followapproval-mode.mdwithin 5 minutes.web_requestsame URL withsign-in-with-xheader → 200 withredemption_info.orders[].redemption_info(code,pin,extra_fields).- 403 → signing wallet is not the invoice payer. Sign with the wallet that paid.
my/orders and my/esims use the same SIWX flow (Path 1 JWT also works on these routes).
Decomposed SIWX payload
Base64 of this JSON (send assign-in-with-x header):
8453) inside the signed message but CAIP-2 (eip155:8453) in the payload.
SIWX message shape
SIWX helpers (no external libraries)
Verified againstsiwe@2.3.2 and @x402/extensions@2.3.0. Run in Node 18+ or any JS shell.
JavaScript:
node -e '…') or any harness with BigInt. Do not hand-type checksummed addresses. If no JavaScript runtime is available, use Path 2 (no connect SIWX) or obtain checksum/message from a one-line Node invocation before calling sign.
Business domain
Bitrefill API names do not match everyday ecommerce wording — map them when talking to users:| API term | Means | User-facing |
|---|---|---|
| invoice | Price-locked checkout (cart + total), not a billing document | ”your order” / “checkout” |
| order | One cart line item (one product/denomination) | “item” |
invoice/create → invoice/pay → backend async fulfillment of each order. Gift-card codes are often near-instant; some products take minutes. Poll invoice/status until delivery_status is all_delivered — do not treat payment confirmation as delivery.
If an item is still not fulfilled after 3 hours, or the user hits any service issue, point them to help.bitrefill.com.
Endpoints
Base URL:https://api.bitrefill.com (no /api prefix on x402 routes). Every gated response embeds next_step: { url, body } chaining search → detail → create → pay → status.
402 envelope: payment-required header is base64 JSON, mirrored into the JSON body.
| Method | Path | Cost | Auth (no JWT) |
|---|---|---|---|
GET | /x402/gift-cards/search?q=&country= | $0.002 | x402 |
GET | /x402/esims/search?q= | $0.002 | x402 |
GET | /x402/topups/search?q= | $0.002 | x402 |
GET | /x402/checkout/info | $0.001 | x402 |
GET | /x402/products/detail?slug= | $0.001 | x402 |
POST | /x402/invoice/create | $0.002 | x402 |
POST | /x402/invoice/pay | invoice amount | x402 (never JWT-waived) |
GET | /x402/invoice/status?invoice_id= | $0.001 or SIWX | x402 or SIWX |
POST | /x402/connect | free | SIWX → JWT |
GET | /x402/my/orders | free | SIWX or JWT |
GET | /x402/my/esims | free | SIWX or JWT |
X-Access-Token, the gate bypasses micro-fees and SIWX on all gated routes except /x402/connect (cannot mint with a token) and invoice/pay (invoice amount never waived).
Repeat reads: paying a route once grants that wallet fee-free access to the same path for 30 days. SIWX routes still need a signature per request when not using JWT.
Payment (Base USDC)
| Field | Value |
|---|---|
| Network (CAIP-2) | eip155:8453 |
| USDC | 0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913 |
| payTo | 0x480CD46E6faDe651a0437DeaddA53D5c8e7D846A |
package_value (critical)
Use the exact string from products/detail packages[].package_value — do not transform.
| Type | Format | Example |
|---|---|---|
| Gift cards | Bare integer string | "10", "50" |
| Top-ups | Bare integer string | "5", "20" |
| eSIMs | Descriptive label | "1GB, 7 Days", "Unlimited, 15 Days" |
package_value → HTTP 500 on invoice/create (no charge). Confirm no charge before retry (see Notes).
Request shapes
invoice/create — gift card:recipient_required: true on detail):
{ "invoice_id", "price_usdc", "price_usd", "expires_in_minutes", "next_step" }.
invoice/pay — { "invoice_id": "<uuid>" }. Success: { "success": true, "status": "payment_confirmed", "transaction", "next_step" }.
invoice/status — without SIWX/JWT: status fields only. With SIWX from payer or Path 1 JWT: adds redemption_info.orders[].redemption_info (code, pin, extra_fields).
Surface routing
| Capability | Path 1 | Path 2 | Path 3 | Path 4 |
|---|---|---|---|---|
| Connect / JWT | sign + web_request /connect | — | — | — |
| Search / browse | web_request + X-Access-Token | x402 pay per route | CLI | search-products |
| Product detail | web_request + token | x402 | CLI | get-product-details |
| Invoice create | web_request + token | x402 | CLI / MCP | buy-products |
| Pay invoice | Base MCP x402 tools | Same | x402 or send | Same |
| Poll status | web_request + token | x402 or token-less poll + SIWX for codes | CLI | get-invoice-by-id |
| Redemption codes | JWT or SIWX on invoice/status | SIWX from payer | CLI | get-invoice-by-id → orders[].redemption_info |
| Order history | web_request /my/orders + token | SIWX per request | CLI | list-invoices |
Claude show_widget
On claude.ai, render search/detail/invoice/status via the built-in show_widget tool — inline in chat, not Artifacts, not HTML in prose. Narrative stays in the message; only the visual goes in widget_code (title: snake_case).
Fragment order: <style> → HTML → <script>. No html/head/body. Host CSS vars only (var(--color-*)); no font-family; no shadows/gradients/blur/transition: all. Body ≥16px; interactive min-height: 44px.
One primary + one secondary CTA. Primary follows next_step (“See details for …” → “Buy … on …” → “Confirm and pay … USDC” → “Check delivery status”); wire it with sendPrompt(...). Secondary is lateral escape only. Selection: transparent 2px border + outline at rest; selected var(--color-border-info) + var(--color-background-info). Pre-select defaults so primary is actionable on first paint.
Orchestration
Path 1: Connect → browse → buy (default)
- Connect — SIWX flow above → store JWT and
expires_in. Do this once per session. - Confirm funds — when needed, check USDC on Base before pay.
- Search —
web_requestGET /x402/gift-cards/search?q=<term>&country=<ISO>withX-Access-Token. Takeslugfromproducts[]. (Oresims/search,topups/search.) - Detail —
web_requestGET /x402/products/detail?slug=<slug>+ token. Confirmin_stock,currency,packages[],recipient_required. - Create —
web_requestPOST /x402/invoice/create+ token with{ "items": [{ "product_id": "<slug>", "package_value": "<exact>" }] }(+refill_inputif top-up). Readinvoice_id,price_usd. - Confirm with user — show exact USDC total, product, denomination. Get explicit approval to pay.
- Pay — x402 on
POST https://api.bitrefill.com/x402/invoice/paywith{ invoice_id },maxPaymentjust aboveprice_usd→approval-mode.md→ complete x402 request. - Poll —
web_requestGET /x402/invoice/status?invoice_id=<id>+ token untildelivery_statusisall_delivered. - Codes — if
redemption_infomissing, run SIWX for codes with the paying wallet. Delivercode/pinsecurely (Risks & Warnings).
Path 2: Pay-per-call x402
- Confirm USDC on Base when needed.
- For each gated step:
web_request→ 402 → x402 pay that URL/method/body,maxPayment: "0.01"→approval-mode.md. - Follow
next_stepthrough detail → create → pay. - Invoice pay:
maxPaymentjust aboveprice_usd. - Poll status; SIWX for codes from paying wallet.
Path 3: CLI
login/verify) for list-orders. Create with --payment_method usdc_base.
Pay the Base invoice — once buy-products returns invoice_id, agent picks one (follow agent_instructions):
- x402 — pay
x402_payment_urlvia Base MCP x402 tools →approval-mode.md. - Direct send —
sendtopayment_infoaddress/amount onbase→approval-mode.md→ poll CLI/get-invoice-by-iduntil paid.
Path 4: MCP
Install + OAuth →search-products → get-product-details → user approves → buy-products with payment_method: "usdc_base" → pay → poll → redeem.
Pay the Base invoice — same as Path 3: x402 on x402_payment_url or send to payment_info. Poll get-invoice-by-id until invoice_status is payment_confirmed, then until invoice_status: complete / orders_delivery_status: all_delivered. Redemption: orders[].redemption_info.
Submission
Bitrefill uses Base MCP for reads, SIWX, x402, and direct USDC — notsend_calls. Read tool names and schemas from the MCP catalog (SKILL.md).
| Bitrefill step | Base MCP | Bitrefill-specific |
|---|---|---|
| Paths 1–2 API calls | web_request | Host api.bitrefill.com (allowlisted). Headers: X-Access-Token (raw JWT, not Authorization), sign-in-with-x, Content-Type. HTTP routing: custom-plugins.md |
| SIWX connect / codes | get_wallets, sign | Decomposed SIWX payload in sign-in-with-x header — see Auth. EIP-55 checksum required |
x402 micro-fees, invoice/pay, Path 3/4 x402_payment_url | x402 tools from MCP catalog | maxPayment: "0.01" for micro-fees; slightly above invoice price_usd for pay |
| Path 3/4 direct USDC | send | { chain: "base", asset: "USDC", recipient, amount } from payment_info |
approval-mode.md. On 402 responses, pay the Base USDC (eip155:8453) entry from accepts[].
Example prompts
$25 Amazon US — Path 1: Connect → JWT → search + token → detail → create → confirm → x402 pay → poll → deliver code. Browse, no session — Path 2: x402 micro-fee on each search/detail/create; SIWX for codes after pay. Existing account — Path 3/4: CLI or MCP catalog → Base USDC invoice → x402 orsend → poll → redeem.
Risks & Warnings
pii— Redemption codes, eSIM QR URLs, PINs are bearer credentials. Never log, commit, or paste in public channels. Return codes only when the user explicitly asks.irreversible— Digital goods are non-refundable once fulfilled. Confirm product, denomination, price, and payment before pay.- Invoice expiry — ~15 min price lock. Stale pay URL → create a new invoice.
- Connect token —
X-Access-Tokenis a bearer secret (~2 h). Never echo in chat. Re-connect when expired. - EIP-55 checksum — mandatory for every SIWX flow; use helpers above.
- CLI session —
~/.config/bitrefill-cli/<host>.v1.jsonis sensitive.
Notes
- Country codes: Alpha-2 uppercase (
US,IT). X-Access-Tokenheader only — Base MCP stripsAuthorization.- Fee schedule: search 0.001 · create 0.001.
- Connect JWT TTL: default 120 minutes.
- HTTP 500 on invoice/create — wrong
package_value; retry without paying until onchain history confirms no charge. - 402 after SIWX send — stale nonce, wrong checksum, or malformed payload; re-fetch challenge and re-sign within 5 minutes.
- 403 on SIWX route — wrong wallet; sign with the invoice payer.
INVOICE_NOT_PAYABLEon pay — already settled; poll status instead.- Docs: github.com/bitrefill/agents, docs.bitrefill.com