What the product decides
Read these fromGET /config/{productId} before writing any payment code:
array
DIRECT_DEBIT — Korint collects from a stored payment method. BANK_TRANSFER — the customer
transfers to an account you obtain from GET /customers/{customerId}/bank-transfer-account, and no
payment method is collected.array
sepa_debit, card, or both. These are Stripe payment method types, and they determine what the
setup can accept.array
Which method types may be charged for the first premium and for recurring premiums. A product can
accept a card for the first payment but require a SEPA mandate for the recurring ones.
array
Fallback types charged when the normal method is unusable — a dead mandate, for example. Absent
means such invoices are left unpaid.
boolean
When true, a new-business contract cannot be sent for signature until a payment method exists for
every direct-debit payer.
boolean
A top-level property of the product config, not part of
payment. When true, a signed contract
only comes into force once the first premium has been collected, in addition to reaching its start
date. Optional, and absent on all of the demo products — treat a missing value as false.boolean
When true, the payment method belongs to the distributing brokerage firm rather than the customer,
and you collect it on the firm’s endpoints instead.
Where payment sits in the journey
Collecting a payment method
1
Put the payer on direct debit
A payment method can only be set up for a customer whose payment mode is Asking for a setup secret on a product whose
DIRECT_DEBIT.A new customer already has one: the mode defaults to the first entry of the product’s
allowedPaymentModes. So on a direct-debit-first product this call is a no-op and you can skip it — but
check the config rather than assuming, because on a product that lists BANK_TRANSFER first the default
is bank transfer and this call is required.allowedPaymentModes excludes DIRECT_DEBIT fails with
CONFLICTING_CONFIG naming allowedPaymentModes.2
Get a client secret
Response
allowedPaymentMethods. It is safe to pass to the browser; it authorises setting up one
payment method for one customer and nothing else.allowedPaymentMethods can be wider than what the contract can actually charge: the SetupIntent accepts
everything in that list, while recurring premiums are limited to paymentMethodOnRecurringPayment. Render
the intersection of the two — plus paymentMethodOnEarlyPayment when the first payment is an early one —
rather than whatever the SetupIntent permits, or Stripe’s Payment Element will offer a card tab that stores
a method the contract can never charge.The response does not include a publishable key, and no endpoint serves one. Stripe.js must be initialised
with the publishable key of our Stripe account for your tenant and environment — ask Korint for it.3
Confirm the setup in the browser
Use Stripe.js with the client secret. For a SEPA direct debit the customer enters an IBAN; for a card,
card details. Follow Stripe’s own guides — we deliberately do not restate them here:We learn the result from Stripe directly, by webhook — you do not report it back to us. The payment
method appears on
Stripe SetupIntents
The setup flow the client secret belongs to.
Stripe Elements
Collecting IBAN or card details in the browser.
GET /customers/{customerId}/payment-methods shortly after the setup succeeds,
which makes this an asynchronous step: see
Asynchronous operations.4
Have the mandate signed, for SEPA
A SEPA direct debit needs a signed mandate authorising the collections. When the product configures
one, request it for the stored method:Payment methods carry one of four statuses:
ACTIVE— usable; a mandate, if required, has been signed.WAITING_MANDATE_SIGNATURE— stored, mandate not yet signed. Accepted for new business, which is what lets the customer sign the contract and the mandate in one session.INVALID_MANDATE— no longer valid; collections will fail.EXPIRED— the underlying method has expired, typically a lapsed card.
PUT /customers/{customerId}/payment-methods/{paymentMethodId}/preferred when more than one exists.When the first premium is taken
invoicingConfig.firstPayment decides this, and it is a value you set on the policy:
NONE— no distinct first payment; the contract is billed on its normal schedule.FULL_AT_SIGNATURE/EARLY_PAYMENT_AT_SIGNATURE— charged when the contract is signed, either the full first premium or an early-payment portion.FULL_AT_START_DATE/EARLY_PAYMENT_AT_START_DATE— charged when cover begins.
requireFirstPaymentToActivate, cover does not begin until that payment has
been collected. A contract that is signed, with a start date in the past, and still not in force is
usually waiting on exactly this — not on a failure. isAwaitingFirstPayment on the policy tells you so;
read the invoices from GET /customers/{customerId}/invoices.

