
API integration for Revolut Business
We build your Revolut Business connector
Your tool queries the Revolut Business API to read transactions, send transfers and reconcile cash with no bank export.
- Senior product team
- banking integrations in production
- from scoping to monitoring
What does the Revolut Business API provide and why connect Revolut to your software?
Revolut Business is an online business bank with currency exchange, team card and international transfer capabilities. Its API lets your application read accounts and transactions, create transfers and manage cards, turning treasury management into a function of your software rather than a manually reviewed export. You integrate it in financial management tools, multi-currency payment platforms or accounting software that needs a real-time view of balances and movements without manually logging into the Revolut portal.
What our clients build on the Revolut API
Reconciliation when the money lands
TransactionCreated triggers matching on amount plus reference. No bank export ticked off at month end.
Paying suppliers from the product
The application prepares, a human approves the draft in Revolut. The software cannot empty an account on a loop bug.
Payout with no IBAN on file
A payout link for an indemnity, a fee, a refund. PayoutLinkStateChanged closes the file.
Multi-currency cash
Accounts, transactions and FX exposed in the director portal. The rate is no longer a frozen cell in a spreadsheet.
What it changes in your cash position
Engineering in service of a measurable outcome: up-to-date cash, framed transfers, less manual export.
You see the money when it arrives
The invoice is matched on TransactionCreated, not on a statement 15 days later. Reminders stop on the day of the credit.
A transfer stays a human decision
Draft in the application, approval in Revolut. That is the boundary a director wants to see on an outbound payment.
Fewer double transfers
request_id derived from the invoice, plus a lock beyond Revolut's 2-week memory. A timeout does not pay twice.
A shorter close
Entries arrive already attached. The accountant stops rebuilding flows from a CSV.
How we ship your Revolut connector
Scoping
Business API, not Merchant. Read or transfer, PAY scope, IP allowlist. We drop READ_SENSITIVE_CARD_DATA if the product does not need it.
Development
JWT client, access_token refreshed before 40 minutes, business request_id, v1.{timestamp}.{body} signature with a 5-minute window.
Acceptance testing
Official signature vector, sandbox simulations (complete, revert, decline, fail), 400 on duplicate request_id treated as success.
Monitoring
Alerts on unprocessed events, a transfer log, a health dashboard. The failed-webhook endpoint is the safety net, not an option.
What the Revolut Business API allows
- Accounts and transactions
- Read accounts and history. Time pagination (from, to, count up to 1,000), not a cursor: equal timestamps have to be handled.
- Transfers and drafts
- POST /pay with request_id. Drafts materialise human approval: the application prepares, an authorised user approves in Revolut.
- Payout links
- Pay someone whose IBAN you do not have. PayoutLinkCreated and PayoutLinkStateChanged follow actual collection.
- v2 webhooks
- Four types only, 10 webhooks maximum. TransactionCreated and TransactionStateChanged cover reconciliation, the rest is swept.
The vocabulary of the Revolut Business API
- private_key_jwt
- Assertion signed with your private key. iss is the redirect URI domain, without https://. sub is the client_id, aud is https://revolut.com. The token exchange body is form-encoded, not JSON.
- request_id
- Idempotency identifier in the POST /pay body, not a header. Remembered for 2 weeks. A duplicate returns 400 Bad Request, not 409.
- Revolut-Signature
- v1=<hex>, HMAC-SHA256 of v1.{Revolut-Request-Timestamp}.{raw body}. 5-minute window. During rotation, several signatures, one match is enough.
- READ_SENSITIVE_CARD_DATA
- Card scope. Without an IP allowlist, you lose access to every Business API endpoint, not only cards. If the product does not need it, do not request it.
- 40-minute access_token
- A 401 mid-job is a nominal case. The refresh_token, per the documentation, does not expire: actual consent duration is confirmed at scoping.
- Business vs Merchant
- Business: b2b.revolut.com, JWT, TransactionCreated. Merchant: merchant.revolut.com, collection, ORDER_COMPLETED. Same developer domain, two products.
The real constraints of the Revolut Business API
This is not the Merchant API
Hosts, scopes and events differ. Mixing them up is the most common scoping error: you collect on one side, you read the account on the other. Modules, secrets and webhook routes stay separate.
Idempotency limited to 2 weeks
Replaying a request_id after 2 weeks can create a second transfer. A 400 on a duplicate is an idempotent success, not a validation error. The mapping is persisted on the response: request_id search is capped at 14 days.
The card scope can cut everything
READ_SENSITIVE_CARD_DATA without an IP allowlist blocks access to the whole Business API. It is a configuration trap, not a refusal limited to one endpoint.
Four events, unpublished rate limits
No balance, card or counterparty event: the rest is swept. No rate limit is published. The failed-webhook endpoint is the safety net, retry policy not being reliably documented.
Business API or Merchant API?
Two products, one developer domain. The right one depends on whether you read an account or you take payment.
| Criterion | Business APIThe account | Merchant APICollection |
|---|---|---|
| Host | b2b.revolut.com/api/1.0 | merchant.revolut.com |
| Authentication | JWT assertion, READ WRITE PAY scopes | Merchant key, version header |
| Events | TransactionCreated, PayoutLink* | ORDER_COMPLETED, DISPUTE_WON |
| Outbound money | POST /pay, drafts, links | Refund of an order |
| Idempotency | request_id, 2 weeks, 400 on duplicate | Specific to collection |
| Webhook signature | v1.{timestamp}.{body}, HMAC | Same mechanism, different events |
| The right case | Cash, transfers, reconciliation | Checkout, subscription, card dispute |
The two combine on one product, with distinct modules. This page covers the Business API. Online collection is scoped separately.
What we measure on a Revolut integration
The other banking APIs
If your accounts are not all at Revolut, these options are worth discussing during scoping.
Revolut BusinessWe build your Revolut Business connectorThis page
QontoFrench business bank, direct API, receipts and SEPA transfers.Open bankingBridge, Powens or Tink: several banks covered, thinner data, consent to renew.We combine Revolut with
The stack that surrounds Revolut Business on our projects.
Revolut integration: your questions
Three steps. First the key pair, the public certificate in the Revolut Business portal, and a client that signs a JWT assertion (iss = domain without scheme, token exchange as form body). Then a connector that refreshes the access_token before 40 minutes, reads transactions in time windows, and sets a request_id derived from the invoice on every POST /pay. Finally v2 webhooks: HMAC of v1.{timestamp}.{raw body}, reject outside the 5-minute window, several signatures during rotation. The sensitive part is not the call, it is not mixing up Business and Merchant, and persisting the request_id mapping on the response.
A first useful flow, typically syncing transactions into a dashboard, ships in two to three weeks. A chain with transfers, drafts, payout links and reconciliation is closer to six to eight weeks. Scoping first settles Business API or Merchant API, and drops READ_SENSITIVE_CARD_DATA if card details are not needed, because that scope without an IP allowlist can cut access to the whole API. We give a firm estimate before we start.
The Business API lives on b2b.revolut.com/api/1.0, authenticates with a JWT assertion, and talks about TransactionCreated, transfers and accounts. The Merchant API lives on merchant.revolut.com, takes online payment, and talks about ORDER_COMPLETED, ORDER_AUTHORISED, DISPUTE_WON. The webhook signing mechanism is similar, which misleads. This page covers the account. If you collect from customers online, that is another connector, other secrets, other routes.
Derive request_id from intent (transfer:{supplier_invoice_id}), never a UUID regenerated on every attempt. Persist the request_id plus transaction id pair on the response, because GET /transactions filtered by request_id only accepts 14 days. Treat a 400 duplicate request_id as success: re-read the transaction in the window, continue. Beyond 2 weeks, Revolut may create a second payment: the application lock covers that window. This is the most concrete bug on this API.
Yes. We push Revolut transactions into Pennylane with the invoice reference, and a periodic consistency check flags the gap, with no silent fix. Qonto combines when some accounts sit elsewhere: the Qonto API for those accounts, Revolut for its own, possibly PSD2 aggregation for the rest. It is not an exclusive choice, it is an account map drawn at scoping. A bank entry is not repaired behind the accountant's back.
A Revolut integration project?
Let's talk. 30 minutes to scope the account and transfers, check what the API actually allows and tell you honestly what is feasible.
Discuss my Revolut project