🚀 Three ways to integrate

Add crypto payments to
anything you build

One URL gets your users paying in seconds — no SDK, no API key, no integration. Plus a free public API for resolving usernames, fetching prices, and reading balances on 25+ chains.

See the Pay Link → Browse endpoints
API Overview

Three ways to integrate

Start with the Pay Link above — it covers most use cases. Layer in the public read API for richer experiences. Use partner endpoints for deeper integrations once OAuth ships.

Public — No Auth

Read API

Resolve usernames, look up prices, read balances on 25+ chains, list supported chains, generate payment links — all without an API key. Server-side calls only.

GET/v1/resolve/{code}
GET/v1/prices
GET/v1/{chain}/balance/{addr}
API Key + User Token

Server-side Payment Links

Programmatically generate pre-filled payment links and QR codes from a logged-in user's account — for invoicing, checkout, and request flows.

POST/v1/partner/request
GET/v1/partner/transactions
Beta — First-party today

Direct Send

Execute gasless transfers on a user's behalf. Requires the user's PIN per send today; OAuth flow lands soon to make this safe for third-party apps.

POST/v1/partner/send
Quick Start

From zero to sending in 3 minutes

1

Drop in the Pay Link (no code, no auth)

One HTML link, one MFW code, one amount. That's the whole integration for most apps. Skip to step 2 only if you need richer UX.

2

Add the public read API (still no auth, server-side)

Resolve recipient names + avatars before showing the pay button. Look up token prices. Read on-chain balances on 25+ chains. All free, all server-side.

3

Register for an API key (when you need partner endpoints)

Takes 30 seconds. Key is shown once — save it securely. Required for /v1/partner/* endpoints (server-side payment links, transaction history).

JavaScript
// ── 1. THE PAY LINK — zero integration ──────────────────────────────
// Just an HTML link. Anyone clicking lands inside their MFW wallet
// on a pre-filled send screen. Tap, confirm, done.
<a href="https://app.myfriendlywallet.io/?to=MFW-SARAH&amount=25&action=send">
  Pay 25 USDC
</a>

// ── 2. PUBLIC READ API — no key, no auth, server-side ───────────────
const base = 'https://mfw-api.sebjornstad.workers.dev';

// Resolve a username → wallet addresses on every chain
const { code, name, avatar, addresses } = await
  fetch(base + '/v1/resolve/MFW-SARAH').then(r => r.json());
// addresses.polygon.address, addresses.bitcoin.address, ... (~70 chains)

// Get USD prices for any token (free oracle)
const { prices } = await
  fetch(base + '/v1/prices').then(r => r.json());
// prices.ETH, prices.USDC, prices.SOL, ... (~100 tokens)

// Read a wallet's balance on any of 25+ chains (CORS proxied)
const bal = await
  fetch(base + '/v1/polygon/balance/0x742d...').then(r => r.json());

// ── 3. PARTNER API — needs your key + user bearer ───────────────────
// Generate a server-side payment link from a user's account
const { pay_link, qr_code } = await fetch(
  base + '/v1/partner/request', {
    method: 'POST',
    headers: {
      'X-MFW-Partner-Key': 'mfw_xxxxxxxxxxxx',    // from /v1/developer/register
      'Authorization': 'Bearer xxxxxxxxxxxx',    // user's MFW session
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({
      to_code: 'MFW-CLIENT', amount: '500', token: 'USDC',
      invoice_number: 'INV-042',
    }),
  }).then(r => r.json());
API Reference

Endpoints

🌐CORS & calling from a browser

The HTTP API only accepts cross-origin browser requests from myfriendlywallet.io, www.myfriendlywallet.io and app.myfriendlywallet.io. Third-party browser apps will be blocked by CORS — call from your server (Node, Python, Cloudflare Worker, edge function, etc.) instead. Server-side calls are unrestricted. The Pay Link below is the exception: it's a deep link to the MFW PWA, so it works from any HTML, anywhere.

Pay Link (deep URL)

LINK https://app.myfriendlywallet.io/?to={code}&...
A deep link to the MFW PWA that pre-fills the send, contact-add, or invoice screen. The most powerful integration — no API key, no SDK, works from any HTML, email, QR code, or social bio.
Public No authentication. Works in the user's browser. The user must have an MFW account (or will be prompted to create one).
to requiredRecipient MFW code, e.g. MFW-SARAH.
action optionalOne of send (open the send screen), add (open the add-contact screen), or invoice_request (open the invoice flow). Default: shows a choice modal.
amount optionalPre-fill the send amount, e.g. 25 or 25.50.
token optionalPre-select the token. Most common: USDC, USDT, EURC.
ref optionalReferral code. If the user is new, this is captured for attribution.
partner optionalYour partner API key prefix (e.g. mfw_abc12345) — NOT your full key. MFW looks up your registered partner_fee_bps + partner_fee_address and applies your fee on the send, on top of MFW's base fee. Cap: 200 bps (2%). Invalid prefixes silently degrade — the payer's send never fails because of partner-side issues. Auto-embedded in URLs returned by /v1/partner/request. See Fee Model for the full scope of what's supported today.
Examples: https://app.myfriendlywallet.io/?to=MFW-SARAH&amount=25&action=send · https://app.myfriendlywallet.io/?to=MFW-SARAH&action=add

User lookup

GET /v1/resolve/{code}
Resolve an MFW code to wallet addresses across every supported chain. Fully public — no auth required.
Public No authentication required (server-side only — see CORS note below)
code requiredMFW code in URL path, e.g. MFW-SARAH. Case-insensitive. Do NOT include the @ prefix — invalid characters return 400.
Returns { code, name, avatar, addresses } where addresses is a chain-keyed map: { polygon: {address, label}, bitcoin: {address, label}, solana: {...}, ethereum: {...}, base: {...}, ... ~70 chains }. Not every user has a wallet on every chain — check for the chain key before reading .address.
Errors: 400 invalid code format (must match MFW-[A-Z0-9]{3,20}) · 404 code not found · 403 user has not verified their email yet (anti-scam protection — these users cannot receive payments via the Pay Link either).
GET /v1/verify/{code}
Lightweight existence check — returns instantly whether a code is registered. Always 200; use the exists flag. Drop the @ prefix or it silently returns {exists:false}.
Public No authentication required (server-side only — see CORS note below)
Returns when found: { exists: true, code, display_name, avatar, pay_link }. Returns when missing: { exists: false }.

Utility (chains, prices, balances) — public, server-side

GET /v1/chains
List every chain MFW currently supports — chain id, EVM chainId, display name, native symbol, brand color.
Public No authentication required
Returns an array: [{ id, chainId, name, symbol, icon, color }, ...]. The id field is the same key used in /v1/resolve's addresses map.
GET /v1/check-code/{code}
Check whether a code is available for new registration. Inverse of /v1/verify.
Public No authentication required
Returns: { available: true|false, code }.
GET /v1/prices
Multi-source aggregated USD prices for ~100 major tokens (CoinGecko + Binance + CoinCap fallback). Cached server-side for low latency.
Public No authentication required
Returns: { prices: { ETH: 2422.07, BTC: 77253, USDC: 0.999913, ... } }. Free price oracle — no key, no signup.
POST /v1/prices/lookup
Batch price lookup for a custom list of tokens. Useful for portfolio displays where you only need a subset.
Public No authentication required
Body: { symbols: ["ETH","SOL","DOGE"] }. Returns the same shape as /v1/prices but filtered to your list.
GET /v1/prices/coingecko
Cached aggregated USD price feed pulled from CoinGecko + fallbacks. Returns the same shape as /v1/prices. Use when you want an alternate path to the aggregated price data.
Public No authentication required
GET /v1/prices/contract/{chain}/{address}
Get the USD price of any ERC-20 or SPL token by contract address. Long-tail token pricing.
Public No authentication required
Path: {chain} = ethereum, polygon, base, solana, etc. {address} = the token contract address.

Multi-chain balance proxy — public, server-side

Why this is gold: normally a multi-chain wallet UI means juggling RPC providers per chain (Ankr, Helius, Alchemy, plus chain-specific niche providers). MFW's worker proxies them all behind one consistent URL pattern. Free, server-side, no signup.
GET /v1/{chain}/balance/{address}
Read native-token balance for any address on the listed chain. CORS-bypassed — works without per-chain RPC keys.
Public No authentication required
Supported {chain} values: ethereum, polygon, base, arbitrum, optimism, bsc, zksync, linea, scroll, opbnb, ronin, mantapacific, vechain, xrp, polkadot, stellar, decred, filecoin, near, tezos, hyperliquid, multiversx, sui, aptos, cardano.

Each chain returns a normalized { balance, decimals } shape. For Solana, see the dedicated section below.
Chain-specific URL variants — not at /v1/{chain}/balance/{address}:
BCH — uses /v1/bch/utxo/{address} (returns UTXOs, no scalar balance endpoint).
Cosmos ecosystem — uses /v1/cosmos/balance/{chainId}/{address}. Supported chainIds: cosmos, osmosis, injective, sei, celestia, dydx, akash, kava.
Cardano UTXOs — in addition to the standard balance endpoint, UTXOs are at /v1/cardano/utxos/{address}.
Decred UTXOs — in addition to balance, UTXOs are at /v1/decred/utxos/{address}.

Solana proxy — public, server-side

GET /v1/solana/blockhash
Latest Solana blockhash — first step in building a Solana transaction.
Public No authentication required
POST /v1/solana/broadcast
Broadcast a signed Solana transaction. Body: { tx: "<base64-signed-tx>" }.
Public No authentication required
GET /v1/solana/balance/{address} also: /v1/solana/account/{address}, /v1/solana/usdt-balance/{address}
Read native SOL balance, full account info, or USDT (SPL) balance for any Solana address.
Public No authentication required

Token discovery — public, server-side

GET /v1/token-discovery/{chain}/{address}
Discover all tokens held by an address on a given chain. Returns balances, symbols, decimals, and prices.
Public No authentication required
Supported {chain} values: ethereum, polygon, base, arbitrum, optimism, bsc, zksync, linea, scroll, opbnb, ronin, mantapacific (plus other EVM chains).

For multi-chain discovery across every EVM chain in one call, use /v1/token-detect/portfolio/{address} below.
GET /v1/token-detect/portfolio/{address}
Full multi-chain portfolio detection for an address — finds tokens across every supported EVM chain.
Public No authentication required
GET /v1/tron/tokens/{address} also: /v1/ton/tokens/{address}
Token discovery on TRON (TRC-20) and TON (Jettons).
Public No authentication required

System

GET /health
Worker liveness probe with feature flags. Use for uptime monitoring.
Public No authentication required
Returns: { status: "ok", version, websocket, embedded_wallet, push_notifications, ... }.

Partner endpoints — your API key required

POST /v1/developer/register
Programmatically request a new partner API key. Same as the form below — useful for CI/CD or onboarding scripts. The key is returned exactly once; store it immediately.
Public No authentication required
name requiredYour name or company contact
email requiredContact email. Must be unique — duplicate returns 409.
app_name requiredDisplay name for your app or product
website optionalYour website URL
partner_fee_bps optionalDefault fee in basis points. Max 200 (2%) — higher returns 400.
partner_fee_address optionalAddress that receives your fee. Required when partner_fee_bps > 0 — otherwise returns 400.
Returns: { success: true, message, api_key, api_key_prefix, partner_fee_bps, docs }. The api_key is shown once — only its hash is stored server-side.
POST /v1/partner/send Beta — first-party today
Execute a gasless stablecoin transfer on behalf of the authenticated user. Currently requires the user's PIN in the request body — which is fine for MFW's own app but unsafe to ask of users in third-party apps. Until the OAuth-style flow lands, prefer the Pay Link or /v1/partner/request for third-party use.
API Key + User Token + PIN X-MFW-Partner-Key + Authorization: Bearer + body.pin
to_code requiredRecipient MFW code, e.g. MFW-SARAH. Case-insensitive.
amount requiredAmount as string or number. Full amount before fees.
pin requiredUser's MFW PIN. The worker requires this to authorise each send. Never collect this in a third-party UI.
token optionalUSDC (default), EURC, or USDT. USDC/EURC settle on Base; USDT settles on Solana.
msg optionalPayment memo shown to recipient
partner_fee_bps optionalYour fee in basis points (max 200 = 2%). Overrides your registered default.
partner_fee_address optionalAddress to receive your fee. Required if partner_fee_bps > 0.
Returns on success: { success: true, tx_hash, amount_sent, token, mfw_fee, partner_fee, recipient_code, msg }.
POST /v1/partner/request
Generate a payment request link and QR code. No funds move — this just builds a URL. Perfect for invoices and checkout pages. The returned pay_link automatically embeds &partner=<your_key_prefix> so your configured partner fee (if any) is applied when the payer pays.
API Key + User Token
to_code requiredWho should pay — their MFW code
amount requiredAmount to request
token optionalUSDC, EURC, USDT
invoice_number optionalIncluded in payment memo (e.g. "INV-042")
msg optionalAdditional memo
Returns: { pay_link, qr_code, from_code, to_code, amount, token }
GET /v1/partner/balance
Returns the authenticated user's wallet addresses across every chain — not live balances. To read on-chain balances, pass these addresses to the public /v1/{chain}/balance/{address} endpoints documented above.
API Key + User Token
Returns: { user_code, evm_address, wallets: { polygon: "0x...", bitcoin: "bc1...", solana: "...", ... } }.
GET /v1/partner/transactions
Paginated transaction history for the authenticated user.
API Key + User Token
limit optionalMax results, default 20, max 100
offset optionalPagination offset
Fee Model

Transparent, stacked fees

MFW takes its fee first, always. Your fee stacks on top. The recipient always receives exactly what's left. Everything is logged and auditable on-chain.

Sender sends $50.00 USDC
MFW gasrelay fee (0.25% — min $0.05 — non-negotiable) − $0.125
Your partner fee (0–2%, your choice) − $0.15 (0.3% example)
Recipient receives $49.725 USDC
Gas cost to sender $0.00 — fully gasless

Partner fees are capped at 200 bps (2%) to protect users. Your fee address receives its cut atomically in the same transaction — no separate payout needed. Partner fees apply on any Pay Link that carries &partner=<your_key_prefix>, which is auto-embedded by /v1/partner/request or can be added manually to Pay Links you generate yourself.

⚠️ Partner-fee scope — what works today

Partner fees are applied on the gasless USDC/EURC send path (Base/Polygon) when the payer has an MFW embedded wallet. That's the path used by virtually all MFW users who sign up via the app — the default flow.

✓ SupportedUSDC + EURC on Base/Polygon, payer with embedded wallet (the default MFW signup)
— Pass-throughUSDT on Solana and other stablecoin paths — your partner prefix is accepted but no partner fee is charged in v1; coming in a follow-up
— Pass-throughSelf-custody wallet users (payer signs each send manually) — partner fee not charged in v1 because the third transfer needs to be client-signed. Ships with the OAuth flow.
Fail-safeIf partner lookup fails for any reason (invalid prefix, DB hiccup, bad address format), the send proceeds normally without a partner fee. The payer is never blocked by partner-side issues.
Security Model

Your key can never move funds alone

The architecture is designed so that a compromised partner key is harmless without the user's active consent.

🔑

Two-factor API access

Every transactional endpoint requires both your partner key AND the user's valid session token. A stolen partner key alone cannot execute any send.

🔐

Keys never leave MFW

Private keys live in MFW's encrypted vault. You never touch them. You cannot drain a user's wallet even with full API access — user consent is always required.

📋

Full audit log

Every API call is logged with developer ID, user ID, endpoint, and timestamp. MFW can revoke any partner key instantly if misuse is detected.

Fee cap protection

Partner fees are hard-capped at 2% in the worker code. You cannot overcharge users by misconfiguring your fee parameter — the cap is enforced server-side.

Developer Community

Build together, learn together

Join fellow developers building on MFW. Get help with widget integration, share what you've built, and help others solve real problems — from simple embeds to custom payment flows.

MFW Developer Community

Ask questions, share code snippets, show off what you've built, and help others — from a first widget embed to full custom payment flows. All skill levels welcome.

# widget-integration # api-and-auth # code-help # bugs-and-issues # built-with-mfw
Join on Discord
Get Started

Register for an API key

Free for all developers. Your key is shown once — save it immediately.

Optional — set a default fee per send. 100 bps = 1%. Max 200 bps (2%).
Your API key — save this now:
⚠️ This key will not be shown again. Store it in your environment variables.