SEPA mandates
A SEPA mandate is a customer's permission to debit their bank account: the creditor that may collect, the account, a mandate reference, and the text the customer accepted. Kontier stores the mandate once, word for word, and the same mandate is then collected on whichever rail your organization uses.
The mandate and the rail are two different things. The mandate is what the customer agreed to. The rail is who sends the debit to the bank.
The rails
| Rail | Who collects | Creditor named in the mandate |
|---|---|---|
own | Your own SEPA files (pain.008), sent by your bank | You, with your creditor identifier |
kontier_payments | Kontier Payments | Mollie B.V. on your behalf, with Mollie's creditor identifier NL08ZZZ502057730000 |
mollie | Your own Mollie account | Mollie B.V. on your behalf, with Mollie's creditor identifier NL08ZZZ502057730000 |
stripe | Your Stripe account | You, with your own creditor identifier when your Stripe account has one; otherwise Stripe on your behalf. The reference is set by Stripe |
Which creditor identifier do you need? On your own rail you need your own, from your bank (in Germany the Bundesbank issues it). On Mollie and Kontier Payments you need none: Mollie collects every merchant's debits under its one identifier, and your customer's bank statement shows your name as the ultimate creditor. There is nothing to set up. On Stripe it's your choice, made in the Stripe dashboard, not in Kontier: by default Stripe collects under Stripe's identifier; Stripe recommends EU businesses use their own, which you enter under Settings → Payment methods in Stripe, before your first live SEPA debit. Kontier reads it from your Stripe account each time it shows the mandate form, so the text your customer accepts names the identifier the debits will carry. If Kontier cannot read your Stripe account, no mandate form is offered.
The organization setting sepa_mandate_rail decides. auto, the default, uses
your own SEPA files when the SEPA Direct Debit connection is set up and enabled,
and otherwise your default payment provider that can hold a SEPA mandate. Name a
rail (own, kontier_payments, mollie, stripe) to always use that one. In a
workspace where the named rail is not connected, no mandate form is offered:
mandates never move silently to another rail. Changing the setting moves no
existing mandate.
On a payment provider's rail a mandate starts pending. Kontier creates the provider's mandate in the background, with no first payment. It becomes active when the provider confirms it, or failed with the provider's reason. On your own rail a mandate is active as soon as it is signed.
Business (B2B) mandates use your own rail only
The SEPA Business-to-Business scheme is collected only with your own SEPA files. It needs a business customer and a SEPA connection that collects B2B. Kontier Payments, Mollie and Stripe collect SEPA Core only. A B2B mandate cannot be refunded once a debit has been taken, and the customer's bank must know about the mandate before the first debit.
One mandate, one collection instrument
Every active mandate is also a payment method of its customer. A new mandate replaces the customer's earlier mandate of the same scheme. It becomes their default for automatic payments when they have none, or when it replaces their default. Removing the payment method revokes the mandate, and revoking the mandate removes the payment method. Nothing is ever collected twice for one invoice.
An own-rail mandate that has not been used for 36 months is shown as expired,
as the EPC rulebook requires, and is no longer collected.
Pre-notification
Before every debit, the customer is told the amount and the collection date. By default Kontier sends this email, and the debit waits until the notice period has passed.
| Setting | What it does |
|---|---|
sepa.prenotification_enabled | On by default. Off: Kontier sends no notice. Turn it off only when you notify your customers another way. |
sepa.prenotification_days | The notice period in calendar days, 2 to 14, default 5. |
Each mandate keeps the period its own text promised. A text that promised a longer period keeps it. A mandate whose text named no period (signed on paper, or recorded before Kontier stored mandate texts) is notified 14 days ahead, as the rulebook says. The email is a mail template like any other, so you can change its wording in the template editor.
On Stripe it depends on the creditor identifier. Under Stripe's, Stripe always sends its own notices and Kontier never sends one. Under your own, you can switch Stripe's notices off in Stripe, and Kontier cannot see that switch, so Kontier notifies and the debit waits for the period, as on Mollie. If you keep Stripe's notices on too, your customers get two.
In the customer portal
Customers give the mandate on the portal's Direct debit page. They enter the account holder and IBAN, read the mandate text and accept it. The text on the page is rendered by Kontier for your creditor, a fresh reference and the customer's language (de, en, fr, es, it, pt, nl, ja). It is stored exactly as shown, together with when and from where it was accepted.
On the same page customers can download their mandate as a PDF, give a new one for another account, or withdraw it. Under Earlier mandates they find every mandate they gave before, each with its PDF.
Over the API
The mandate routes are under the Payment Methods tag. Reading needs the
payment.read scope, and recording or revoking needs payment.write.
| Operation | What it does |
|---|---|
GET /v1/customers/{id}/sepa-mandates | The customer's mandates, newest first, and the offer: the rail, creditor, schemes, a fresh reference and the mandate text in locale |
POST /v1/customers/{id}/sepa-mandates | Record a mandate (channel operator or api) |
GET /v1/sepa-mandates/{mandate_id} | One mandate with its history |
POST /v1/sepa-mandates/{mandate_id}/revoke | End a mandate |
POST /v1/sepa-mandates/{mandate_id}/sync | Set up a mandate whose setup at the payment provider failed again |
GET /v1/sepa-mandates/{mandate_id}/pdf | The mandate as a PDF |
GET /v1/invoices/{id}/sepa-prenotifications | The pre-notifications sent for an invoice, and whether each mail went out |
The IBAN is never returned in full: a mandate carries iban_masked and
iban_last4.
A mandate signed on paper
Use channel operator (the default) for a form the customer signed. Send the
date on the form and, ideally, the ID of its uploaded scan. Kontier never saw the
wording, so it stores none, and the rulebook's 14 days of notice apply.
cURL
A mandate collected in your own application
If customers sign up in your own application, you can collect the mandate there
and send it with channel api. You must show Kontier's text unchanged:
- Read the offer in the customer's language:
GET /v1/customers/{id}/sepa-mandates?locale=de. Showoffer.text, the creditor andoffer.referenceas they are. - When the customer accepts, send the mandate with the reference,
locale,text_version, the SHA-256 of the text you showed (text_sha256, hex, of the exact UTF-8 string), when they accepted (accepted_at, at most 24 hours ago) and the IP address and user agent they accepted from.
cURL
text_sha256 here is a placeholder: compute it from the offer.text you
showed, for example sha256(offer.text.encode("utf-8")).hexdigest() in Python.
Kontier checks the mandate as its own portal does (account holder, IBAN, EU/EEA account, scheme, reference) and also checks the evidence:
Refusal (fields[].code) | Why |
|---|---|
SEPA_MANDATE_TEXT_CHANGED | text_version is not the current one, or text_sha256 is not the hash of Kontier's text for this creditor, reference, scheme and language |
SEPA_MANDATE_ACCEPTED_AT_INVALID | accepted_at is missing, in the future, or more than 24 hours ago |
SEPA_MANDATE_EVIDENCE_MISSING | The IP address or user agent is missing |
SEPA_MANDATE_NOT_ACCEPTED | confirmed is not true |
You answer for the consent you collect
With confirmed: true on channel api you state that the customer was shown
the offer's text unchanged and accepted it. Kontier did not see your page. You
are the creditor, or the seller a payment provider collects for, and you are
responsible for the consent, as you are for any mandate you collect. If you
cannot show the text unchanged, send customers to the portal instead. A customer
who disputes a debit can claim a refund from their bank for up to 13 months when
no valid mandate exists.
Webhooks
Every change to a mandate is announced in the transaction that makes it. The
payload is the mandate as GET /v1/sepa-mandates/{mandate_id} returns it, with
the IBAN masked.
| Event | Fires when |
|---|---|
sepa_mandate.created | A mandate is recorded, through any channel. On your own rail sepa_mandate.activated follows in the same transaction. |
sepa_mandate.activated | The mandate can be collected on. |
sepa_mandate.revoked | The mandate ended. revoked_by says who: customer, operator, provider, bank, replaced, erasure. |
sepa_mandate.failed | The payment provider refused to set up a pending mandate. sync_error says why. |
The mandate is also a payment method, so payment_method.attached and
payment_method.removed arrive alongside these. See
Webhooks and events for signatures and retries.
Dashboard and API names
| In the dashboard | In the API |
|---|---|
| SEPA mandates on the customer | GET /customers/{id}/sepa-mandates |
| Record mandate | POST /customers/{id}/sepa-mandates, channel operator |
| Revoke | POST /sepa-mandates/{mandate_id}/revoke |
| Download PDF | GET /sepa-mandates/{mandate_id}/pdf |