Every agent framework has a tool for web search. None has a tool for paying a real person in a market the card rails don't reach.
Storspay is the payout tool for AI agents: one MCP tool call sends a real payment — same-day, into Africa and Latin America — inside limits a human sets in advance.
Live today. Request access and we'll send keys and docs once your business clears KYB.
One all-in rate. Storspay never holds your funds — see Disclosures.
No spam · We email you about your keys, nothing else
Let an AI agent pay real people.
One MCP tool call sends a payout inside a mandate a human set in advance. For agent builders and AI-native teams.
Embed payouts in your own checkout.
Instant payouts for gig, creator and outsourcing platforms. Escrow (hold & release) for marketplaces. Webhooks, sandbox keys, revenue share.
Accounts and cards for the people you pay. Payments in from Africa.
Open a USD account for any seller or worker, issue a card that spends from it, collect from buyers in Africa, and pay in USD, GBP or EUR. Same keys.
// The agent's toolbelt already has search.
// This adds payouts.
await storspay.createPayout({
mandate_id: "mnd_...", // permission a human granted
recipient_id: "rcp_...", // must be on the approved list
amount_usd: 300,
idempotency_key: "..." // safe to retry
});Set the limits. Then try to break them.
This simulator runs entirely in your browser. Set a mandate on the left, then fire scenarios on the right — the outcomes respond to your settings, because that's the product.
Set the agent's limits
That refusal is the product.
Every block is logged, every limit is set by a human, and no agent can widen its own permission.
Request API access →Why a finance team will actually allow an agent to pay people.
An agent that can move money is only deployable if the money can't move outside lines a human drew. Every payout runs inside a mandate:
Approved people only
The agent pays only recipients a human put on an approved list. Anyone else is refused, logged, and left for a human to add.
Capped per payment and per month
Hard ceilings on any single payout and on the month's total. When the cap is reached, the agent stops — it cannot raise its own limit.
Allowed countries only
Payouts go only into corridors the human switched on. Everything else refuses on corridor, before any money is touched.
Big payments wait for a human
Anything above the approval threshold stops and waits. A named person approves it before it moves — no exceptions, no override flag.
Instant pause
A human can pause every agent on the account instantly. Paused means paused: pending runs freeze and nothing new executes.
No proprietary SDK. Nothing to install.
The interface is built on the standards agent frameworks already speak, so calling Storspay is no different from calling any other tool.
MCP — Model Context Protocol
The tool surface is an MCP server. Every major agent framework supports MCP, so any agent can call Storspay payouts with no custom work on either side.
AP2-style mandates
The mandate structure is modelled on the AP2 intent / cart / payment pattern: the human grants a scoped, signed permission in advance, and every payout is checked against it.
Agent card for discovery
A machine-readable agent card at /.well-known/agent.json describes the capabilities and authorization model, so agents and directories can discover the service.
Agent payments today are about agents buying things.
The agent-payments wave so far is agents buying from merchants — checkout, carts, cards. Almost nobody is building for agents that pay people: the annotators, contributors, sellers and delivery teams that platforms owe money to every week. And the payout rails that do exist stop at a handful of countries. Ours don't — they reach the corridors where this workforce actually is, across Africa and Latin America.
Integrate once. Every vendor, worker and seller gets paid through your own checkout.
A REST API for platforms and marketplaces that owe money to people in Africa, Latin America and Asia. Create a recipient, create a payout, get a webhook when it lands — 2–5 minutes later, in local currency. Pay out instantly, or hold funds in escrow until delivery is confirmed. Sandbox keys to build, production keys after KYB.
Three calls. That's the integration.
Everything lives under /api/v1/ and is authenticated with your API key as a Bearer token. Build against sk_test_ keys in the sandbox — nothing moves — then switch the prefix to sk_live_ when KYB clears.
- Create a recipient once — name, country, currency and their bank or mobile-money details. You get back a
recipientIdto reuse forever. - Create a payout in USD with your own reference. The response quotes the fee, the exchange rate and the exact local amount before anything settles.
- Listen for the webhook —
payout.completedarrives when the money lands, usually within 2–5 minutes.
curl https://app.storspay.com/api/v1/recipients \
-H "Authorization: Bearer sk_test_51Hx…" \
-H "Content-Type: application/json" \
-d '{
"name": "Amara Okafor",
"email": "amara@example.com",
"country": "NG",
"currency": "NGN",
"bankAccount": { "bankCode": "058", "accountNumber": "0123456789" }
}'
// 201 Created
{ "recipientId": "rcp_8f2k…", "status": "verified" }curl https://app.storspay.com/api/v1/payouts \
-H "Authorization: Bearer sk_test_51Hx…" \
-d '{ "recipientId": "rcp_8f2k…", "amountUsd": 250,
"reference": "order_10492" }'
// 201 Created
{ "payoutId": "pay_3n7q…", "status": "processing",
"fee": 5.00, "exchangeRate": 1329.17,
"localAmount": 325647.00, "currency": "NGN",
"estimatedDelivery": "2–5 minutes" }Instant payouts. Money lands in 2–5 minutes.
The default mode. Your platform calls POST /api/v1/payouts, funds leave your Storspay wallet immediately and arrive in the recipient's bank account or mobile-money wallet in local currency. Same rails as our payroll product — triggered by your code instead of a person.
Built for platforms that pay on a schedule or on demand: weekly gig earnings, per-task data-labelling payments, creator revenue, monthly contractor invoices. Batch as many calls as you need — rate limit is 100 requests a minute per key, and every payout carries your own reference so reconciliation is a join, not a hunt.
If a payout fails — a wrong account number, say — funds return to your wallet automatically and you receive payout.failed with the reason. Recipients never open an account, install an app or see anything but local currency.
{
"payoutId": "pay_3n7q…",
"reference": "order_10492",
"status": "completed",
"amountUsd": 250.00,
"fee": 5.00,
"exchangeRate": 1329.17,
"localAmount": 325647.00,
"currency": "NGN",
"recipient": { "recipientId": "rcp_8f2k…", "country": "NG" },
"createdAt": "2026-09-06T14:02:11Z",
"completedAt": "2026-09-06T14:05:48Z"
}{ "data": [ …47 payouts… ], "hasMore": false,
"totals": { "amountUsd": 11840.00, "fees": 236.80 } }Escrow. Hold at checkout, release on delivery.
Built for marketplaces. Create the payout with "escrow": true and the funds are secured from your wallet but not disbursed — the payout sits in held. Your buyer sees "Payment secured". When delivery is confirmed, call POST /api/v1/payouts/:id/release and the vendor is paid in the usual 2–5 minutes.
- Buyer view: Payment secured → Funds held → Delivered. Vendor view: Payment pending → Payment released → Funds received. Both are yours to render — we send the state changes.
- Cancel a held payout any time with POST /api/v1/payouts/:id/cancel — funds return to your wallet instantly and you get payout.refunded.
- 14-day safety net: a payout still held after 14 days is refunded to your wallet automatically, with a payout.refunded webhook. No money ever gets stuck.
{ "recipientId": "rcp_8f2k…", "amountUsd": 1200,
"reference": "order_20817", "escrow": true }
// 201 Created — funds secured, nothing disbursed yet
{ "payoutId": "pay_9k2e…", "status": "held",
"fee": 24.00, "localAmount": 1563103.00, "currency": "NGN",
"holdExpiresAt": "2026-09-20T14:02:11Z" }// 200 OK — disbursing to the vendor now { "payoutId": "pay_9k2e…", "status": "processing", "releasedAt": "2026-09-09T09:41:03Z", "estimatedDelivery": "2–5 minutes" }
{ "payoutId": "pay_9k2e…", "status": "refunded",
"refundedToWallet": 1224.00 }Webhooks. Every state change, signed and retried.
Register a webhook URL when your partner account is created (or override it per payout with callbackUrl). We POST every payout state change with your reference attached, sign each delivery with HMAC-SHA256 using your webhook secret, and retry failed deliveries three times — after 30 seconds, 2 minutes and 10 minutes.
payout.createdpayout acceptedpayout.processingfunds in flightpayout.completedmoney landedpayout.failedreturned to walletpayout.heldescrow securedpayout.releasedescrow releasedpayout.refundedcancelled or 14-day timeoutVerify the signature by computing HMAC-SHA256 over the raw body with your secret and comparing it to the Storspay-Signature header. Treat events as idempotent — the same payoutId and status may arrive twice if a retry overlaps.
Request sandbox keys →Storspay-Signature: t=1757167548,v1=5f1e9a…
Content-Type: application/json
{
"event": "payout.completed",
"payoutId": "pay_3n7q…",
"reference": "order_10492",
"status": "completed",
"amountUsd": 250.00,
"localAmount": 325647.00,
"currency": "NGN",
"recipient": { "recipientId": "rcp_8f2k…", "name": "Amara Okafor" },
"timestamp": "2026-09-06T14:05:48Z"
}const sig = crypto.createHmac('sha256', WEBHOOK_SECRET)
.update(rawBody).digest('hex');
if (sig !== headerV1) return res.status(400).end();
// respond 2xx within 10s — otherwise we retry (30s → 2m → 10m)Every endpoint, on one screen.
All routes live under https://app.storspay.com/api/v1/, require Authorization: Bearer <key>, return JSON and follow OpenAPI 3.0. Full request/response schemas ship with your keys.
| Method | Path | What it does |
|---|---|---|
| Recipients | ||
| POST | /recipients | Create a recipient — name, email, country, currency, bank or mobile-money details. Optional payoutMethod: local_currency (default), usd_ach, gbp_fp, eur_sepa or storspay_account. Returns recipientId. |
| GET | /recipients | List all recipients for your platform. |
| GET | /recipients/:id | Fetch one recipient. |
| Payouts | ||
| POST | /payouts | Create a payout: recipientId, amountUsd, reference, optional callbackUrl, optional escrow (default false). Returns payoutId, status, fee, exchangeRate, localAmount, estimatedDelivery. |
| GET | /payouts/:id | Payout status and details. |
| GET | /payouts | List payouts — filter by status, date range, recipient. |
| POST | /payouts/:id/release | Release an escrowed payout (status held → disbursed in 2–5 min). |
| POST | /payouts/:id/cancel | Cancel a held payout — funds return to your wallet. |
| Account & market data | ||
| GET | /balance | Your current wallet balance. |
| GET | /earnings | Accumulated revenue share and pending payout of earnings. |
| GET | /corridors | All live corridors with current rates, limits and channel availability (bank / mobile money). |
| GET | /rates/:corridor | Current exchange rate for one corridor. |
Auth: Bearer API key (sk_test_ sandbox · sk_live_ production) · Rate limit 100 requests/min per key · Keys are generated, rotated and revoked by Storspay; your platform's admin sees usage stats.
You integrate once. You earn on every payout.
Platform partners pay the same transparent all-in rate as everyone else — 2% per payout, covering conversion, settlement and local delivery, with no API fee and no monthly minimum. Then two things only API partners get:
Earnings accrue per payout and are visible any time via GET /api/v1/earnings or your partner dashboard. We pay accumulated earnings out monthly to your bank account or your Storspay wallet.
Talk to us about partner terms →Illustrative figures. Your discount and revenue-share percentage are set in your partner agreement.
Run a marketplace checkout. Watch the money move.
This simulator runs entirely in your browser. Pick instant or escrow, fire the API calls on the right, and watch the buyer and vendor screens on the left update — exactly the states your webhook handler will receive.
That's the whole vendor-payment flow.
Your checkout calls one endpoint, the vendor is paid in local currency in minutes, and every state change reaches your webhook — signed. Request sandbox keys and build this against real endpoints today.
Request sandbox keys →Same keys, four more surfaces. Accounts, cards, collections, transfers.
Open a USD account (with GBP and EUR details) for any seller, worker or organisation. Issue them a card that spends from it. Collect from buyers in Africa by bank transfer or mobile money. Move money between accounts instantly, with optional escrow. All under /api/v1/, the same Bearer keys, the same webhook envelope. Build against the sandbox today; production follows verification of your business and each account holder.
A USD account for anyone you pay. One call.
Post the holder — a person, a business or an organisation — and you get back a pending account and a hosted verification link. When they pass, the account activates with a US routing and account number in their name, plus UK sort-code and EUR IBAN details. Deposits arrive by the same webhook path as your platform wallet.
- Create the holder with an
externalReffrom your system — the same ref twice returns the same account, never a duplicate. - Send them the
kycUrl— a hosted flow with your name on it. Sandbox holders named "Test Approved" pass instantly. - Settle sales into it with
POST /transfersfor 0.5% — instant, no rail — or let buyers and employers pay the account details directly.
curl https://app.storspay.com/api/v1/virtual-accounts \
-H "Authorization: Bearer sk_test_51Hx…" \
-d '{
"holder": { "externalRef": "seller_4471", "type": "individual",
"displayName": "Amara Okafor", "email": "amara@example.com",
"phone": "+2348012345678", "country": "NG",
"dateOfBirth": "1991-04-12" },
"currency": "USD"
}'
// 201 Created
{ "virtualAccountId": "va_9k2m…", "holderId": "hld_2f7a…",
"status": "pending_kyc", "kycUrl": "https://verify.storspay.com/…" }{ "virtualAccountId": "va_9k2m…", "status": "active",
"usd": { "routingNumber": "0210…", "accountNumber": "9876…",
"bankName": "…", "accountHolderName": "Amara Okafor" },
"gbp": { "sortCode": "04-00-…", "accountNumber": "3310…" },
"eur": { "iban": "IE…4471", "bic": "…" },
"balanceUsd": 0.00 }A card that spends from the balance.
Issue a virtual Storspay Card the moment an account is active, or a physical one shipped to the holder. Every authorisation is checked against the balance in real time and declined in plain language when it can't clear. Controls — per-transaction, daily and monthly caps, allowed countries, blocked merchant categories, ATM and online toggles — are yours, the holder's, or an organisation manager's for delegate cards.
- Issue —
POST /cards(virtual, instant) orPOST /cards/physical(shipped; activated with last-4 + date of birth). - Control —
PATCH /cards/:idto freeze, set spend controls, report lost.validFrom/validUntilfor trip cards. - Reveal safely — the PAN is never in an API response.
POST /cards/:id/reveal-tokenreturns a 60-second single-use token your app exchanges in the holder's own session.
Three active cards per individual, twenty-five per organisation. Virtual cards are free; physical $10. USD purchases carry no fee; other currencies 1.5%.
curl https://app.storspay.com/api/v1/cards \
-H "Authorization: Bearer sk_test_51Hx…" \
-d '{ "virtualAccountId": "va_9k2m…",
"cardholderName": "Amara Okafor",
"spendControls": { "perTxnUsd": 500, "monthlyUsd": 3000,
"allowedCountries": ["NG","US","GB"],
"atm": false, "online": true } }'
// 201 Created
{ "cardId": "crd_7t3p…", "form": "virtual", "last4": "4471",
"expiry": "09/29", "status": "active" }{ "event": "card.declined", "data": {
"cardId": "crd_7t3p…", "amountUsd": 640.00,
"merchant": { "name": "…", "mcc": "5732", "country": "US" },
"declineReason": "per_transaction_limit",
"message": "Above this card's $500 per-purchase limit" } }Payouts, in reverse.
A collection is a payment request: you say who's paying, from which country, by bank or mobile money, and how much — in their currency or in USD. You get back local payment instructions and a reference to show them. When they pay, the funds convert and credit the account you named — your platform wallet or a holder's account — and collection.credited fires. 2% all-in, mid-market rate on arrival.
- Create with
creditTo,country,method, amount and the payer's details. Amounts above a channel cap return several references in one collection. - Show the instructions — bank or paybill details rendered as Storspay's, plus the reference and an expiry countdown.
- Handle the states — pending → received → converting → credited. Late or mismatched payments are credited and flagged, never lost. Above $25,000 a review state sits before credited.
curl https://app.storspay.com/api/v1/collections \
-H "Authorization: Bearer sk_test_51Hx…" \
-d '{ "creditTo": { "virtualAccountId": "va_9k2m…" },
"country": "KE", "currency": "KES", "amountUsd": 980,
"method": "bank_transfer",
"payer": { "name": "Riverside Medical Group",
"source": { "accountType": "bank", "accountNumber": "…" } },
"reference": "inv_2026_0147", "expiresInMinutes": 1440 }'
// 201 Created
{ "collectionId": "col_5r8w…", "status": "pending",
"quotedRate": 129.44, "amountLocal": 129437, "feeUsd": 20.00,
"expectedUsd": 980.00, "expiresAt": "2026-09-10T14:02:00Z",
"paymentInstructions": [{ "reference": "STORS-KE-4K7P2Q",
"bankName": "…", "accountNumber": "…", "amountLocal": 129437 }] }{ "event": "collection.credited", "data": {
"collectionId": "col_5r8w…", "receivedLocal": 129437,
"effectiveRate": 129.41, "creditedUsd": 980.22,
"creditTo": { "virtualAccountId": "va_9k2m…" } } }Move money between accounts. Or out in USD, GBP, EUR.
POST /transfers moves USD from your platform wallet or a holder's account to another account (instant, free between holders, 0.5% from a platform), or out to any destination — a local bank or mobile wallet through least-cost routing, or a US, UK or European bank account for a flat fee. Escrow works here too: escrow:true holds until you release or cancel, with a 14-day auto-refund.
USD, GBP and EUR payouts are the same shape on /payouts: create the recipient with payoutMethod: usd_ach | gbp_fp | eur_sepa and their bank details (ABA routing, sort code or IBAN — checksum-validated), and the payout delivers the exact amount with no conversion: flat $5, £4 or €4.50. Or payoutMethod: storspay_account to land it instantly in their Storspay Account.
curl https://app.storspay.com/api/v1/transfers \
-H "Authorization: Bearer sk_test_51Hx…" \
-d '{ "from": { "kind": "partner_wallet" },
"to": { "virtualAccountId": "va_9k2m…" },
"amountUsd": 1200, "reference": "order_10492",
"escrow": false }'
// 201 Created
{ "transferId": "trf_2c9x…", "status": "completed",
"feeUsd": 6.00, "arrival": "instant" }curl https://app.storspay.com/api/v1/payouts \
-H "Authorization: Bearer sk_test_51Hx…" \
-d '{ "recipientId": "rcp_gbp_71…", // payoutMethod: gbp_fp
"amountUsd": 1000, "reference": "inv_884" }'
// 201 Created
{ "payoutId": "pay_8d1k…", "status": "processing",
"channel": "gbp_fp", "exchangeRate": 0.7385,
"localAmount": 738.45, "feeGbp": 4.00,
"estimatedDelivery": "within hours" }The four surfaces, on one screen.
Same base URL, auth, pagination and error envelope as the Platform API. Resources belonging to another partner return 404, never 403. New error codes: kyc_not_approved, holder_frozen, limit_exceeded, card_limit_reached, balance_not_zero, collections_unavailable.
| Method | Path | What it does |
|---|---|---|
| Storspay Accounts | ||
| POST | /virtual-accounts | Open an account for a holder (or an existing holderId). Returns pending_kyc + kycUrl; activates with USD, GBP and EUR details. |
| GET | /virtual-accounts · /:id · /:id/transactions | List, fetch, and read the ledger — deposits, collections, transfers in/out, card settlements, fees. |
| POST | /virtual-accounts/:id/kyc-link | Regenerate the hosted verification link. |
| DELETE | /virtual-accounts/:id | Close an account — balance must be zero. |
| Storspay Cards | ||
| POST | /cards · /cards/physical | Issue a virtual card instantly, or a physical card to a shipping address. |
| GET | /cards · /:id · /:id/transactions | List cards, fetch one, read authorisations, settlements, reversals and refunds. |
| PATCH | /cards/:id | Freeze / unfreeze, update spendControls, activate a physical card, report lost. |
| POST | /cards/:id/reveal-token | 60-second, single-use token to show PAN and CVV in the holder's session. Never returned by the API itself. |
| DELETE | /cards/:id | Cancel a card. |
| Collections — "Receive payment" | ||
| POST | /collections | Create a payment request: creditTo, country, currency, amountLocal or amountUsd, method, payer, reference, expiresInMinutes. Returns instructions, quoted rate, fee, expected USD. |
| GET | /collections · /:id | List and fetch — status pending / received / converting / credited / expired / cancelled / failed. |
| POST | /collections/:id/cancel | Cancel a pending request. |
| Transfers | ||
| POST | /transfers | from partner wallet or account → to account, @handle, or a payout destination (local, USD·ACH, GBP, EUR). Optional escrow. |
| GET | /transfers · /:id | List and fetch; the seven payout statuses reused. |
| PATCH | /transfers/:id | { "action": "release" | "cancel" } for escrowed transfers; 14-day auto-refund otherwise. |
Webhooks: virtual_account.*, card.*, collection.*, transfer.* — same envelope and Storspay-Signature as payouts, retried 30 s / 2 min / 10 min. Sandbox: holders named "Test Approved" / "Test Rejected"; simulated deposit, collection-received and card-purchase endpoints.
Africa, Latin America and Asia, live now.
The payout rails under this API are live today, moving B2B cross-border payroll. Twenty-six corridors, added to quarterly.
West & Central Africa
East & Southern Africa
Latin America & Asia
Same pricing as the rest of Storspay. No API fee.
2% all-in per payout, depending on corridor — the same rate as every other way of using Storspay. That one rate covers conversion, settlement and local delivery. No separate API fee, no hidden FX markup, no monthly minimum.
Where this is, honestly.
Agent-callable rails + Platform API
The payout rails are live and moving payroll today. The MCP tool for agents and the REST Platform & Marketplace API (instant payouts, escrow, webhooks) both sit on top of them. Verified businesses get keys on request. The Accounts, Cards & Collections surfaces are in sandbox on the same keys; production opens per business after verification.
Framework SDKs
Packaged integrations for the agent frameworks people actually use, driven by what the access list tells us they're building.
Self-serve keys
Instant keys after automated KYB, no human in the loop on our side. Until then, a person reviews every access request.
The questions you'd type into a search box.
POST /virtual-accounts opens a USD account (with GBP and EUR details) in the seller's name after a hosted verification; POST /cards issues a virtual or physical Storspay Card that spends from it. Settle sales into the account with POST /transfers for 0.5%. Your checkout shows "Powered by Storspay" and nothing else.POST /collections creates a payment request with local bank or mobile-money instructions and a reference. When the buyer pays, USD is credited to your wallet or the seller's account and collection.credited fires. 2% all-in at the mid-market rate on arrival; large amounts split under local caps automatically.payoutMethod: usd_ach, gbp_fp or eur_sepa and their bank details. The payout delivers the exact amount with no conversion for a flat $5, £4 or €4.50 — in the same batch as your local-currency payouts.Ready to pay real people — from your platform or your agent?
Request access and tell us what you're building: a marketplace, a payout platform, an AI agent. Sandbox keys, production keys and docs follow KYB, and your answer shapes what we ship next.
One all-in rate. Storspay never holds your funds — see Disclosures.
B2B only · KYB required · No personal remittances
Investor? See the investor thesis →