Connect Retool to Sage Pay (now branded Opayo) via a REST API Resource using Basic Authentication with your integration key and password. Opayo is the UK's leading payment gateway, processing GBP and EUR transactions for British and European businesses. Configure the REST API Resource with Opayo's API base URL and Basic Auth credentials, then query transaction records, process refunds, and manage recurring payment schedules from a unified UK-focused payment operations dashboard.
| Fact | Value |
|---|---|
| Tool | Sage Pay (Opayo) |
| Category | Payment |
| Method | REST API Resource |
| Difficulty | Intermediate |
| Time required | 30 minutes |
| Last updated | April 2026 |
Why connect Retool to Sage Pay (Opayo)?
Opayo (formerly Sage Pay) is the dominant payment gateway for UK businesses, processing billions in GBP and EUR transactions annually. While Opayo provides a My Sage Pay portal for transaction management, it lacks the flexibility that finance and operations teams need for custom reporting, bulk operations, and integration with other business systems. Retool bridging the Opayo API enables UK finance teams to build internal payment operations panels that match their specific workflows rather than adapting to the constraints of the portal.
The most valuable Retool application for Opayo is a transaction search and refund processing dashboard that finance staff use for customer service escalations. When a customer contacts support about a payment issue, the support agent can open the Retool panel, search by card last four digits or transaction reference, view the full transaction history, and initiate a refund with a single click — all without needing access to the Opayo portal with its broader permissions. Retool's permission system means junior support staff can access only the refund functionality while finance managers see all transaction data and reporting.
Opayo's REST API (PI API — Payment Integration API) provides endpoints for transaction operations: retrieving transaction details by transaction ID, processing refunds and repeat payments, and managing payment session data. The API uses sandbox and live environments with different base URLs and separate credential sets, making it safe to test in sandbox before deploying live payment operations to your team.
Integration method
Sage Pay/Opayo connects via Retool's REST API Resource using Opayo's REST API at pi-test.sagepay.com (sandbox) or pi.sagepay.com (live). Authentication uses HTTP Basic Auth with your integration key as the username and integration password as the password — credentials are combined with a colon, Base64-encoded, and sent in the Authorization: Basic header. All requests proxy through Retool's server-side infrastructure, keeping the credentials off the browser. The Opayo API follows standard REST conventions for transaction queries, refund processing, and payment method management.
Prerequisites
- An Opayo (Sage Pay) merchant account with PI API access enabled
- Opayo integration key and integration password (available in the My Sage Pay portal under Settings → Integration)
- Access to Opayo's sandbox environment for testing (sandbox credentials are separate from live credentials)
- Familiarity with Retool's REST API Resource configuration and Basic Auth setup
- A Retool account with Resource creation permissions
Step-by-step guide
Obtain Opayo API credentials and understand the environment setup
Log in to the My Sage Pay portal at mysagepay.com (or the Opayo portal at admin.opayo.co.uk for newer accounts). Navigate to Settings → Integration or the API Settings section. In this section you will find your integration credentials for the PI API (Payment Integration API): an Integration Key (similar to a username) and an Integration Password. These two values together form the Basic Auth credentials for all API calls. Copy both values carefully — they are long alphanumeric strings. Opayo provides two separate sets of credentials: one for the test/sandbox environment and one for the live production environment. Always start with sandbox credentials to test your Retool integration safely before connecting to the live payment environment. The Opayo sandbox uses the base URL https://pi-test.sagepay.com/api/v1 and the live environment uses https://pi.sagepay.com/api/v1. You will create two separate Retool Resources — one for sandbox and one for live — to prevent accidental live transactions during development and testing. Store both sets of credentials in Retool configuration variables: create OPAYO_TEST_KEY, OPAYO_TEST_PASSWORD for sandbox, and OPAYO_LIVE_KEY, OPAYO_LIVE_PASSWORD for live — all marked as secret. The Basic Auth header value is created by Base64-encoding the string 'integration_key:integration_password'. You will configure this in the Retool Resource in the next step.
Pro tip: Opayo's sandbox environment uses test card numbers (available in Opayo's developer documentation) that will not charge real money. Always confirm your Retool queries are hitting the sandbox URL (pi-test.sagepay.com) before switching to the live environment. Add an environment indicator banner to your Retool dashboard so users always know which environment they are viewing.
Expected result: You have your Opayo integration key and integration password for both the sandbox and live environments. Both credential sets are stored as secret configuration variables in Retool.
Configure Opayo REST API Resources in Retool
In Retool, click the Resources tab and click Add Resource. Select REST API from the resource type list. Name the first Resource Opayo API (Sandbox). In the Base URL field, enter https://pi-test.sagepay.com/api/v1. Configure Basic Authentication: in the Authentication section of the resource form, look for an Authentication type dropdown. If Retool shows a Basic Auth option, select it and enter the Integration Key as the username field and the Integration Password as the password field, referencing the configuration variables: {{ config.OPAYO_TEST_KEY }} and {{ config.OPAYO_TEST_PASSWORD }}. If Retool does not show a dedicated Basic Auth option, configure it manually in the Headers section: add an Authorization header with value Basic {{ btoa(config.OPAYO_TEST_KEY + ':' + config.OPAYO_TEST_PASSWORD) }}. However, Retool's {{ }} expressions in resource headers do not support btoa() — you need to pre-compute the Base64-encoded value. Use a JavaScript query in Retool to compute btoa('your_key:your_password') and store the result as a configuration variable OPAYO_TEST_BASIC_AUTH. Then set the Authorization header to Basic {{ config.OPAYO_TEST_BASIC_AUTH }}. Add a second header: Content-Type with value application/json. Click Save to save the sandbox Resource. Repeat this process to create a second Resource named Opayo API (Live) using the live base URL https://pi.sagepay.com/api/v1 and the live credentials OPAYO_LIVE_KEY and OPAYO_LIVE_PASSWORD. Having two separate Resources makes it easy to switch an app between sandbox and live by changing which Resource each query uses.
1// JavaScript query to compute Basic Auth header value2// Run this once to generate the Base64 value for each environment34// For sandbox:5const sandboxAuth = btoa(6 retoolContext.configVars.OPAYO_TEST_KEY + ':' +7 retoolContext.configVars.OPAYO_TEST_PASSWORD8);910// For live (store separately):11const liveAuth = btoa(12 retoolContext.configVars.OPAYO_LIVE_KEY + ':' +13 retoolContext.configVars.OPAYO_LIVE_PASSWORD14);1516return {17 sandbox_basic_auth: sandboxAuth,18 live_basic_auth: liveAuth19};20// Copy the output values and store as:21// OPAYO_TEST_BASIC_AUTH and OPAYO_LIVE_BASIC_AUTH configuration variablesPro tip: Store the pre-computed Base64 Basic Auth strings as separate configuration variables (OPAYO_TEST_BASIC_AUTH and OPAYO_LIVE_BASIC_AUTH) rather than computing them dynamically in the Resource header. This avoids any compatibility issues with expression evaluation in Resource-level headers and makes the auth value immediately visible for debugging.
Expected result: Two Retool REST API Resources are configured — one for sandbox and one for live — each with the correct Opayo base URL and Authorization header with Basic Auth credentials. A test query returns a valid API response from the sandbox environment.
Query transaction records from the Opayo API
Create a query to retrieve transaction data from Opayo. In your Retool app, open the Code panel and click Create new query. Select the Opayo API (Sandbox) Resource. Opayo's PI API structure focuses on transaction management rather than bulk reporting — to retrieve a specific transaction, you query /transactions/{transactionId}. For searching transactions by date or status, you may need to use Opayo's reporting API or rely on your own database records of Opayo transaction IDs to look up each one individually. Set Method to GET. In the Path field, enter /transactions/{{ transactionIdInput.value }} to look up a specific transaction by ID. Add a text input component named transactionIdInput to the canvas for entering the transaction ID. Alternatively, if you maintain a database of your Opayo transaction IDs alongside customer records, create a database query first to fetch the list of relevant transaction IDs (by customer email, date range, or amount), then use a Retool Workflow or looped JavaScript query to fetch each transaction's details from Opayo and merge them into a unified dataset. Run a test query with a known sandbox transaction ID to see the response structure — Opayo returns a JSON object with status, statusCode, statusDetail, transactionId, merchantSessionKey, amount, currency, and card payment details.
1// JavaScript transformer for Opayo transaction detail response2const txn = data || {};3const payment = txn.paymentMethod?.card || {};45return {6 transaction_id: txn.transactionId || '',7 merchant_session_key: txn.merchantSessionKey || '',8 status: txn.status || '',9 status_code: txn.statusCode || '',10 status_detail: txn.statusDetail || '',11 amount_pence: txn.amount?.totalAmount || 0,12 amount_display: txn.amount?.totalAmount13 ? `£${(txn.amount.totalAmount / 100).toFixed(2)}`14 : 'N/A',15 currency: txn.amount?.currency || 'GBP',16 card_type: payment.cardType || '',17 card_last_four: payment.lastFourDigits || '****',18 card_expiry: payment.expiryDate || '',19 cardholder_name: payment.cardholderName || '',20 billing_address: txn.billingAddress21 ? [txn.billingAddress.address1, txn.billingAddress.city, txn.billingAddress.postalCode].filter(Boolean).join(', ')22 : '',23 created_at: txn.createdAt || txn.date || '',24 avs_check: txn.avsCvcCheck?.address || 'N/A',25 cvc_check: txn.avsCvcCheck?.securityCode || 'N/A',26 is_refundable: txn.status === 'Ok' && (txn.amount?.totalAmount || 0) > 027};Pro tip: Opayo's PI API returns monetary amounts in pence (GBP) or cents (EUR) — divide by 100 to get pounds or euros. For example, an amount of 1999 represents £19.99. Verify this against a known transaction in the Opayo portal before displaying amounts to users.
Expected result: A transaction lookup query successfully retrieves and transforms transaction details from the Opayo sandbox API, showing formatted amount in GBP, masked card details, transaction status, and AVS/CVC check results.
Build the transaction search and refund processing UI
With the transaction query working, build the payment operations dashboard. At the top of the canvas, add a search area in a Container: add a Text Input named transactionIdInput labeled Transaction Reference, a second Text Input for customer email (if your database can translate email to transaction IDs), and a Button labeled Look Up Transaction. Below the search area, add a detail Container that shows transaction details when a transaction is found. Bind each text field in the container to the properties of the transaction query result — txn.status_display, txn.amount_display, txn.card_last_four, etc. Add a status indicator: use a Tag component with green color for 'Ok' status and red for 'NotAuthed' or failed statuses. Add a second Container for the Refund section that appears only when txn.is_refundable is true (bind the container's Show property to {{ getTransaction.data.is_refundable }}). Inside the refund container, add a Number Input labeled Refund Amount (£) with a max value constraint set to the original transaction amount. Add a Text Area labeled Reason for Refund. Add a Button labeled Process Refund that is wired to a POST query targeting /transactions/{{ transactionIdInput.value }}/refund. The refund query body should include: transactionType: 'Refund', amount: {{ Math.round(refundAmountInput.value * 100) }} (converting pounds to pence), currency: 'GBP', description: {{ refundReasonInput.value }}, and parentTransactionId: {{ transactionIdInput.value }}. Add a Modal confirmation dialog before submitting the refund — the user must confirm the amount and reason before the actual API call fires.
1// POST query body for Opayo refund2// Method: POST3// Path: /transactions4// Body type: JSON5{6 "transactionType": "Refund",7 "amount": {{ Math.round(refundAmountInput.value * 100) }},8 "currency": "GBP",9 "description": "{{ refundReasonInput.value }}",10 "parentTransactionId": "{{ getTransaction.data.transaction_id }}",11 "vendorTxCode": "REFUND-{{ Date.now() }}"12}Pro tip: Opayo refunds require a unique vendorTxCode for each refund transaction — use a combination of the original transaction ID and a timestamp to generate a unique value automatically. If you submit a refund with a vendorTxCode that has been used before, Opayo will reject it with an error about duplicate transaction codes.
Expected result: A complete transaction search and refund dashboard shows: a search area with transaction ID input and Look Up button, a transaction detail panel with masked card data and status, and a conditional refund panel that appears for refundable transactions. A confirmation modal protects against accidental refund submissions.
Add recurring payment management and environment switching
Extend the dashboard to handle recurring payment management — a common need for subscription businesses using Opayo. Create a query at /tokens to retrieve saved payment tokens (card-on-file records linked to customer references). Display tokens in a Table with customer reference, card type, masked card number, and expiry date. Add a Repeat Payment button for selected tokens that triggers a POST to /transactions with transactionType: 'Repeat', referencing the stored token. For the live vs. sandbox environment switch, add a Toggle or Select component at the top of the dashboard labeled Environment with options Sandbox and Live. Create separate query versions that reference either the Opayo sandbox Resource or the live Resource based on the toggle value — or use the toggle value to drive a conditional in a wrapper JavaScript query that selects the appropriate Resource. Add a prominent warning banner that changes from gray to red when the Live environment is selected to prevent accidental live transactions during testing. For UK businesses processing high volumes or needing custom authorization flows, token vaulting integrations, and 3D Secure v2 compliance reporting in Retool, RapidDev can help architect the complete Opayo payment operations solution.
1// POST query body for Opayo repeat payment using stored token2// Method: POST3// Path: /transactions4{5 "transactionType": "Repeat",6 "amount": {{ repeatAmountInput.value * 100 }},7 "currency": "GBP",8 "description": "{{ repeatDescriptionInput.value }}",9 "parentTransactionId": "{{ tokensTable.selectedRow.transaction_id }}",10 "vendorTxCode": "REPEAT-{{ tokensTable.selectedRow.customer_ref }}-{{ Date.now() }}",11 "statementReference": "{{ statementRefInput.value || 'Subscription renewal' }}"12}Pro tip: When switching between sandbox and live environments in Retool, add a query run confirmation step that reminds users they are about to execute against the live environment. The 'Require confirmation to run' option in Retool's query settings provides this safety check without requiring a custom modal.
Expected result: The dashboard includes a recurring payment management Table with token details and repeat payment functionality. An environment toggle with a visual warning indicator allows safe switching between sandbox and live environments with clear feedback about which environment is active.
Common use cases
Transaction search and refund processing dashboard
Build a Retool payment operations panel where finance and support staff can search for transactions by reference number, customer email, or date range. Display matching transactions in a Table with transaction ID, amount, currency, status, card type, and card last four digits. For completed transactions, add a Refund button that opens a modal with amount field and reason, then submits a refund request to Opayo. Require confirmation before processing and show the refund status result.
Build a Retool Opayo payment dashboard with a transaction search panel at the top (text input for transaction ID or customer email, date range picker, status filter). Show results in a Table with transaction ID, amount (GBP), status, card type, and card last four. Add a Refund button on selected rows that opens a modal for entering refund amount and reason, then POSTs to the Opayo refund endpoint.
Copy this prompt to try it in Retool
Daily settlement reconciliation report
Create a Retool panel that pulls the day's transaction data from Opayo and reconciles it against expected settlement amounts. Query all transactions for the current day, group by status (approved, declined, refunded), and display totals in Stat components. Show a Table of all transactions for the day sorted by time. Add an export button to download the daily transaction report as CSV for the finance team's reconciliation process.
Build a Retool daily settlement dashboard that queries Opayo transactions for a selected date. Show Stat components for total approved amount, total declined count, total refunded amount, and net settlement amount. Display all transactions in a Table sorted by transaction time descending with amount, status, card type, and reference. Add a CSV export button.
Copy this prompt to try it in Retool
Recurring payment and subscription management panel
Build a Retool panel for managing recurring payment mandates. Query active recurring payment tokens from Opayo, display them with customer reference, card details (masked), and next payment date. Allow finance staff to update billing dates, cancel mandates, or trigger manual repeat payments. Include a history view showing all past repeat transactions for a selected mandate alongside the mandate status.
Build a Retool recurring payment manager that queries Opayo for active payment mandates. Show a Table with customer reference, card type, masked card number, mandate status, and last payment date. Add actions for cancelling a mandate and triggering a manual repeat payment. Include a selected mandate detail panel showing the last 12 payment attempts with their status and amounts.
Copy this prompt to try it in Retool
Troubleshooting
API returns 401 Unauthorized with message 'Invalid vendor' or 'Authentication failed'
Cause: The Basic Auth header value is incorrect — the integration key and password may be swapped, the Base64 encoding is wrong, or the credentials belong to the wrong environment (test vs. live).
Solution: Verify the Authorization header value using the pre-computation JavaScript query from Step 2 — ensure the format is Basic {Base64(integration_key:integration_password)} with the integration key as the username. Double-check that sandbox credentials are being used with the sandbox URL (pi-test.sagepay.com) and live credentials with the live URL (pi.sagepay.com). Regenerate the Base64 string from scratch using a known-good online tool and compare against what is stored in the configuration variable.
1// Verify the Base64 encoding2const key = 'your_integration_key';3const password = 'your_integration_password';4console.log(btoa(key + ':' + password));5// This value should match OPAYO_TEST_BASIC_AUTH in config varsRefund query returns '3073 - The Transaction cannot be REFUNDED' error
Cause: Opayo only allows refunds on transactions with 'Ok' status that have been settled. Transactions that are still in a pending settlement state, have already been fully refunded, or have a status other than 'Ok' cannot be refunded via the API.
Solution: Check the original transaction's status in the Opayo portal to confirm it has settled. Ensure the refund amount does not exceed the original transaction amount minus any previous refunds. Wait 24-48 hours after the original transaction if it was very recent — Opayo requires transactions to complete settlement before they can be refunded.
API returns '5009 - Duplicate vendorTxCode' when submitting a refund
Cause: The vendorTxCode submitted with the refund has already been used for a previous transaction or refund. Each transaction request must have a unique vendorTxCode.
Solution: Update the refund query body to generate a unique vendorTxCode using a timestamp and the original transaction ID: 'REFUND-' + parentTransactionId + '-' + Date.now(). This ensures uniqueness even if the same transaction is refunded multiple times (partial refunds).
1// Unique vendorTxCode pattern2const vendorTxCode = `REFUND-${getTransaction.data.transaction_id}-${Date.now()}`;3// Use this value in the refund POST bodyTransaction amounts display as very large numbers (e.g., £199900 instead of £1,999.00)
Cause: Opayo stores amounts in pence (smallest currency unit), not pounds. The transformer is displaying raw pence values without dividing by 100.
Solution: Update the transformer to divide all amount values by 100 before formatting as currency: const amountPounds = (txn.amount?.totalAmount || 0) / 100; then format as £${amountPounds.toFixed(2)}. This converts pence to GBP correctly.
1// Correct pence to pounds conversion2const amountPounds = (txn.amount?.totalAmount || 0) / 100;3return `£${amountPounds.toFixed(2)}`;4// Do NOT skip the / 100 divisionBest practices
- Always create separate Retool Resources for Opayo sandbox and live environments, and add a clear visual indicator (color banner or environment label) so users always know which environment is active — accidentally processing live refunds in what you thought was a sandbox is a serious operational risk.
- Store Opayo integration credentials (key and password) in Retool configuration variables marked as secret for both sandbox and live environments — Basic Auth credentials must never appear in query configurations that team members can view.
- Pre-compute the Base64-encoded Basic Auth string and store it as a configuration variable rather than computing it dynamically in the Resource header — this avoids potential expression evaluation issues and makes the auth value immediately verifiable.
- Add a confirmation modal before any refund or repeat payment action — Retool's built-in confirmation dialog (query → Require confirmation to run) provides this safety gate with minimal configuration.
- Validate that refund amounts do not exceed the original transaction amount in your Retool form — use a Number Input max value constraint set to {{ getTransaction.data.amount_raw / 100 }} to prevent over-refund attempts before they reach the Opayo API.
- Remember that Opayo amounts are always in the smallest currency unit (pence for GBP, cents for EUR) — multiply pounds/euros by 100 for any amount you send to the API, and divide by 100 for any amount you display from the API.
- Generate unique vendorTxCodes for all transaction requests using a timestamp or UUID pattern — duplicate vendorTxCode errors are common when refund buttons are clicked multiple times or when retry logic is not properly implemented.
Alternatives
Stripe is a global payment platform with a more developer-friendly API and a native Retool connector, making it better suited for international businesses and new integrations, while Opayo is preferred by established UK businesses already using the Sage Pay infrastructure.
Worldpay is a global enterprise payment processor serving high-volume merchants across multiple markets, while Opayo is UK-focused and better suited for mid-market British businesses.
Adyen is a modern unified commerce platform with a comprehensive REST API and global payment capabilities, making it the preferred choice for businesses looking to consolidate payment processing across markets rather than using a UK-specific gateway.
Frequently asked questions
What is the difference between Sage Pay and Opayo?
Sage Pay was the original brand name of the UK payment gateway founded in 2001. In 2020, Elavon (a US Bancorp subsidiary) acquired Sage Pay and rebranded it as Opayo. The payment gateway technology, API, and merchant accounts are the same — Opayo is simply the current brand name. You may see both names in documentation and integrations; they refer to the same service.
Does Opayo provide a dedicated sandbox environment for testing?
Yes. Opayo provides a sandbox test environment at pi-test.sagepay.com with its own set of test credentials (separate from your live integration key and password). The sandbox accepts Opayo's published test card numbers and processes simulated transactions without moving real money. Always test your Retool integration against the sandbox before switching to the live environment credentials.
Can I query all transactions for a date range through the Opayo PI API?
The Opayo PI API is designed around individual transaction operations (look up by transaction ID, process refunds, manage tokens) rather than bulk reporting queries. For date-range transaction reporting, use the My Opayo portal's reporting section or export transaction data from the portal to your own database, then query that database from Retool for date-range analysis. The API works best for operational lookups and actions on known transaction IDs.
How does Opayo handle 3D Secure v2 (SCA) for European payments?
Opayo supports 3D Secure v2 as required by the Strong Customer Authentication (SCA) regulations under PSD2. For API-initiated transactions (like repeat payments from Retool), Opayo applies transaction risk analysis to determine whether step-up authentication is required. Server-to-server transactions from Retool that are genuine repeat payments (using a parentTransactionId from a previously authenticated transaction) typically qualify for SCA exemptions. Consult Opayo's developer documentation for the specific SCA parameters required in your transaction requests.
Is it possible to use Opayo for multi-currency transactions beyond GBP?
Yes. Opayo supports multiple currencies including EUR, USD, and others depending on your merchant account configuration. Specify the currency code in the amount object of your transaction request using the three-letter ISO 4217 currency code (e.g., 'EUR'). Your Opayo merchant account must be configured to accept the target currency — contact Opayo support to enable additional currencies on your account. All amounts are sent and returned in the currency's smallest unit (cents for EUR, pence for GBP).
Talk to an Expert
Our team has built 600+ apps. Get personalized help with your project.
Book a free consultation