SEPA direct debit with Stripe
Collect a buyer's SEPA authorization once, reuse that mandate for later debits, then synchronize every Stripe execution into the canonical Ormuz PSP payment before reconciliation.
Business objective
A recurring debit combines two distinct responsibilities: obtain a reusable mandate
and execute a payment. The mandate belongs to the Stripe Customer context; each debit is materialized in Ormuz by a psp_payment distinct object carrying amount, currency, and business attachments.
A SEPA mandate authorizes a debit rail; it proves neither that a debit was initiated nor that it was collected. Create a new psp_payment for each debit intent.
Mental model
The Customer and mandate are reusable; the `psp_payment` represents one precise payment intent and remains the Ormuz anchor for its Stripe execution.
The mapping between Ormuz and Stripe objects is durable. The process therefore does not need to carry raw Stripe IDs between steps: Stripe nodes accept typed objects and reuse existing mappings.
Prerequisites
- A Stripe configuration active and consistent with the Ormuz environment.
- A buyer company and, for interactive collection, a contact with the required information.
- A process able to present a User Journey when mandate signature is required.
- A clear rule for creating the
psp_payment: invoice, order, checkout session, or another explicit business basis.
1. Collect or reuse the mandate
Start with stripe.ensure_customer. The node creates the Stripe Customer only when no reusable mapping exists for the company or contact.
Then use stripe.ensure_sepa_debit_mandate
for the standard path. It first looks for active mandates: if none exists, it opens a Stripe Elements user action; if exactly one exists, it reuses it without interaction; if several exist, it stops on ambiguity rather than choosing arbitrarily.
| Need | Node | Behavior |
|---|---|---|
| Reuse when possible, collect when no mandate exists | stripe.ensure_sepa_debit_mandate | Reuses the unique active mandate, collects when none exists, and fails on ambiguity. |
| Resolve without interaction | stripe.resolve_sepa_debit_mandate | Explicitly routes zero, one, or several mandate candidates. |
| Force a new collection | stripe.collect_sepa_debit_mandate | Creates a new SetupIntent and suspends the process during signature. |
When resolution returns several active mandates, handle the ambiguity in the process. Choosing a mandate is a business decision and must not depend on provider list ordering.
2. Create and then trigger the debit
First create the Ormuz intent with create_psp_payment. Amount, currency, and business basis of the debit are then frozen in a platform.psp_payment in draft status.
Pass this payment, the Customer, and mandate to stripe.trigger_sepa_debit. The node validates mandate consistency, creates or reuses the Stripe PaymentIntent idempotently, and preserves its mapping to the same psp_payment.
The Stripe node does not freely redefine the debit amount: the supplied psp_payment remains the source of truth for the payment intent.
3. Track the result and reconcile
A SEPA direct debit may evolve after creation. Use Stripe events and
stripe.sync_psp_payment to reread the PaymentIntent and report authoritative status and amounts back to the psp_payment Ormuz.
When the payment genuinely represents a receipt to apply to an invoice or receivable, then use reconcile_payment or the
payment reconciliationjourney. Invoice settlement must not be inferred from provider status alone without creating the corresponding business allocation.
Resume, idempotency, and security
- Customer : reused through the company's or contact's Stripe mapping.
- Mandat : reusable while it remains active and compatible with the Customer.
- PaymentIntent : correlated to the
psp_paymentto avoid a second debit on resume. - Secrets Stripe : values required by the browser must be exposed only during the interaction that consumes them.
- Replay : place a resume boundary before any interaction that would be dangerous to repeat automatically.
Checklist
- Resolve the Stripe Customer from an Ormuz object, never from a hard-coded Stripe ID.
- Reuse an active mandate when one exists and explicitly handle ambiguities.
- Create a distinct
psp_paymentfor every debit. - Trigger the debit from the amount and currency of the Ormuz payment.
- Synchronize the Stripe result before any business decision depending on final status.
- Create a
payment_allocationwhen cash must settle an invoice or reduce a receivable.