SEPA Direct Debit server-to-server integration
Collect payments directly from your customers' EUR bank accounts using server-to-server API calls — no hosted checkout widget required.
The Single Euro Payments Area (SEPA) is a European Union initiative that standardises payments within and across member countries. SEPA Direct Debit (SDD) lets merchants collect payments directly from customers' EUR-denominated bank accounts — making it a popular choice for subscriptions, recurring billing, and any flow where your platform manages payment mandates directly. Revolut supports the SEPA Direct Debit Core scheme, which covers both personal and business bank accounts across the SEPA region.
This guide will help you integrate with the Revolut Merchant API to accept SEPA Direct Debit payments through direct server-to-server API calls, without relying on a checkout widget. To debit an account, you collect the customer's name and IBAN, obtain a signed mandate authorising the debit, then submit the payment from your backend.
How it works
From an implementation perspective, integrating SEPA Direct Debit with Revolut involves the following components:
- Server-side: You set up endpoints on your server that create orders and submit payments using the Revolut Merchant API.
- Mandate management: You collect SEPA Direct Debit mandates from your customers and store them securely. Revolut does not manage mandates on your behalf.
- Webhooks: You set up an endpoint to receive webhook events from the Merchant API. Unlike card payments, SEPA Direct Debit is fully asynchronous — payment outcomes can arrive up to 5 business days after submission. Webhooks are mandatory, not optional.
The order and payment flow is as follows:
- Order creation: Your backend creates an order via the Revolut Merchant API and obtains the order ID.
- Mandate collection: Your platform collects the customer's IBAN and mandate consent. You are responsible for compliance with SEPA mandate requirements.
- Payment submission: Your backend submits the payment request with the debtor's IBAN and name (or a saved payment method ID).
- Asynchronous processing: Revolut submits the debit instruction to the SEPA scheme. No polling is required.
- Webhook notification: Your server receives a webhook when the payment is completed or declined — this can take from a few hours to up to 5 business days.
For more information about the order and payment lifecycle, see: Order and payment lifecycle.
Implementation overview
Check the following high-level overview on how to implement SEPA Direct Debit integration:
- Create an order
- Collect a SEPA mandate
- Handle SEPA mandate and notification rules
- Create a payment request
- Handle payment outcomes via webhooks
Before you begin
Before you start this guide, ensure you have completed the following steps:
- Get started: 1. Apply for a Merchant account
- Get started: 2. Generate the API keys
- Obtained a valid SEPA Creditor ID
- Contacted your account executive to have SEPA Direct Debits enabled on your merchant account
- Shared your Creditor ID with Revolut
- Confirmed you can collect, store, and manage SEPA Direct Debit mandates in compliance with SEPA guidelines
- Set up a process to send pre-debit notifications to customers as required by SEPA rules
Implement SEPA Direct Debit integration
1. Create an order
Create an order from your backend forwarding the data collected during checkout, and including your Secret API key in the authorisation header. We recommend creating the order when the customer is at your checkout and you are ready to initiate the payment.
Send a POST request to the Create an order endpoint with the order details:
{
"amount": 100,
"currency": "EUR",
"customer": {
"email": "customer@example.com"
}
}
SEPA Direct Debit payments are denominated in EUR only.
| Parameter | Description | Required |
|---|---|---|
amount | The order amount in the smallest currency unit (cents). For €1.00, use 100. | Yes |
currency | Must be EUR for SEPA Direct Debit payments. | Yes |
customer | Customer details. Pass email for new customers or id for existing customers. Required if you want to save the payment method for future use. | No |
For complete details on all available parameters, see: Merchant API: Create an order.
Once the order is created, extract the id from the response — you will use it as order_id in Step 4:
{
"id": "64d38f09-d04e-a9b5-b394-991f8a527eb3",
"token": "1112e405-c0b1-4a3f-a50d-e8acd66c7a8e",
"type": "payment",
"state": "pending",
"created_at": "2023-08-09T13:05:13.697830Z",
"updated_at": "2023-08-09T13:05:13.697830Z",
"capture_mode": "automatic",
"amount": 100,
"currency": "EUR",
"outstanding_amount": 100,
"checkout_url": "https://checkout.revolut.com/payment-link/999515ab-be9e-4477-b879-85b85c1576c1"
}
2. Collect a SEPA mandate
Before initiating any SEPA Direct Debit payment, you must collect a valid mandate from your customer. A mandate is your customer's explicit authorisation for you to debit their bank account.
Collect the following information and store it securely in your system:
| Mandate field | Description |
|---|---|
| Customer name | The account holder's name as it appears on their bank account |
| IBAN | The customer's International Bank Account Number |
| Mandate consent | The customer must explicitly agree to the SEPA Direct Debit terms before any debit is initiated |
Never send IBAN or mandate data directly from your frontend to Revolut.
Always route it through your backend server.
You are responsible for ensuring that each mandate contains all mandatory SEPA fields and is accepted by the customer before any payment is submitted. For full details on mandate storage and compliance requirements, see Step 3.
3. Handle SEPA mandate and notification rules
SEPA rules impose obligations on you as a merchant before and after initiating any direct debit. You are fully responsible for compliance — Revolut does not manage mandates or send pre-notifications on your behalf.
Mandate management
| Requirement | Details |
|---|---|
| Mandatory fields | Debtor name, IBAN, creditor identifier, mandate reference, customer consent |
| Storage | Store mandates securely for as long as they remain valid and for at least 14 months after the last collection |
| Mandate reference | Revolut generates a unique mandate reference number and returns it in the payment response. Use this reference in pre-debit notifications sent to your customers. |
| Revocation | Provide customers with a clear process to cancel or revoke their mandate |
| Signed mandate delivery | Share a copy of the signed mandate with the customer as required by SEPA guidelines. In the event of a dispute, you may be asked to submit the mandate and evidence of its delivery. |
| Audit readiness | Be prepared to provide proof of mandate authorisation if challenged by the debtor's bank |
Pre-notification requirements
You must notify the customer before each debit. Send the pre-notification at least 14 calendar days before the debit date, unless you have contractually agreed to a shorter period with the customer.
Each notification must include:
| Required content | Details |
|---|---|
| Last 4 digits of IBAN | The last 4 digits of the debtor's bank account number |
| Mandate reference | The unique reference number of the mandate |
| Debit amount | The amount to be debited |
| Creditor identifier | Your SEPA creditor identifier |
| Contact information | Your business contact details |
For subscriptions with fixed amounts and regular dates, a single pre-notification can cover multiple future collections if the schedule is clearly communicated.
If anything in the mandate changes — amount, date, or any other terms — you must collect a new mandate from the customer. Revolut does not support mandate updates.
Submission deadlines
| Payment type | Submit instructions to Revolut by |
|---|---|
| First or single SDD | At least 5 business days before the requested payment date |
| Recurring SDD | At least 2 business days before the requested payment date |
If instructions are submitted after the deadlines above, the payment may be processed later than your intended date.
4. Create a payment request
Once the order is created and the mandate has been collected, submit a payment request from your backend.
Send a POST request to the Pay for an order endpoint, passing id returned from Step 1: Create an order as {order_id}.
There are two ways to submit a SEPA Direct Debit payment request, depending on whether you are charging a customer for the first time or using a payment method they have previously authorised:
For the first payment from a customer, pass the debtor's IBAN and name directly. Pass save_for: merchant to save this payment method for future recurring charges without requiring the customer to re-enter their details.
{
"payment_method": {
"type": "sepa_direct_debit",
"debtor_iban": "DE12345678901234567890",
"debtor_name": "John Doe",
"billing_address": {
"street_line_1": "Example Street 123",
"street_line_2": "II/123",
"region": "London",
"city": "London",
"country_code": "GB",
"postcode": "123456"
},
"save_for": "merchant"
}
}
Payment request object:
| Parameter | Description | Format | Required |
|---|---|---|---|
payment_method | Payment method details for initiating a payment request. | Object | Yes |
payment_method object:
| Parameter | Description | Format | Required |
|---|---|---|---|
type | The type of payment method. Must be sepa_direct_debit. | String | Yes |
debtor_iban | The customer's IBAN. | String | Yes |
debtor_name | The account holder's name. | String | Yes |
billing_address | The customer's billing address. | Object | No |
save_for | Pass merchant to save the payment method for future merchant-initiated charges. | String | No |
billing_address object:
| Parameter | Description | Required |
|---|---|---|
street_line_1 | Street line 1 information. | No |
street_line_2 | Street line 2 information. | No |
region | The region associated with the address. | No |
city | The city associated with the address. | No |
country_code | The country associated with the address (ISO 3166-1 alpha-2). | Yes |
postcode | The postcode associated with the address. | Yes |
After submitting, the payment response will return with state: pending. This is expected — the payment is now queued for submission to the SEPA scheme.
{
"id": "d4aa447c-b9ef-4a0b-86ac-59bc4e8d590e",
"token": "74d501db-3abe-4bdb-bef2-9a73e01f8a13",
"order_id": "64d38f09-d04e-a9b5-b394-991f8a527eb3",
"state": "pending",
"amount": 100,
"currency": "EUR",
"payment_method": {
"type": "sepa_direct_debit",
"debtor_iban_last_four": "7890",
"debtor_name": "John Doe",
"mandate_reference": "69E6085A8B8FA31BBB82E833650700AD"
}
}
Store the following values from the response for later use:
| Field | What to do |
|---|---|
payment_method.id | Use as the saved_payment_method.id in subsequent recurring payment requests. Not returned in the pending state — retrieve it from the payment after receiving the ORDER_COMPLETED webhook. |
payment_method.mandate_reference | Include in pre-debit notifications sent to your customers as required by SEPA rules. |
5. Handle payment outcomes via webhooks
Once the payment request is submitted, processing moves entirely to the backend — no polling is required. SEPA Direct Debit payments follow a multi-day settlement process: after Revolut submits the debit instruction to the scheme, there is a refusal window during which the debtor's bank can return the payment.
Most outcomes — whether completed or declined — can arrive up to 5 business days after submission. Do not assume a pending state means the payment has failed, and do not fulfil orders until you receive a final webhook event.
For SEPA Direct Debit, webhooks are not optional. Your backend must be set up to receive and process webhooks before you go live.
Set up your webhook endpoint by subscribing to the following events via the Create a webhook endpoint:
ORDER_COMPLETED, ORDER_PAYMENT_DECLINED, ORDER_PAYMENT_FAILED, ORDER_CANCELLED
For detailed information on setting up webhooks, see: Use webhooks to track order and payment lifecycle.
Handle the following scenarios:
The payment has been captured and completed.
Webhook expected:
| Webhook event | Description |
|---|---|
ORDER_COMPLETED | The payment has been captured and completed |
What to do:
Fulfil the order (ship goods, grant access, etc.) once ORDER_COMPLETED is received.
If you passed save_for: "merchant" in the initial payment request, also retrieve the payment after ORDER_COMPLETED to obtain payment_method.id — store it for subsequent recurring payment requests.
Implementation checklist
Before deploying your implementation to your production environment, complete the checklist below:
Account setup
- Obtained a valid SEPA Creditor ID.
- Contacted your account executive to have SEPA Direct Debits enabled on your merchant account.
- Shared your Creditor ID with Revolut.
API integration
- Successfully created an order using the Merchant API and extracted the order
id.
Mandate management
- Mandates collected with all mandatory SEPA fields: debtor name, IBAN, creditor identifier, and customer consent.
- Mandates stored securely for at least 14 months after the last collection.
- Mandate reference extracted from the payment response and stored for use in pre-debit notifications.
Notifications & timing
- Pre-notification workflow in place: customers notified at least 14 calendar days before each debit.
- First or single SDD instructions submitted at least 5 business days before the payment date.
- Recurring SDD instructions submitted at least 2 business days before the payment date.
Webhook handling
- Webhook endpoint configured and subscribed to
ORDER_COMPLETED,ORDER_PAYMENT_DECLINED,ORDER_PAYMENT_FAILED,ORDER_CANCELLED. - Backend implementation handles delayed webhook delivery (payment outcomes can arrive up to 5 business days after submission).
- Error handling implemented for declined payments with appropriate customer-facing messaging.
- (If saving payment methods for recurring use) Payment retrieved after
ORDER_COMPLETEDto obtainpayment_method.id, and stored securely for subsequent recurring payment requests.
SEPA Direct Debit is not available in the Sandbox environment. Integration testing requires a production merchant account with SEPA Direct Debits enabled.
Congratulations! You've successfully integrated SEPA Direct Debit with the Revolut Merchant API.
Disputes
SEPA Direct Debit provides a dispute process through which customers can challenge payments with their bank.
Unconditional dispute window (up to 8 weeks)
Customers can dispute any SEPA Direct Debit payment through their bank within 8 weeks of being debited, without providing a reason. Disputes within this period are automatically honoured.
Unauthorised payment claims (8 weeks to 13 months)
After 8 weeks and up to 13 months, a customer can dispute a payment only on the grounds that it was unauthorised. When Revolut receives a dispute notification from the SEPA scheme, it is automatically booked as lost.
SEPA Direct Debit disputes are final — there is no appeal process. If a customer successfully disputes a payment, you must contact them directly to resolve the situation. If they agree to return the funds, they must initiate a new payment.
If a dispute is raised against a payment associated with a mandate, that mandate may be deactivated. Check the mandate status after any dispute and re-collect consent from the customer if their mandate is no longer active.
You can view and monitor SEPA Direct Debit disputes programmatically using the Disputes API.
SEPA Direct Debit disputes cannot be challenged. When Revolut receives a dispute from the SEPA scheme, it is automatically booked as lost - there is no response or evidence submission process.
Refunds
You can refund SEPA Direct Debit payments for up to 5 days after receiving the ORDER_COMPLETED webhook — full amount only. Refunds are free, but processing fees for the original payment are non-refundable.
To issue a refund, use the Refund an order endpoint.
For full details on issuing refunds, see: Refunds.
Timing
Refunds typically take 3-4 business days to process. Funds appear in the customer's account within 5 business days. SEPA refunds appear as credits on the customer's bank statement with a reference to the original payment — they are not explicitly labelled as refunds.
Always notify the customer when issuing a refund and inform them that it may take up to 5 business days to appear in their account.