Direct debit

You pull money from the customer's bank account under a standing authorization — a mandate. Ideal for subscriptions and invoicing: cheap, bank-grade, and reusable for years. The trade-offs are speed (days, not seconds) and returnability, and this page covers both.

The direct-debit methods

Schemepayment_methodRegionMandate instrument
SEPA Direct Debitsepa_debitEUSEPA mandate (IBAN + acceptance)
ACHachUSACH authorization (routing + account no.)
Bacs Direct Debitbacs_debitUKDirect Debit Instruction
BECS Direct Debitbecs_debitAustralia / NZDirect Debit Request
ACSS Debitacss_debitCanadaPre-authorized debit agreement

Five schemes, one model: collect a mandate once, then debit it on your schedule. Each scheme prescribes its own mandate wording and rules — hosted checkout records the correct text and acceptance evidence per scheme, so you never draft mandate language yourself.

The mandate lifecycle

The mandate mandate collected hosted checkout active pm_… reusable debits pulled payment_method_id revoked lapsed — disuse Each debit submitted processing succeeded return window open 2–5 business days return → dispute (dp_…) failed early return — insufficient_funds, account_closed

Collection. Hosted checkout collects the account details and mandate acceptance, and the result is a reusable pm_… instrument attached to the customer — with the account tail and the mandate reference on it (sepa_debit: { iban_last4, mandate_reference }). The save-and-charge pattern is in the payment methods overview.

Active. The mandate stays valid until the customer or their bank revokes it — or, under SEPA rules, until it lapses after 36 months without a debit. Charging a dead mandate fails cleanly; see errors.

The mandate reference travels. The scheme requires the reference (and your name) to appear on the customer's bank statement — that's what mandate_reference is for. Surface it in your receipts too; unrecognized statement lines are the top cause of avoidable returns.

Charging a mandate

Pass the method and the saved instrument. No return_url: there is no customer interaction to return from —

POST /v1/payments — charge a saved SEPA mandate
curl https://api.finscale.dev/v1/payments \
  -H "Authorization: Bearer sk_test_51FinscaleDemo…" \
  -H "Idempotency-Key: idem_ord_9f21_0716" \
  -H "Content-Type: application/json" \
  -d '{
    "amount": 4900,
    "currency": "EUR",
    "payment_method": "sepa_debit",
    "payment_method_id": "pm_6Wq2rT8nB4Yx",
    "customer": { "id": "cus_4T8nQb2Wp1Zr" },
    "reference": "ord_9f21_0716"
  }'
201 Created — nothing for the customer to do
{
  "id": "pay_8Q2mX4nT1cVb",
  "object": "payment",
  "amount": 4900,
  "currency": "EUR",
  "status": "processing",
  "payment_method": "sepa_debit",
  "payment_method_id": "pm_6Wq2rT8nB4Yx",
  "payment_method_details": {
    "sepa_debit": {
      "iban_last4": "3401",
      "mandate_reference": "FSCL-MNDT-8Q2MX4NT"
    }
  },
  "customer": "cus_4T8nQb2Wp1Zr",
  "reference": "ord_9f21_0716",
  "provider": "prov_eu_acq_01",
  "next_action": null,
  "created_at": "2026-07-16T09:24:31Z",
  "livemode": false
}

The payment goes straight to processingnext_action is null and stays that way. First-time flows (no saved instrument yet) start from hosted checkout, which collects the mandate and can take the first debit in the same session.

The debit timeline

Direct debit is the slowest family in the catalog, by design of the underlying schemes:

  • processing lasts 2–5 business days while the debit clears — the exact spread depends on the scheme and submission cut-off times.
  • payment.succeeded fires when the scheme confirms the debit. Gate fulfillment of high-value goods on this event, not on payment creation.
  • Success is still not final — see the return window below.

Returns & disputes

A direct debit can bounce at two points, and the API distinguishes them:

  • Early return, during processing — the bank rejects the pull: no funds, closed account, revoked mandate. The payment moves to failed with a normalized failure_code such as insufficient_funds or account_closed, and payment.failed fires. No dispute object is involved.
  • Late return, after succeeded — the customer exercises their scheme rights and the settled debit is pulled back. This surfaces as a Dispute (dp_…) via dispute.created: reason: "fraudulent" for an unauthorized-debit claim, reason: "general" otherwise. The dispute flow — evidence, deadlines, outcomes — applies unchanged; your strongest evidence is the mandate acceptance record, which Finscale stores from checkout.
Return windows are long SEPA gives consumers a no-questions-asked refund right of 8 weeks after the debit — and about 13 months for unauthorized-debit claims. ACH consumer returns run around 60 days. Price this into your exposure for high-risk verticals, and use the risk engine to gate first-time debits from new customers.

Settlement timing

Funds confirm at succeeded and join your unified payout on the standard T+2 schedule. Late returns net against a later payout as negative settlement lines — the settlement report ties each one back to the original payment id, and reconciliation shows the id chain.

Error scenarios

ScenarioWhat the API does
Debit bounces in clearingpayment.failed with failure_code: "insufficient_funds", "account_closed", … Retrying is allowed by the schemes within limits — create a new payment; don't loop retries on insufficient_funds faster than your dunning policy.
Mandate revoked or lapsedThe charge fails without touching the bank; payment.failed carries the failure reason, and the pm_… instrument stops being chargeable. Re-collect a mandate through checkout.
payment_method_id missing or not attached to the customer400 invalid_request_error at create — a debit needs a mandate-backed instrument.
Settled debit returned by the customerDispute object via dispute.created — see Returns & disputes.
Currency doesn't match the scheme400 invalid_request_error with currency_not_supportedsepa_debit is EUR-only, ach USD-only, and so on.