Payments
A payment is money arriving against an invoice. It can come through a payment gateway, from a customer's wallet, or by hand when somebody pays by bank transfer.
Payments are separate from invoices on purpose. One invoice can be settled by
several payments, a single payment can be split across invoices, and a payment
can arrive long before or after the document it settles. What connects them is
the invoice's balance, which is the number that decides whether it is paid.
Three ways money arrives
Through a gateway
The customer pays by card or direct debit and the provider tells Kontier what happened. Stripe and GoCardless are supported. The payment appears with the provider's reference and moves through its own states as the provider confirms or fails it.
This is the path you want for self-serve.
From a wallet
The customer has a prepaid balance and the invoice draws on it. Nothing leaves a bank; the money was already there. See Wallets for holds, top-ups and how a balance is spent.
Recorded by hand
A bank transfer, a cheque, a write-off. Nothing comes back through a provider, so somebody records it against the invoice. This is the path most B2B invoices actually take, and it is the one people forget to document.
Amounts are Money, in major units
amount on a recorded payment is {"value": "49.99", "currency": "EUR"}, not
4999. The currency must be the invoice's own currency; another currency is
refused with 422 CURRENCY_MISMATCH. A payment larger than the open balance is
refused with 422 INVOICE_OVERPAYMENT.
Record one in the dashboard
Over the API, this is POST /v1/invoices/{id}/record-payment; see
Record one over the API.
-
Open the invoice
Payments attach to an invoice, not to a customer, so start from Billing and open the one being settled.
-
Record the payment
Use Record Payment. Enter the amount that actually arrived, the rail it arrived through, and the date it landed.
Partial payments are fine. The invoice keeps a balance and stays unpaid until the balance reaches zero.
-
Check it in the ledger
Ledger → Payments is the cross-customer view: everything that arrived, in date order, filterable by time range and direction.
Record one over the API
The invoice must be finalized or overdue. Only amount is required. The
response is the updated invoice, not a separate payment object. Amounts on a
read are {value, currency} objects with trailing zeros trimmed, so compare them
as decimals, never as strings.
| Field | What it is |
|---|---|
amount | What arrived, as {value, currency}: a positive amount in major units. currency must be the invoice's currency; another currency is refused with 422 CURRENCY_MISMATCH |
instrument | The rail the money came over as you file it (BANK_TRANSFER, CASH, WIRE, CHEQUE, …); a free-form string, so agree a convention and stick to it |
received_at | When the money moved. Omitted, it is the current time. It may not lie in the future |
reference | Your bank statement line or cheque number. Recording the same reference twice is recognised as a replay and leaves the invoice unchanged |
provider, method | For a payment a provider reported. Leave empty for a hand-entered receipt |
Refunds
POST /v1/invoices/{id}/refund gives money back, in full or in part, and writes
the credit note for it in the same transaction. instrument is gateway (back
through the provider that charged it) or wallet (onto the customer's wallet);
omit it for the invoice's default rail, which GET /v1/invoices/{id}/refund-rails
names. amount is in major units; omit it for a full refund. reason is one
of duplicate, fraudulent, requested_by_customer, service_issue, other.
A refund answers 202 when the gateway confirms asynchronously, or when an
approval checkpoint parked it (a person decides approvals in the dashboard;
the API can read them with GET /v1/approvals but not decide them), and 402
REFUND_DECLINED when the provider refuses.
Charging an invoice now
POST /v1/invoices/{id}/charge charges a finalized or overdue invoice off
the customer's saved auto-pay method, right now. It answers 200 with one
outcome:
outcome | What happened | What you do |
|---|---|---|
charged | The provider accepted the charge, or it is still processing (a SEPA debit takes days). The invoice is not paid yet. | Wait for invoice.payment_recorded with settled: true. |
declined | The provider refused; reason says why. The decline is recorded, and the dunning policy's retry steps try again on their days. | Ask the customer for another method. |
checkout_required | The customer has no saved method. checkout_url is the provider's hosted page that pays this balance once and then returns the customer to the portal's checkout page. | Send the customer to checkout_url. |
no_payment_method | No saved method, and the provider has no hosted page (or the deployment has no portal to return the customer to). | Send the customer a portal link to add a method. |
awaiting_sepa_file | The saved method is a SEPA mandate on your own rail: your next SEPA file collects it, not this call. | Create the file as usual. |
awaiting_sepa_prenotice | The saved method is a SEPA mandate Kontier pre-notifies (Mollie, Kontier Payments, or Stripe under your own creditor identifier). The notice went out and the debit runs on the day it names. | Nothing; see SEPA mandates. |
The hosted page in checkout_required pays this one invoice and saves no
method for later charges. For recurring charges, have the customer save a
method first: a portal link with scope add_payment_method
(POST /v1/customers/{id}/portal-links). Subscribe to the
payment_method.attached webhook to learn when they have; you do not need to
poll GET /v1/payment-methods.
Dashboard and API names
| In the dashboard | In the API |
|---|---|
| Record Payment | POST /invoices/{id}/record-payment |
| Amount on the form | amount, {value, currency} in major units |
| Source | instrument, a free-form string |
| Reference | reference, your bank or provider reference |
| Ledger → Payments | GET /invoices/{id}/payments per invoice, GET /payments/{id} for one |
| Ledger → Transactions | GET /transactions, every money movement, not only payments |
| Balance on the invoice | what is still owed after all payments |
Where payments go next
- The invoice settles itself. When the balance reaches zero the invoice
becomes
paid; no separate step. - A failed collection starts dunning, on the policy set for the
organization (
PUT /v1/dunning-policy) or the plan (PUT /v1/plans/{planId}/dunning-policy). - Charge on demand.
POST /v1/invoices/{id}/chargecollects an open invoice now through the customer's payment method. See Charging an invoice now.
Next step
Continue to Wallets for prepaid balances, holds and top-ups.
Reference
| Topic | When you need it |
|---|---|
| Wallets | Prepaid balance, holds and auto-topup |
| Dunning | What happens when a payment fails |
| Credit notes | Reducing what is owed rather than refunding it |
| Payment gateways | Connecting Stripe or GoCardless |
| SEPA mandates | Direct debit mandates, the creditor identifier of each rail, and pre-notification |
| Payments API | Payment retrieval and the per-invoice payment list |