BillKit/Docs Console
Get started

Test mode

Test mode is the same API against a separate set of rows and a separate Mollie account. The key you send decides which one you are in.

Updated Sep 13, 2026 · API version 2026-09-13

What separates the two modes

Every row in BillKit carries a mode. A bk_test_ key can only read and write test rows, and a bk_live_ key can only read and write live rows. Asking for an object from the other mode returns 404 resource_missing, the same answer you get for an object that belongs to another account, because “it exists but not for you” is not something an API should confirm.

Objects carry livemode: false in test mode and livemode: true in live mode, and so does every webhook event. Webhook endpoints are per mode too, so a test endpoint never receives live traffic.

Mollie credentials are stored per mode as well. Test mode drives your Mollie test API key, which means payments are simulated by Mollie and no money moves. Connect it under Settings → Mollie in the console before your first checkout.

Completing a test payment

BillKit does not simulate payments, and there are no BillKit test card numbers. Mollie owns that part. When you open the url from a test-mode checkout session, Mollie shows its test status selector rather than a real payment form: pick paid to complete the flow, or failed and expired to exercise your failure handling. Mollie’s own test card numbers work in the card form when the selector is not shown.

The console keeps the ones you need under Developers → Test cards: Mollie’s card numbers, and the amounts that make a payment fail for a reason you pick, so you can exercise dunning without waiting for a real decline. Mollie owns those values and changes them occasionally, so its Testing reference is the page to trust if one of them stops working.

Everything downstream is real BillKit behaviour. The mandate is stored, the subscription is created, the invoice is written, the events fire and your webhook endpoint is called.

Test clocks

A test clock is a virtual “now” that you move forward by hand. Attach customers to it, jump the clock past a deadline, and BillKit’s time-driven logic runs as if that moment had arrived.

shell
curl https://api.billkit.eu/v1/test_clocks \
-H "Authorization: Bearer $BILLKIT_API_KEY" \
-H "Content-Type: application/json" \
-d '{"frozen_time": 1789344000, "name": "trial conversion"}'

frozen_time is Unix seconds. Attach a customer to the clock at creation time, using the test_clock field on POST /v1/customers. That field is rejected on a live key. Then advance it, which is a separate call and must always move forward.

shell
curl https://api.billkit.eu/v1/test_clocks/tc_9Yx2Rn6vQt4mLpKbdw/advance \
-H "Authorization: Bearer $BILLKIT_API_KEY" \
-H "Content-Type: application/json" \
-d '{"frozen_time": 1791936000}'

The advance call runs to completion before it returns, so by the time you get a response the work is done and you can read the results immediately.

What a clock does and does not move

Advancing the clockEffect
Trial expiryTrials past trial_end are reaped: subscription.trial_ended, or subscription.canceled if the customer had already cancelled during the trial.
Metered period closeOpen periods are closed, the usage invoice is written, and the mandate is charged.
Dunning noticesThe dunning notifier runs against past-due subscriptions attached to the clock.
One-off payment expiryUnpaid one-off payments past their expiry become terminal.
Mollie renewalsNot affected. Mollie runs its own schedule on real time, and BillKit cannot fast-forward another company’s clock.
created / updated timestampsNot affected. Those are stamped by the database on real time.

A clock only touches customers attached to it. The ordinary background workers skip clock-attached customers entirely, so an advance can never reach into anyone else’s data, and a clock in one account is invisible to another.

Clocks are test mode only. Every route under /v1/test_clocks refuses a live-mode key with a 400, regardless of the key’s scopes. Deleting a clock detaches its customers rather than deleting them.

Going live

Nothing about your integration changes except the key and the Mollie credential. Endpoints, field names and event types are identical, and going live adds the live half rather than ending test mode.

The console gates the switch under Settings → Go live on three blocking requirements: a Mollie credential for live mode, at least one live price, and at least one payment that has actually succeeded in test mode. Connecting with Mollie satisfies the first in one step because a single authorisation covers both modes; a pasted test key does not, since credentials are per mode with no fallback between them. A verified custom domain and a live webhook endpoint are flagged as recommended but do not block.