Skip to main content
Payment is not a step at the end of the journey. On most products it sits between confirmation and signature, because the policyholder signs a direct debit mandate at the same moment they sign the contract — and on some products cover does not begin until the first premium has been collected. Getting the ordering wrong is the most common way an otherwise correct integration stalls: the signature request is rejected, and the error names a payment method rather than the signature. Korint uses Stripe as its payment processor. We hold the Stripe account; you never call Stripe’s API server-side. Your only Stripe interaction is confirming a setup in the customer’s browser with a client secret we give you.

What the product decides

Read these from GET /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 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.
Asking for a setup secret on a product whose allowedPaymentModes excludes DIRECT_DEBIT fails with CONFLICTING_CONFIG naming allowedPaymentModes.
2

Get a client secret

Response
This is a Stripe SetupIntent client secret, created on our Stripe account and restricted to the product’s 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.
Quote the policy before asking for a secret. The customer’s counterpart on the payment side is created when the policy is quoted, not when the customer is created. Ask earlier in the journey — after creating the customer, after setting the payment mode, even after calculate-quote — and you get:
POST /policies/{policyId}/quote is what creates it; calculate-quote does not, because it persists nothing. Confirmation creates it too, for contracts that reach that point another way.
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:

Stripe SetupIntents

The setup flow the client secret belongs to.

Stripe Elements

Collecting IBAN or card details in the browser.
We learn the result from Stripe directly, by webhook — you do not report it back to us. The payment method appears on 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.
Set the method the customer should be charged on with 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.
If the product also sets 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.
POST /customers/{customerId}/retry-charge re-attempts a failed collection, and GET /customers/{customerId}/balance shows what is outstanding. For what happens when payments keep failing, see Manage unpaid invoices.
Source of NO_VALID_PAYMENT_METHODS on a signature request. POST /policies/{policyId}/signature is refused when the branch is new business, the payer is on DIRECT_DEBIT, the product sets signature.requirePaymentMethodForNewBusiness, and no payment method for that payer is ACTIVE or WAITING_MANDATE_SIGNATURE.An early-payment firstPayment adds a second condition that is easy to miss: the payer also needs a method whose type appears in payment.paymentMethodOnEarlyPayment, so a stored SEPA mandate does not satisfy a product that takes the first payment by card.The ordering to implement is confirm → payment mode → client secret → browser setup → mandate request → signature.