Server-to-Server
Collect the payer's IBAN and mandate acceptance in your own checkout, then send the payment request directly to the API. There is no hosted page and no browser redirection.
For the full sequence diagram and status table, see Payment workflow on the SEPA Direct Debit overview.
You can provide the mandate reference in one of three ways:
- pass your own reference in the
sepa_mandateparameter, - create one upfront with the Mandate Reference API and pass the returned
tokenassepa_mandate, or - omit
sepa_mandateand let the API generate one automatically.
Implementation flow
- Present the SEPA mandate at checkout and capture the payer's agreement.
- Make a Payment API request including the bank account data (
iban,account_holder) and the relevantpayment_type(ddordd_b2b). The synchronous response returns the transaction in thestartedstatus. - The collection is queued for the next SEPA export cycle. Once it is submitted to the bank, the transaction moves to
pendingand a postback is sent. - After the bank reconciles the collection, the transaction reaches its final status (
completed, orchargeback/declined/erroron a return), and a postback is sent for the change.
A postback is sent on each status change, so use it, not the synchronous response, as the source of truth for the final result.
For a general walkthrough of credentials, authentication, and postbacks, see Get Started — Server-to-Server Processing.
Create a payment
The request structure is the same for both schemes. Only the payment_type value changes:
ddforB2Cdd_b2bforB2B
POST/rest/payment
/rest/paymentProduction URL
https://api.betterpayment.de/rest/paymentTest URL
https://testapi.betterpayment.de/rest/paymentpayment_typeStringrequireddd for B2C or dd_b2b for B2Border_idStringrequiredamountFloatrequiredcurrencyStringrequiredEURaccount_holderStringrequiredibanStringrequiredbicStringsepa_mandateStringpostback_urlStringrequiredPOST /rest/payment
Authorization: Basic <base64(api_key:api_password)>
Content-Type: application/json
{
"payment_type": "dd",
"order_id": "SEPA-12345",
"amount": "15.90",
"currency": "EUR",
"account_holder": "Max Mustermann",
"iban": "DE89370400440532013000",
"first_name": "Max",
"last_name": "Mustermann",
"address": "Teststr. 5",
"city": "Berlin",
"postal_code": "15557",
"country": "DE",
"postback_url": "https://your-postback.url.com"
}
For a B2B payment, use the same payload with payment_type: "dd_b2b". Example:
{
"payment_type": "dd_b2b",
"order_id": "SEPA-B2B-12345",
"amount": "150.00",
"currency": "EUR",
"account_holder": "Muster GmbH",
"iban": "DE89370400440532013000",
"first_name": "Max",
"last_name": "Mustermann",
"address": "Teststr. 5",
"city": "Berlin",
"postal_code": "15557",
"country": "DE",
"postback_url": "https://your-postback.url.com"
}
Payment API Response
The synchronous response format is the same for both schemes:
transaction_idStringpayment_typeStringstatus_codeInteger1 (started) until the collection is submitted to the bankstatusStringorder_idStringmessageStringadditional_transaction_dataStringpostback_url as part of the postback data.amountFloatincluded_feesStringerror_codeIntegermandate_idStringibanStringrecurring_mandateInteger1 if the mandate is recurring, 0 otherwiseexecution_dateString{
"transaction_id": "6c2e7e30-b741-4c5e-bc50-91dffdf0e5fb",
"payment_type": "dd",
"status_code": 1,
"status": "started",
"order_id": "SEPA-12345",
"message": null,
"additional_transaction_data": null,
"amount": 15.9,
"included_fees": "0.00",
"error_code": 0,
"mandate_id": "a7678918bfbbfa449cf9ff78446b60a4",
"iban": "DE89370400440532013000",
"recurring_mandate": 0,
"execution_date": "2026-07-07"
}
Depending on your payment method configuration and acquirer, SEPA transactions are submitted to the financial institution either the same day or the next business day. Until submission happens on our side, the transaction stays in the started state. Use the postback as the source of truth for the final status.
Create a Mandate Reference
SEPA Direct Debit transactions depend on a mandate. You can either provide the mandate yourself via the sepa_mandate parameter in the Payment API, or create a mandate reference upfront using the Mandate Reference API.
Use the dedicated API reference page for:
- the endpoint definition for
POST /rest/create_mandate_reference - request and response examples
- the full parameter list
- how to use the returned
transaction_idand mandate reference (tokenin the response, the value to show to the payer and to send later assepa_mandate)
When creating the mandate reference, use payment_type: "dd" for B2C or payment_type: "dd_b2b" for B2B.
Recurring Payments
Mandates can be one-time or recurring. For recurring collections:
- Create an initial payment or a mandate reference with
recurring: 1. - Store the returned
transaction_id. - Create each subsequent collection with
recurring: 1andoriginal_transaction_idset to the storedtransaction_id.
The recurring flow is the same for both schemes.
Refund API
Refunds are supported in full and in part. A SEPA refund is processed as a credit transfer back to the payer's account, so the refund is created in the started status and completed asynchronously.
POST/rest/refund
/rest/refundProduction URL
https://api.betterpayment.de/rest/refundTest URL
https://testapi.betterpayment.de/rest/refundtransaction_idStringrequiredamountFloatcommentStringPOST /rest/refund
Authorization: Basic <base64(api_key:api_password)>
Content-Type: application/json
{
"transaction_id": "6c2e7e30-b741-4c5e-bc50-91dffdf0e5fb",
"amount": "15.90",
"comment": "Goods returned"
}
For B2B, note that the lack of payer refund rights for authorised collections does not change the merchant-side refund API flow.
Payout API
Payouts send money to a bank account without a prior payment (an unreferenced credit transfer). Provide the recipient bank account data.
POST/rest/payout
/rest/payoutProduction URL
https://api.betterpayment.de/rest/payoutTest URL
https://testapi.betterpayment.de/rest/payoutpayment_typeStringrequireddd for B2C or dd_b2b for B2Border_idStringrequiredamountFloatrequiredcurrencyStringrequiredaccount_holderStringrequiredibanStringrequiredmerchant_referenceStringpostback_urlStringrequiredPOST /rest/payout
Authorization: Basic <base64(api_key:api_password)>
Content-Type: application/json
{
"payment_type": "dd",
"order_id": "PAYOUT-12345",
"amount": "15.90",
"currency": "EUR",
"account_holder": "Max Mustermann",
"iban": "DE89370400440532013000",
"merchant_reference": "Refund for order XYZ",
"postback_url": "https://your-postback.url.com"
}
Postbacks
When the collection is submitted and its status changes, a postback is sent to your postback_url. In addition to the standard Payment API postback fields, SEPA Direct Debit postbacks include mandate_id, iban, bic, recurring_mandate, and execution_date. This applies to both B2C and B2B. For retry policy and signature verification, see Postbacks.
Test Data
Use the following test bank account in the sandbox environment for both B2C and B2B:
| Field | Value |
|---|---|
account_holder | Max Mustermann |
iban | DE89370400440532013000 |
bic | COBADEFFXXX |