Disputes
A cardholder's bank can pull a payment back weeks after it settled. BillKit records those chargebacks read-only. There is nothing to configure, and contesting one happens in Mollie, not here.
What a dispute is here
A dispute is a chargeback: the cardholder told their bank they do not accept a payment, and the bank pulled the money back out of your Mollie balance. It is not a refund. A refund is you returning money; a chargeback is a bank taking it, usually with a fee, and usually long after the original payment looked final.
BillKit does not run the chargeback. Your acquirer and Mollie do. What BillKit gives you is a record of one against the payment, the subscription and the customer it belongs to, so a chargeback shows up in the same place as the rest of that customer’s billing history instead of only in your Mollie dashboard.
Disputes are read-only. There is no endpoint to create, contest or close one, because Mollie’s API has no way to do those things either. To contest a chargeback, go through Mollie. See Contesting a chargeback.
The two states
| Status | What it means |
|---|---|
| open | The chargeback was received. The funds are already out of your balance. |
| won | Mollie reversed the chargeback. The funds came back to you. |
There is no lost status, and that is the most important thing to understand about this
resource.
Mollie reports two things about a chargeback: that it was received, and, later, that it was
reversed. A chargeback you lost never reverses, and nothing arrives to say so. BillKit does not
guess a lost state from a timer, because a late reversal would then contradict an outcome the API
had already published. A standing chargeback stays open indefinitely.
If you need “lost” for your own accounting, derive it on your side from age, but treat it as an
estimate, not a fact, and let a later dispute.closed correct you.
When the money moves
Funds leave on open, not on close. By the time the dispute exists in BillKit, your balance has
already been debited. This is why dispute.created is the event worth acting on: it is the one
that has a financial consequence, and waiting for a resolution that may never come means acting
weeks late or not at all.
The disputed amount shows on the charge as amount_disputed_cents and is taken off
amount_refundable_cents, because you cannot refund money the bank has already returned. A
refund against a charge disputed in full is refused with a 409 charge_disputed. The charge itself stays paid.
| Event | When it fires |
|---|---|
| dispute.created | A chargeback was received. Funds are already withdrawn. |
| dispute.closed | The chargeback reversed, open to won. Funds returned. |
A chargeback that Mollie has already reversed by the time BillKit first sees it emits both events
back to back, so a listener that only handles dispute.closed still gets a consistent picture.
What BillKit does not do to the subscription
Nothing automatic. A dispute does not cancel, pause or suspend the subscription it came from, and the period it paid for is not restated or debited again.
One thing does change. When a charge made on the payment method a subscription renews on (the
first payment that set the method up, a renewal, a metered usage charge or a plan change) is
charged back for a reason that means the method cannot be charged again (a closed or blocked
account, a revoked mandate, a debit the customer refused or disputed, suspected fraud), BillKit
stops charging that method, as long as the subscription still renews on it. Every subscription
of that customer renewing on the same method is affected, not only the one the charge belongs
to. At the next renewal the subscription goes
past_due without a charge attempt, and the customer is asked to pay with a new method, exactly
as for a renewal declined for the same reason. A metered subscription’s next usage invoice is
likewise not charged until the method is replaced. Until then a plan change is refused too. See
Recover failed payments.
A chargeback can be fraud on a stolen card, in which case you almost certainly want to end service immediately. It can equally be a customer who forgot what the line item was, in which case cancelling their subscription turns a support conversation into a lost account. BillKit cannot tell those apart, so it tells you and lets you decide.
The usual shape is to listen for dispute.created, look at the subscription it names, and apply
your own policy: cancel, suspend access, or just open a ticket.
Reading disputes
curl "https://api.billkit.eu/v1/disputes?limit=20" \
-H "Authorization: Bearer $BILLKIT_API_KEY"Newest first. Filter with status (open, won, or both comma-separated) or with payment_id.
The payment_id filter matches subscription payments only, not one-off charges.
Each dispute carries the amount_cents and currency taken, the reason the bank supplied when
it supplied one, Mollie’s provider_chargeback_id, and reversed_at, the time it was reversed, or
null while it is open. It points at either a payment_id or a one_shot_payment_id, never
both. subscription_id is the subscription behind the payment, and null for a one-off charge.
There is no customer id on the dispute; read it from the payment.
Full field-by-field shapes are in the API reference: List disputes and Retrieve a dispute.
Reconciliation, if a webhook goes missing
Mollie notifies BillKit again when a chargeback reverses. If that notification is lost, the
dispute would sit open even though the money came back.
So BillKit also re-checks open disputes with Mollie in the background, roughly hourly once a
dispute is a day old, and dispute.closed fires the same way either way. It stops checking a
dispute after 180 days. A reversal later than that still arrives if Mollie notifies BillKit about
it. There is nothing to configure.
A chargeback whose first notification is lost entirely is still found, by a slower backstop.
BillKit keeps re-reading paid payments from Mollie for 400 days after they were paid (a SEPA debit
can be charged back as unauthorised for 13 months), and when Mollie reports money charged back
that no dispute covers, it records the dispute and fires dispute.created as the webhook would
have. Each payment is re-read at most once a week; with many paid payments the gap between
re-reads grows, so treat this as a backstop, not a delivery channel.
Contesting a chargeback
You cannot contest a chargeback through BillKit. Mollie’s API has no way to submit evidence or accept a chargeback, so BillKit cannot offer one.
To contest, go to the payment in your Mollie dashboard and follow Mollie’s chargeback process, or
contact Mollie support, who work with the acquirer. provider_chargeback_id and the Mollie
payment id (from GET /v1/payments/{id}/provider) tell
them which chargeback you mean. If you win, Mollie reverses the chargeback, BillKit moves the
dispute to won, and dispute.closed fires. If you lose, nothing changes here.
Test mode
A chargeback Mollie simulates against a test payment reaches BillKit the same way a live one does,
with the same events, so you can build your dispute.created handling without waiting for a real
cardholder to dispute something.
Chargeback fees are charged by your acquirer and settled on your Mollie balance. They are not part of the BillKit dispute record, and they do not appear on a BillKit invoice or credit note.
BillKit