# SEPA direct debit for Unified Payments API To process a SEPA Direct Debit payment: 1. [Set up the mandate](#Set_up_the_mandate) with your customer to obtain their consent.
If you have an existing mandate ID, you can skip this step. 2. [Send the customer a pre-notification](#Send_a_pre-notification) of your intent to charge their account. - Optionally, you can [Create a SEPA payment source](#Create_a_SEPA_payment_source_) to store the mandate to use in a recurring payment series. 4. [Request the payment](#Request_a_payment). ## Set up the mandate To comply with [European Payments Council (EPC)](https://www.europeanpaymentscouncil.eu/what-we-do/epc-payment-schemes/sepa-direct-debit/sepa-direct-debit-core-rulebook-and-implementation) requirements, you must set up a mandate to obtain the bank account owner's consent before you can collect SEPA debit payments from their account. See [Move your existing mandates](https://www.checkout.com/docs/payments/add-payment-methods/sepa-direct-debit.md#Move_your_existing_mandates) if you have an existing mandate that you want to migrate to Checkout.com. Checkout.com enables you to store this information as a payment instrument, and generates a `mandate_id` for you to reference in later payments. --- ## Send a pre-notification To comply with [EPC requirements](https://www.europeanpaymentscouncil.eu/what-we-do/sepa-direct-debit/sepa-direct-debit-core-rulebook), you must send the customer a pre-notification before debiting any funds from their account. See [SEPA payment flow](https://www.checkout.com/docs/payments/add-payment-methods/sepa-direct-debit.md#SEPA_payment_flow) for more information. --- ## Create a SEPA payment source `Optional` If you want to store the mandate to use in a recurring payment series, you can create a SEPA payment source. You can create the SEPA payment source at any of the following moments: - [Before you perform your first payment request](#Create_a_payment_source_before_your_first_payment) - [At the same time as you perform your first payment request](#Create_a_payment_source_with_your_first_payment_request) ### Create a payment source before your first payment In the `instrument_data.type` field, specify the mandate you want to use: - `Core` - `B2B` ### Request example **Core** ```json { "type": "sepa", "instrument_data": { "type": "Core", "account_number": "FR7630006000011234567890189", "currency": "EUR", "country": "FR", "payment_type": "Regular", "date_of_signature": "2025-03-22" }, "account_holder": { "first_name": "Ali", "last_name": "Farid", "billing_address": { "address_line1": "Rue Exemple", "address_line2": "1", "city": "Paris", "zip": "75000", "country": "FR" } } } ``` **B2B** For a B2B request, you must set: - `"instrument_data.type": "B2B"` - `"account_holder.type": "corporate"` - `account_holder.company_name` to the company name from whose account you plan to debit. ```json { "type": "sepa", "instrument_data": { "type": "B2B", "account_number": "FR7630006000011234567890189", "currency": "EUR", "country": "FR", "payment_type": "Regular", "date_of_signature": "2025-03-22" }, "account_holder": { "type": "Corporate", "company_name": "Software Company", "billing_address": { "address_line1": "Rue Exemple", "address_line2": "1", "city": "Paris", "zip": "75000", "country": "FR" } } } ``` ### Response example ```json { "type": "sepa", "id": "src_wmlfc3zyhqzehihu7giusaaawu", "fingerprint": "vnsdrvikkvre3dtrjjvlm5du4q" } ``` The `id` returned represents the saved instrument containing your mandate ID. To retrieve the mandate ID, call the [Get instrument details](https://api-reference.checkout.com/tag/Instruments/#operation/getInstrumentDetails) endpoint. > **Information** > > There may be a short delay between when you create the instrument, and when the mandate ID is returned in the response. You receive an instrument ID, which you can reuse as the `source` in future payment requests. ### Create a payment source with your first payment request Call the [Request a payment](https://api-reference.checkout.com/tag/Payments/#operation/requestAPaymentOrPayout) endpoint to create a SEPA payment. In the `instrument_data.type` field, specify the mandate you want to use: - `Core` - `B2B` > **Information** > > Your base URL's `{prefix}` value is unique to your account and environment. To learn how to retrieve your base URLs for the sandbox and production environments, see [API endpoints](https://www.checkout.com/docs/developer-resources/api/api-endpoints.md). **Production** `POST` `https://{prefix}.api.checkout.com/payments` **Sandbox** `POST` `https://{prefix}.api.sandbox.checkout.com/payments` #### Request example **Core** ```json { "source": { "type": "sepa", "country": "FR", "account_number": "FR7630006000011234567890189", "currency": "EUR", "mandate_id": "123456", "mandate_type": "Core", "date_of_signature": "2022-08-22", "account_holder": { "first_name": "Ali", "last_name": "Farid", "billing_address": { "address_line1": "Rue Exemple", "address_line2": "1", "city": "Paris", "zip": "75000", "country": "FR" } } }, "payment_type": "Regular", "amount": 10000, "currency": "EUR", "processing_channel_id": "pc_xyz", "success_url": "https://example.com/payments/success", "failure_url": "https://example.com/payments/failure" } ``` **B2B** For a B2B request, you must set: - `"instrument_data.type": "B2B"` - `"account_holder.type": "corporate"` - `account_holder.company_name` to the company name from whose account you plan to debit. ```json { "source": { "type": "sepa", "country": "FR", "account_number": "FR7630006000011234567890189", "currency": "EUR", "mandate_id": "123456", "mandate_type": "B2B", "date_of_signature": "2022-08-22", "account_holder": { "type": "corporate", "company_name": "Software Company", "billing_address": { "address_line1": "Rue Exemple", "address_line2": "1", "city": "Paris", "zip": "75000", "country": "FR" } } }, "payment_type": "Regular", "amount": 10000, "currency": "EUR", "processing_channel_id": "pc_xyz", "success_url": "https://example.com/payments/success", "failure_url": "https://example.com/payments/failure" } ``` #### Response example If you receive a `202 Accepted` response with the status `Pending`, your request was successful. ```json { "id": "pay_ukzxtgobaoiu7l3gm2x6qxirru", "status": "Pending", "source": { "id": "src_3ycibaogn7gexoo4p7i6jmitz4", "type": "sepa" }, "_links": { "self": { "href": "https://{prefix}.api.checkout.com/payments/pay_ukzxtgobaoiu7l3gm2x6qxirru" } } } ``` --- ## Request a payment Call the [Request a payment](https://api-reference.checkout.com/tag/Payments/#operation/requestAPaymentOrPayout) endpoint to create a SEPA payment. In the `instrument_data.type` field, specify the mandate you want to use: - `Core` - `B2B` > **Information** > > Your base URL's `{prefix}` value is unique to your account and environment. To learn how to retrieve your base URLs for the sandbox and production environments, see [API endpoints](https://www.checkout.com/docs/developer-resources/api/api-endpoints.md). **Production** `POST` `https://{prefix}.api.checkout.com/payments` **Sandbox** `POST` `https://{prefix}.api.sandbox.checkout.com/payments` ### Request example - To request a payment against a one-off mandate, set `payment_type` to `Regular`. - To request a payment against a recurring mandate, set `payment_type` to `Recurring`. **With a SEPA source** ```json { "payment_type": "Recurring", "source": { "type": "id", "id": "src_wmlfc3zyhqzehihu7giusaaawu" }, "amount": 10000, "currency": "EUR", "processing_channel_id": "pc_xyz", "success_url": "https://example.com/payments/success", "failure_url": "https://example.com/payments/failure" } ``` If you receive a `202 Accepted` response with a status field set to `Pending`, your request was successful. ### Response example ```json { "id": "pay_ukzxtgobaoiu7l3gm2x6qxirru", "status": "Pending", "source": { "id": "src_wmlfc3zyhqzehihu7giusaaawu", "type": "sepa" }, "processing": { "partner_payment_id": "GA3OX32ASX3E5A7" }, "_links": { "self": { "href": "https://{prefix}.api.checkout.com/payments/pay_ukzxtgobaoiu7l3gm2x6qxirru" } } } ``` **Without a SEPA source** ```json { "source": { "type": "sepa", "country": "FR", "account_number": "FR7630006000011234567890189", "currency": "EUR", "mandate_id": "123456", "date_of_signature": "2022-08-22", "account_holder": { "first_name": "Ali", "last_name": "Farid", "billing_address": { "address_line1": "Rue Exemple", "address_line2": "1", "city": "Paris", "zip": "75000", "country": "FR" } } }, "payment_type": "Regular", "amount": 10000, "currency": "EUR", "processing_channel_id": "pc_xyz", "success_url": "https://example.com/payments/success", "failure_url": "https://example.com/payments/failure" } ``` If you receive a `202 Accepted` response with a status field set to `Pending`, your request was successful. ### Response example ```json { "id": "pay_ukzxtgobaoiu7l3gm2x6qxirru", "status": "Pending", "source": { "id": "src_3ycibaogn7gexoo4p7i6jmitz4", "type": "sepa" }, "_links": { "self": { "href": "https://{prefix}.api.sandbox.checkout.com/payments/pay_ukzxtgobaoiu7l3gm2x6qxirru" }, "succeed": { "href": "https://{prefix}.api.sandbox.checkout.com/apms/sepa/payments/pay_ukzxtgobaoiu7l3gm2x6qxirru/finalize/Accepted" }, "decline": { "href": "https://{prefix}.api.sandbox.checkout.com/apms/sepa/payments/pay_ukzxtgobaoiu7l3gm2x6qxirru/finalize/Rejected" } } } ``` --- ## Get details about a payment You can retrieve details about an existing SEPA Direct Debit Core payment using the following endpoint. For the full API specification, see the [API reference](https://api-reference.checkout.com/tag/Payments/#operation/getPaymentDetails). > **Information** > > Your base URL's `{prefix}` value is unique to your account and environment. To learn how to retrieve your base URLs for the sandbox and production environments, see [API endpoints](https://www.checkout.com/docs/developer-resources/api/api-endpoints.md). **Production** `GET` `https://{prefix}.api.checkout.com/payments/{id}` **Sandbox** `GET` `https://{prefix}.api.sandbox.checkout.com/payments/{id}` ### Response example ```json { "id": "pay_ukzxtgobaoiu7l3gm2x6qxirru", "requested_on": "2023-03-24T07:43:12.9792854Z", "source": { "id": "src_wmlfc3zyhqzehihu7giusaaawu", "type": "sepa" }, "amount": 10000, "currency": "EUR", "payment_type": "Recurring", "status": "Pending", "processing": { "partner_payment_id": "GA3OX32ASX3E5A7" }, "_links": { "self": { "href": "https://{prefix}.api.checkout.com/payments/pay_ihrxjxcbjegeliqmdr72lby2aq" }, "actions": { "href": "https://{prefix}.api.checkout.com/payments/pay_ihrxjxcbjegeliqmdr72lby2aq/actions" } } } ``` --- ## Refund a payment You can partially or fully refund a payment through the [Dashboard](https://dashboard.checkout.com) or the [Refund API](https://api-reference.checkout.com/tag/Payments/#operation/refundAPayment) if: - It has been seven or more days since the original payment date. - The payment status is `captured`. When you request a refund, you receive a `payment_refund_pending` webhook. If the refund is successfully sent and approved by the SEPA Direct Debit network, you receive a `payment_refunded` webhook. The payment status changes to `refunded` or `partially_refunded`. > **Information** > > If you plan to issue a refund, you should communicate this to the customer to prevent them from simultaneously canceling the payment with their bank. If the customer is credited twice, contact them directly to resolve the situation. If the refund is declined by the SEPA Direct Debit network or the customer's bank, you receive a `payment_refund_declined` webhook. --- ## Process a payment return Customers can reverse a payment made against an SEPA Direct Debit Core mandate up to eight weeks after the original payment date. The customer may submit a claim with their bank to reverse the payment if: - They want to revoke the direct debit authorization. - They state that they did not provide authorization for the direct debit. If a customer initiates a return, you receive a `payment_returned` webhook. You cannot challenge SEPA Direct Debit Core reversals initiated by the customer. The funds are always returned to the customer. If you dispute a reversal, contact your customer directly. > **Information** > > You can initiate a reversal for a payment made against an SEPA Direct Debit Core mandate that has not been authorized up to 13 months after the original payment date. --- ## Perform a test payment To start testing, contact your account manager or implementation engineer to enable SEPA Direct Debit payments in the sandbox environment. To perform a test payment, you must generate a valid IBAN using an online IBAN generator. `POST` `https://{prefix}.api.sandbox.checkout.com/payments` ### Request example ```json { "source": { "type": "sepa", "country": "FR", "account_number": "FR7630006000011234567890189", "currency": "EUR", "mandate_id": "123456", "date_of_signature": "2023-04-21", "account_holder": { "first_name": "Ali", "last_name": "Farid", "billing_address": { "address_line1": "Rue Exemple", "address_line2": "1", "city": "Paris", "zip": "75000", "country": "FR" } } }, "reference": "Test Reference", "payment_type": "Regular", "amount":1000, "currency": "EUR", "processing_channel_id": "pc_xyz", "success_url": "https://example.com/payments/success", "failure_url": "https://example.com/payments/failure", "description": "Test description", "billing_descriptor": { "name": "Test billing descriptor", "city": "Paris", "reference": "Test billing descriptor reference" } } ``` ### Response example ```json { "id": "pay_d7mgufw7cjuebp6hs25j27onom", "status": "Pending", "reference": "Test Regular Payment SEPA 23.06.2023", "source": { "id": "src_tko5xm22x7aetihg6befv5p7me", "type": "sepa" }, "_links": { "self": { "href": "https://{prefix}.api.sandbox.checkout.com/payments/pay_d7mgufw7cjuebp6hs25j27onom" }, "succeed": { "href": "https://{prefix}.api.sandbox.checkout.com/apms/sepa/payments/pay_d7mgufw7cjuebp6hs25j27onom/finalize/Accepted" }, "decline": { "href": "https://{prefix}.api.sandbox.checkout.com/apms/sepa/payments/pay_d7mgufw7cjuebp6hs25j27onom/finalize/Rejected" } } } ``` ### Perform a test payment with a payment instrument To perform a test payment with a payment instrument, you must first create the test instrument using the following endpoint: `POST` `https://{prefix}.api.sandbox.checkout.com/instruments` In your request, use your client ID as the `merchant_identifier` value. #### Request example ```json { "type": "sepa", "instrument_data": { "country": "FR", "account_number": "FR7630006000011234567890189", "currency": "EUR", "payment_type": "Regular" }, "account_holder": { "first_name": "Ali", "last_name": "Farid", "billing_address": { "address_line1": "Rue Exemple", "address_line2": "1", "city": "Paris", "zip": "7500", "country": "FR" } }, "merchant_identifier": "cli_xyz" } ``` #### Response example ```json { "type": "sepa", "id": "src_bvql42klnjve7nrcgix66lconq", "fingerprint": "kbzfhm3mxiuedjgi6ceb2tdcuy" } ``` To perform a test payment with the payment instrument, in your payment request: - Set `source.type` to `id`. - Set `source.id` to the `id` value returned in the `Create a payment instrument` [response](https://api-reference.checkout.com/tag/Instruments/#operation/createAnInstrument). --- ## Transition a test payment's status Payments automatically move through different states during processing. For example, the status may change from `approved` to `refunded`. When testing payment flows, you can manually change the status of a test payment to simulate different scenarios. To change a test payment status: 1. Create a test payment as shown in the [Perform a test payment](#Perform_a_test_payment) section. 2. You receive a response with the following `_links` object: ```json { "_links": { "succeed": { "href": "https://{prefix}.api.sandbox.checkout.com/apms/sepa/payments/pay_d7mgufw7cjuebp6hs25j27onom/finalize/Accepted" }, "decline": { "href": "https://{prefix}.api.sandbox.checkout.com/apms/sepa/payments/pay_d7mgufw7cjuebp6hs25j27onom/finalize/Rejected" } } } ``` 3. Accept the payment by sending a `PUT` request to the `_links.succeed.href` URL. 4. After accepting the payment, you receive a response with the following `_links` object: Payments automatically move through different states during processing. For example, the status may change from `approved` to `refunded`. When testing payment flows, you can manually change the status of a test payment to simulate different scenarios. To change a test payment status: 1. Create a test payment as shown in the [Perform a test payment](#Perform_a_test_payment) section. 2. You receive a response with the following `_links` object: ```json { "_links": { "succeed": { "href": "https://{prefix}.api.sandbox.checkout.com/apms/sepa/payments/pay_d7mgufw7cjuebp6hs25j27onom/finalize/Accepted" }, "decline": { "href": "https://{prefix}.api.sandbox.checkout.com/apms/sepa/payments/pay_d7mgufw7cjuebp6hs25j27onom/finalize/Rejected" } } } ``` 3. Accept the payment by sending a `PUT` request to the `_links.succeed.href` URL. 4. After accepting the payment, you receive a response with the following `_links` object: ```json { "_links": { "reject": { "href": "https://{prefix}.api.sandbox.checkout.com/apms/sepa/payments/pay_pprqxl2py3kuxiu5qhtjk6exxe/finalize/Rejected" }, "return": { "href": "https://{prefix}.api.sandbox.checkout.com/apms/sepa/payments/pay_pprqxl2py3kuxiu5qhtjk6exxe/finalize/Returned" }, "chargeback": { "href": "https://{prefix}.api.sandbox.checkout.com/apms/sepa/payments/pay_pprqxl2py3kuxiu5qhtjk6exxe/finalize/Refunded" }, "refund": { "href": "https://{prefix}.api.sandbox.checkout.com/payments/pay_pprqxl2py3kuxiu5qhtjk6exxe/refunds" }, "actions": { "href": "https://{prefix}.api.sandbox.checkout.com/payments/pay_pprqxl2py3kuxiu5qhtjk6exxe/actions" } } } ``` 5. To simulate a specific action, use the corresponding URL provided in the `_links` object. For example: - To return a payment, send a `PUT` request to the URL specified in `_links.return.href`. - To view all previous statuses of the payment, use the `_links.actions.href` endpoint. You can also view a list of these actions by calling the [Get payment details](https://api-reference.checkout.com/tag/Payments/#operation/getPaymentDetails) endpoint, setting the `{id}` query parameter to the `payment_id` received in the test payment response. --- ## Perform a test refund The SEPA Direct Debit network blocks refunds until seven days after the original payment was created. To bypass this restriction in the sandbox environment, use `4815162342` as your mandate ID when you request your test payment or create your test payment instrument. After you perform the test refund you can finalize and capture it by calling the following endpoint: `PUT` `https://{prefix}.api.sandbox.checkout.com/apms/sepa/{paymentId}/refunds/{refundId}/finalize/accepted` Alternatively, to decline the test refund, call the following endpoint: `PUT` `https://{prefix}.api.sandbox.checkout.com/apms/sepa/{paymentId}/refunds/{refundId}/finalize/rejected`