Push payments to Revolut Terminal
This guide explains how 3rd-party Point of Sale (POS) software providers can integrate with the Revolut Terminal to push payment intents from their server-side POS applications to physical Revolut Terminal devices.
This integration is designed for developers and integrators building Point of Sale (POS) software who want to enable their merchants to accept payments using Revolut Terminal devices.
How it works
Push payments to Revolut Terminal is a server-to-server integration that allows your POS software to send payment requests directly to Revolut Terminal devices. This integration requires internet connectivity on both the POS system and the Revolut Terminal (there is no Bluetooth or physical cable communication).
From an implementation perspective, the integration works with the following components:
- Server-side: Your POS server communicates with the Revolut Merchant API to create orders, find available terminals, and push payment intents.
- Revolut Terminal: The physical terminal (connected to the internet and in Pay at Counter mode) polls for payment intents assigned to its location and processes customer payments.
- Polling mechanism: Your POS server polls the Merchant API to track the payment status in real-time.
Orders, payment intents, and payments
Before diving into the payment flow, it's important to understand how these three concepts relate to each other:
-
Order: The foundation of any transaction. An order represents what the merchant wants to receive payment for (e.g., items purchased, total amount). Orders can have multiple payment attempts associated with them.
-
Payment intent: The link between an order and the terminal. When you create a payment intent, you're signalling your intention to complete payment for a specific order on a specific terminal. The payment intent allows the terminal to recognise and display the payment request.
-
Payment: The actual payment attempt and its result. Once a customer interacts with the terminal (e.g., inserts their card), a payment is created and processed. Each payment intent can result in one payment.
A payment intent reaching completed status means the checkout process finished on the terminal—but it does not guarantee the payment succeeded. You must check the actual payment status, which can be captured or completed (successful), declined (card rejected), failed (technical error), or cancelled.
Payment flow
- The Revolut Terminal is set to Pay at Counter mode and listens for payment intents assigned to its location.
- A customer is ready to pay at your point of sale.
- Your POS server creates an order via the Merchant API: Create an order endpoint.
- Your POS retrieves available terminals at the same location via the Terminals API.
- Your POS creates a payment intent (payment request), specifying the target terminal.
- The Revolut Terminal polls for and fetches the payment intent assigned to it.
- The Revolut Terminal displays the payment request, and the customer completes the payment.
- Your POS polls the payment intent status until it reaches
completed. - Your POS polls the payment status until it reaches a final state (
captured,completed,declined,failed, orcancelled). - The terminal displays the result to the customer, and your POS displays the result to the merchant staff.
For more information about the order and payment lifecycle in the Merchant API, see: Order and payment lifecycle.
Implementation overview
Check the following high-level overview on how to implement push payments to Revolut Terminal:
- Create or use an existing location
- Create an order
- Find available terminals
- Push payment intent to terminal
- Track payment intent status
- Track payment status
- Display results on POS
Your role as API orchestrator
As a POS software provider integrating with Revolut Terminal, you act as an API orchestrator - making API calls to Revolut's Merchant API on behalf of your merchants. This means merchants will provide their Revolut Merchant API keys to your POS system, and your system will use these keys to create orders, push payment intents, and track payment statuses.
This is a critical security responsibility that requires proper handling of merchant API keys.
Never expose merchant API keys in:
- Frontend/client-side code (JavaScript, mobile apps)
- Browser network requests visible in developer tools
- Application logs or error messages
- Source code repositories (use environment variables instead)
- Plain-text configuration files
Exposing API keys can allow unauthorised parties to create orders, process payments, and access merchant data.
API key management requirements
Collection:
- Collect API keys through secure, encrypted channels (HTTPS)
- Use secure input forms that don't expose keys in browser developer tools or network logs
- Never transmit API keys via email, chat, or other insecure communication methods
- Provide clear instructions to merchants about where to find their API keys and how to securely provide them
Storage:
- Store API keys encrypted at rest using industry-standard encryption (e.g., AES-256)
- Implement strict access controls - limit which systems and personnel can access stored keys
- Store keys in secure credential management systems or vaults
- Never store API keys in plain text in databases, configuration files, or source code
Usage:
- API keys must only be used in your server-side application - never expose keys in client-side code, mobile apps, or browser JavaScript
- Never log API keys in application logs, error messages, or debugging output
- Use environment variables or secure configuration management for production deployments
- Implement monitoring to detect unusual API usage patterns that might indicate compromised keys
Compliance and best practices:
- Follow PCI DSS requirements if you're handling payment card data
- Implement API key rotation procedures to allow merchants to update their keys if compromised
- Provide merchants with the ability to revoke access and update their API keys in your system
- Document your security practices in your POS documentation to give merchants confidence in your integration
If you're unsure about security best practices for API key management, consult with your security team or a security professional before deploying your integration to production.
Before you begin
Before you start this tutorial, ensure you have the followings:
- Apply for a Merchant account
- Generate the API key
- At least one Revolut Terminal device (app version 1.56 or higher) with Pay at Counter mode enabled
- A Point of Sale (POS) application with server-side API capabilities
If you don't have the required Terminal app version, you can update your device by restarting it twice. See Update software for details.
Implement push payments
This section walks you through the exact sequence of API calls needed to process a payment from your POS to a Revolut Terminal.
1. Create or use an existing location
A location is required to link orders in the Merchant API with the physical place where your merchant operates and uses their Revolut Terminal.
- From a business perspective: Locations help you organize your business operations by associating transactions with specific physical stores or points of sale. This is essential for reporting, inventory management, and understanding where your sales are happening.
- From a technical perspective: The Merchant API stores location information and requires you to use the
location_idduring order creation to link that purchase to a specific location. This link is what enables push payments to work—only terminals assigned to the same location can receive payment intents for orders created at that location.
Only physical location types work with push payments. Online locations are not supported for terminal integrations.
You have two options: create a new location or use an existing one.
Use the Create a location endpoint to register a new physical location in the Merchant API.
Request:
POST https://merchant.revolut.com/api/locations
Headers:
| Header | Value |
|---|---|
Authorization | Bearer <your_secret_api_key> |
Revolut-Api-Version | <api_version> |
Content-Type | application/json |
Request body:
Provide the location details including name, type (must be "physical"), and address information.
{
"name": "Example Street Store",
"type": "physical",
"address": {
"street_line_1": "123 Example Street",
"city": "London",
"postcode": "W1B 5TH",
"country_code": "GB"
}
}
Alternatively, you can create locations via the Revolut Business Portal, as described in the Locations section.
In this case, you'll need to retrieve the location ID using the Retrieve location list endpoint.
After obtaining your location's id, make sure your Revolut Terminal is assigned to the same location. You can check and change the terminal's location via More > Settings > General > Locations on the device.
See Additional features: Change the Terminal location for details.
2. Create an order
When a customer is ready to pay at your POS, your server-side application should create an order that captures the purchase details. This order is the foundation of the payment flow—it defines what is being purchased, for how much, and at which location.
Your POS server is responsible for:
- Collecting the checkout details (e.g.,
amount,currency,line_items, etc.) from your POS interface. - Securely calling the Merchant API: Create an order endpoint with these details and your API key.
- Receiving the order details, including the unique
id, back from the Merchant API. - Using this
idin subsequent steps to push the payment intent to a terminal.
Request:
POST https://merchant.revolut.com/api/orders
Headers:
| Header | Value |
|---|---|
Authorization | Bearer <your_secret_api_key> |
Revolut-Api-Version | <api_version> |
Content-Type | application/json |
Request body:
The following fields are required for push payments to work correctly:
| Field | Value | Description |
|---|---|---|
channel | "pos" | Identifies this as a POS transaction (required for push payments). |
location_id | "<your_location_id>" | The location ID from step 1 (links order to terminal location). |
capture_mode | "manual" | Set to manual for controlled capture timing. The terminal will automatically handle capture or cancellation based on the payment outcome. |
fulfilment_type | "eat_in" or "take_away" | Transaction context (required for reporting and compliance). |
metadata.pos_partner_name | "<your_pos_name>" | Your POS software name for tracking and support purposes. |
{
"amount": 2500,
"currency": "GBP",
"channel": "pos",
"location_id": "b9d53717-90e3-462b-8ac1-c6d51bcf497c",
"fulfilment_type": "eat_in",
"capture_mode": "manual",
"metadata": {
"pos_partner_name": "YourPOS"
}
}
You can include additional fields like line_items, customer.email, or description to provide more context in the merchant's Revolut Business dashboard for reporting and customer service purposes.
3. Find available terminals
Before you can push a payment intent, you need to identify which terminal at the location should receive the payment request. This step is performed each time a payment is initiated, allowing staff to dynamically select the appropriate terminal for each transaction (for example, a staff member at a POS station choosing which terminal a colleague should use to accept payment at a customer's table).
Your POS server queries the Merchant API to retrieve a list of terminals that are online, in Pay at Counter mode, and assigned to the same location as your order.
Request:
GET https://merchant.revolut.com/api/terminals?operation_mode=pos&location_id=<location_id>
Headers:
| Header | Value |
|---|---|
Authorization | Bearer <your_secret_api_key> |
Revolut-Api-Version | <api_version> |
Query parameters:
| Parameter | Value | Description |
|---|---|---|
operation_mode | pos | Filters to only return terminals in Pay at Counter mode (required for push payments). |
location_id | <location_id> | The same location_id you used in previous steps. This ensures you only see terminals at that specific location. |
Troubleshooting: No terminals returned
If the API returns an empty list, verify that:
- The terminal is logged in to the correct Revolut Business account
- The terminal is assigned to the same location (matching the
location_idfrom step 1) - Pay at Counter mode is enabled on the terminal (see Enable Pay at Counter mode)
- The terminal is powered on and connected to the internet
4. Push payment intent to terminal
Now that you have both an order and a terminal, you can push the payment intent to the selected terminal. This action sends the payment request to the physical terminal device, where it will be displayed to the customer.
Your POS server sends the payment intent by calling the specified endpoint with:
- The
order_idfrom step 2 (in the URL path) - The
terminal_idfrom step 3 (in the request body) - The
amountto charge (must match the order amount)
Request:
POST https://merchant.revolut.com/api/orders/{order_id}/payment-intents
Request body:
{
"amount": 2500,
"terminal_id": "0e53f673-7705-473a-a263-89a3e7647c3d"
}
At this point, the payment request appears on the Revolut Terminal screen, prompting the customer to present their card or device. The terminal will process the payment and update the payment intent status accordingly.
Cancel a payment intent (optional)
If needed, you can cancel a payment intent while it's still in pending state (before the customer has completed the payment):
Request:
POST https://merchant.revolut.com/api/payment-intents/{payment_intent_id}/cancel
This is useful if the customer changes their mind or if there's an issue with the order before payment is completed.
5. Track payment intent status
After pushing the payment intent to the terminal, you need to monitor its status to know when the customer has completed (or cancelled) the payment. This is done by repeatedly checking the payment intent's state.
What your POS server does:
- Polls the payment intent endpoint using the
payment_intent_idfrom step 4 - Continues polling while the state is
pendingorprocessing - Handles the final state (
completed,cancelled, orfailed) - Extracts the
payment_idwhen payment is completed
Request:
Use the payment_intent_id you saved from step 4:
GET https://merchant.revolut.com/api/payment-intents/{payment_intent_id}
Headers:
| Header | Value |
|---|---|
Authorization | Bearer <your_secret_api_key> |
Revolut-Api-Version | <api_version> |
Payment intent states and actions
| State | Description | Action |
|---|---|---|
pending | Payment intent has been created and sent to the terminal. The customer has not yet started interacting with the terminal. | Continue polling. |
processing | Customer is actively interacting with the terminal (e.g., inserting card, entering PIN). | Continue polling. |
completed | Payment authorization is complete. The response includes a payment_id. | Stop polling. Extract the payment_id and proceed to step 6 to retrieve the final payment status. |
cancelled | Payment intent was cancelled (either by your system calling the cancel endpoint, or by the customer on the terminal). | Stop polling. Handle the cancellation in your system (e.g., notify staff, update order status). You'll need to create a new order if the customer wants to retry. |
failed | Payment intent failed due to technical issues (e.g., timeout, terminal became unavailable, network error). | Stop polling. Handle the error in your system. Check the terminal's availability and connection. You may retry by creating a new payment intent. |
- Poll every second while the state is
pendingorprocessing - Set a reasonable timeout (e.g., 60 seconds) to handle cases where the customer abandons the payment
- When the timeout is reached, consider calling the cancel endpoint and updating your order status accordingly
6. Track payment status
Once the payment intent reaches completed state, you need to poll the payment status until it reaches a final state. The terminal automatically handles the payment capture or cancellation based on the transaction outcome, so your POS should continuously check the payment status until processing is complete.
What your POS server does:
- Retrieves payment details using the
payment_idfrom step 5 - Continuously polls while the payment is in transitional states (
authorised,capture_started,declining,cancelling,failing) - Stops polling when reaching a final state:
captured,completed,declined,failed, orcancelled - Extracts payment method details (card information) for display or receipts
Request:
Use the Retrieve payment details endpoint with the payment_id you saved from step 5:
GET https://merchant.revolut.com/api/payments/{payment_id}
Headers:
| Header | Value |
|---|---|
Authorization | Bearer <your_secret_api_key> |
Revolut-Api-Version | <api_version> |
Payment states and actions
| State | Description | Action |
|---|---|---|
captured | Payment successfully captured. Funds will be transferred to the merchant's account. | Stop polling. Proceed to step 7 to display success message. |
completed | Payment completed successfully (typically for alternative payment methods). | Stop polling. Proceed to step 7 to display success message. |
declined | Payment was declined by the card issuer (e.g., insufficient funds, card blocked). | Stop polling. Display decline message. Customer may retry with a different payment method. |
failed | Payment failed due to technical issues during processing. | Stop polling. Display failure message. Customer may retry. |
cancelled | Payment was cancelled before completion. | Stop polling. Display cancellation message. Customer may retry if needed. |
authorised | Payment authorised, capture in progress. | Continue polling (terminal is processing the capture). |
capture_started | Capture process has started. | Continue polling. |
declining | Decline process in progress. | Continue polling. |
cancelling | Cancellation in progress. | Continue polling. |
failing | Failure process in progress. | Continue polling. |
- Poll every second while the payment is in a transitional state
- Set a reasonable timeout (e.g., 60 seconds) to handle edge cases
- Do not use transitional states for business logic—only use final states to determine the transaction outcome
The payment_method object in the response contains card details that can be useful for displaying on receipts or in your POS interface (e.g., "Visa ending in 4242"). Never log or store full card numbers — only use the provided last_four and other safe fields.
7. Display results on POS
Once the payment reaches a final state, use the payment response data to display the transaction result to merchant staff. The Revolut Terminal automatically displays the result to the customer.
Available data from the payment response:
The payment response from step 6 includes:
state: The final payment state (captured,completed,declined,failed, orcancelled)amountandcurrency: Transaction amountpayment_method: Card details includingcard_brand,card_type, andlast_fourdigitscreated_at,updated_at,completed_at: Timestamps for tracking
Handling different payment states:
Use the state field to determine how to handle the transaction in your POS:
- Success states (
capturedorcompleted): The payment was successful and funds will be transferred. Update your order status accordingly and offer receipt options. - Unsuccessful states (
declined,failed, orcancelled): The payment was not successful. Consider providing an option to retry with a new payment attempt.
Example approaches:
Your POS UI might display information like:
- Successful payments: Transaction confirmation with payment method details (e.g., "Paid with Visa ending in 4242") and receipt options
- Unsuccessful payments: Payment status with an option to create a new transaction
- The terminal shows the result to the customer; your POS display is for merchant staff only
- Use
payment_methoddetails for generating receipts (never log or store full card numbers) - Update order status in your system based on the payment
state
Merchant journey
This section provides context for integrators on how merchants will set up the Revolut Terminal integration with your POS software.
Overview for integrators
As a POS software provider, implementing push payments to Revolut Terminal allows you to offer your merchants a seamless payment acceptance solution using Revolut's physical terminal devices. This integration becomes a key feature of your POS offering.
From a business perspective:
- Your merchants gain access to Revolut Terminal devices without switching POS systems
- You can market "Revolut Terminal support" as a competitive advantage
- Merchants benefit from Revolut's competitive payment processing rates
- You maintain control of the merchant relationship and POS experience
From a technical perspective:
- Your POS software communicates directly with Revolut's Merchant API
- No complex terminal SDKs or drivers are required — it's pure REST API integration
- Your server-side application remains the central hub for order management and business logic
- Terminals operate independently, with your POS pushing payment requests as needed
Documentation requirements:
Once you've implemented this integration, you should update your own POS documentation to guide your merchants through the setup and usage of Revolut Terminal. The merchant setup journey below outlines what your merchants will need to do — this information should be incorporated into your product documentation.
Security requirements:
As a POS provider, you're responsible for securely handling your merchants' Revolut API keys. When merchants provide their API keys during the pairing process, you must:
- Store API keys encrypted at rest using industry-standard encryption
- Only use API keys from your secure server-side application (never in client-side code, browser JavaScript, or mobile apps)
- Never log or expose API keys in application logs, error messages, or network requests
- Implement access controls and monitoring for stored credentials
- Provide merchants with the ability to update or revoke their API keys if needed
For comprehensive security guidelines and best practices, see Your role as API orchestrator.
Merchant API keys provide full access to create orders and process payments. Improper handling of these credentials can lead to unauthorised access to merchant accounts and payment data.
Merchant setup steps
Phase 1: Initial setup and login
-
Merchant logs into POS (on 3rd Party POS) The merchant logs into their third-party Point of Sale application.
-
Merchant logs into Revolut Business (on Revolut Terminal) The merchant logs into their Revolut Business account on the Revolut Terminal and selects a specific location (e.g., "Regent Street, 123 Store").
-
Merchant enables 'Pay at Counter' mode (on Revolut Terminal) The merchant enables 'Pay at Counter' mode in the Revolut Terminal's settings, allowing the integrated POS to push payments to it. For detailed instructions, see Enable Pay at Counter mode.
Phase 2: Device pairing
-
Merchant navigates to POS pairing settings (on 3rd Party POS) The merchant accesses the pairing/integration settings within the POS application and selects the "Revolut Terminal" option.
-
Merchant enters API key (on 3rd Party POS) The merchant enters their Merchant API Secret Key into the POS to authenticate and link their Terminal devices.
Currently, only API key authentication is supported. Additional authentication options may be available in future releases.
Phase 3: Processing payments
-
Merchant initiates order (on 3rd Party POS) The merchant starts a new order on the POS system for a customer who is ready to pay.
-
POS sends payment to Terminal (automated) The merchant selects one of the available Revolut Terminals (logged into the same location) as the payment method. The POS automatically sends the payment request to the selected terminal to be processed.
Implementation checklist
Before deploying your push payments integration to production, complete the checklist below to ensure everything works as expected. You should verify that all checks pass in both the sandbox environment and production environment before rolling out to your merchants.
Testing in sandbox
You can test push payments to Terminal in the sandbox environment using simulated payment scenarios. The sandbox behaves identically to production with the following differences:
API base URL:
- Use
https://sandbox-merchant.revolut.comfor all API calls (instead ofhttps://merchant.revolut.com)
Terminal discovery (Step 3):
- The sandbox returns a single virtual terminal with ID:
11111111-0000-0000-0000-000000000000 - Use this terminal ID when testing payment intent creation
Order amounts for testing scenarios:
Different order amounts trigger specific payment outcomes in sandbox:
| Payment outcome | Amount (minor units) |
|---|---|
| Successful payment | Any amount not listed below |
| Insufficient funds | 3500 or 2000 ≤ amount < 2300 |
| Transaction not allowed for cardholder | 4000 or 2300 ≤ amount < 2500 |
| Suspected fraud | 2500 ≤ amount < 2700 |
Initial setup
- Merchant account is created and API key is generated
- At least one Revolut Terminal device is available (app version 1.56 or higher)
- Physical location is created via the Merchant API or exists in Revolut Business
- Terminal is assigned to the correct location via terminal settings
- Pay at Counter mode is enabled on the terminal
Order creation and terminal discovery
- Your POS server successfully creates orders with required POS fields (
channel: "pos",location_id,capture_mode: "manual",fulfilment_type) - API request includes the correct
location_idmatching your terminal's location - Order creation returns a valid
order_id - Terminal discovery API returns your terminal in the list (with correct
location_idandoperationMode: "pos") - Your POS can handle multiple terminals at the same location (if applicable)
Payment flow
- Push payment intent successfully sends payment to the terminal
- Payment request appears on the Revolut Terminal screen
- Polling logic correctly checks payment intent status every 2-3 seconds
- Polling stops when reaching a final state (
completed,cancelled, orfailed) - Timeout logic is implemented (e.g., 90 seconds) to handle abandoned payments
- Successful payment flow:
- Customer can complete payment on the terminal with a real card
- Payment intent reaches
completedstate - POS polls payment status continuously until reaching final state
- Payment status reaches final success state (
capturedorcompleted) - Terminal automatically displays result to customer
- POS displays transaction result to merchant staff based on payment response data
- Error handling works as expected:
- Declined payments are handled correctly with appropriate messaging
- Failed payment intents are handled with proper error messaging
- Cancelled payments are handled appropriately
- Your POS recovers gracefully from errors
Edge cases and security
- Cancel payment intent endpoint works correctly for pending payments
- Partial capture functionality works as expected (if you use this feature)
- API keys are never exposed in client-side code, mobile apps, or browser JavaScript
- API keys are stored encrypted at rest using industry-standard encryption (e.g., AES-256)
- API keys are never logged in application logs, error messages, or debugging output
- Secure credential management system is implemented for storing API keys (e.g., AWS Secrets Manager, Azure Key Vault, HashiCorp Vault)
- API key collection happens over secure, encrypted channels (HTTPS only)
- Merchants can update or revoke their API keys in your POS system
- Order amounts are validated server-side before creating payment intents
- Your system handles network timeouts and connection errors gracefully
- Terminal unavailability is handled appropriately (no terminals returned scenario)
Documentation and merchant experience
- Your POS documentation includes Revolut Terminal setup instructions
- Merchants understand how to enable Pay at Counter mode
- Merchants understand how to assign terminals to locations
- Merchants understand how to enter API keys in your POS
- Your support team is trained on troubleshooting common issues (e.g., terminal not appearing, payment not showing on terminal)
Testing recommendations
- In production, test with small amounts (e.g., £0.01) and refund immediately after each test (you need to have sufficient funds on your account to process refund fees)
- Test both successful and failed payment scenarios
- Test with multiple terminals at the same location (if applicable)
- Simulate network failures and timeouts to ensure your error handling is robust
- Test the complete flow from order creation through final payment status display
Going live
Once you've completed testing and verified all items in the checklist above, you can roll out the integration to your merchants. Ensure your documentation is updated and your support team is prepared to assist merchants with setup and troubleshooting.
For guidance on testing strategies or if you encounter issues during implementation, contact your Revolut Account Executive.
What's next?
Now that you've implemented push payments to Revolut Terminal, explore these resources to enhance your integration:
- Explore the Merchant API - Discover all available operations and endpoints for order management
- Refund orders - Learn how to process refunds for completed orders
- Retrieve order details - Get detailed information about specific orders
- Work with webhooks - Set up real-time notifications for order and payment events instead of polling
- Order and payment lifecycle - Understand the full payment flow and state transitions
- Get started with Revolut Terminal - Learn how merchants set up and configure Terminal devices
- Manage payments - Understand how merchants handle refunds, receipts, and reports on the Terminal