Skip to content
Docs / Testing

Testing

Build and exercise the whole payment path without moving money. Test mode is a property of the API key you use — not a separate environment you deploy against.

Test keys

In the Flik portal, turn on Test Mode — the switch at the bottom of the sidebar — then open API Keys and choose New key. A key made while Test Mode is on is a test key; made with it off, a live key. That is fixed for the life of the key — you cannot flip it later — and the keys list shows only the keys for whichever mode the switch is in. Mint one key per environment.

You can tell them apart from the credentials themselves. Test keys carry flik_test_; live keys carry flik_live_.

Two environments, two prefixes
# staging
FLIK_CLIENT_ID=flik_test_cid_8Fq2mXbRt7yLpK3nVwZaQ4
FLIK_CLIENT_SECRET=flik_test_sk_3f9c1a7d2e8b4056cc1d9e7a3b5f21c4

# production
FLIK_CLIENT_ID=flik_live_cid_4Rm9tYuIo2pAsD6fGh1JkT
FLIK_CLIENT_SECRET=flik_live_sk_7b2e4c8a1d3f9056aa7c2e4b8d1f6a30

Assert on the prefix at boot

Because the prefix is part of the credential, your application can check it. Do that in whatever loads your configuration, and refuse to start if the key does not match the environment:

const clientId = process.env.FLIK_CLIENT_ID;
const expected =
  process.env.NODE_ENV === "production" ? "flik_live_" : "flik_test_";

if (!clientId || !clientId.startsWith(expected)) {
  throw new Error(
    `FLIK_CLIENT_ID must start with ${expected} in ${process.env.NODE_ENV}`
  );
}

The failure this prevents is a live key sitting in a staging config — copied in during an incident, restored from the wrong secret store, pasted into the wrong pipeline variable. Without the check, nothing looks wrong until your integration tests take real money off a real customer. A crash at boot is a cheap way to find out.

Same URL, same endpoints

Both modes use https://app.flik.co.nz and the same paths. There is no sandbox host to point at and no /test/ prefix. Going live means swapping the client ID and secret; nothing else in your code or configuration changes.

The other half of that is worth saying out loud: nothing in a URL or a log line tells you which mode a call ran in. The key decides, and only the key. If you need to know after the fact, look at testMode on the response.

Test and live share one organisation A test key and a live key belong to the same organisation, so either can read the other's sessions and links — GET /api/checkout-sessions/{id} answers for both. What tells them apart is testMode on the response, which is why your integration tests should assert on it. Keep the two apart in your own systems: never seed live records from test ones, and never treat a test payment as money.

What test mode does

Test mode is not a stub. Requests hit the same API, run the same validation and create real rows: a checkout session gets an id, a transaction id, an expiry and a checkout URL, and it moves through the same created, pending, completed, failed and expired statuses as any other. Anything your code does with a live response, it can do with a test one.

What does not happen is the money. No bank is contacted, no card is processed, nothing settles. Every response created by a test key carries "testMode": true:

GET /api/checkout-sessions/{id}
{
  "id": "cs_7Hk2pQr4TnVxWy9BdLmE",
  "status": "completed",
  "amount": { "total": 25.00, "currency": "NZD" },
  "checkoutMethod": "both",
  "transactionType": "open_banking",
  "testMode": true,
  "foreignTransactionId": "order-5591"
}

Assert on that field in your integration tests. It is the one signal in the response that proves the suite is not pointed at production.

Completing a test payment

Create the session and redirect the customer to url, exactly as you would in live. The checkout page looks exactly like the live one, with a Test mode badge above the amount. On the card rail, enter one of the test cards below — any name, email, future expiry and CVC. On the bank rail, pick any bank and press Pay: there is no consent step, and the payment settles immediately.

Either way the session behaves as a completed payment from there on: the status becomes completed, transactionType records which rail was simulated, the customer is sent to your redirectUrl, and the webhook fires. That is the whole flow, end to end, with no money involved.

Test cards

A test session set to card or both accepts the numbers below. They are recognised by Flik in test mode only — no real card is involved, nothing reaches a card network, and no money moves. Any future expiry and any CVC work.

Number Brand Result
4111 1111 1111 1111 Visa Approved
5555 5555 5555 4444 Mastercard Approved
3714 496353 98431 American Express Approved
4000 0000 0000 0002 Visa Declined
5555 0000 0000 0008 Mastercard Declined
3700 000000 00002 American Express Declined

Test the declines. A card that is refused is the one path most integrations never exercise, and it is the one your customer hits on a Friday night. A declined test card leaves the session status at failed, sends nothing to your webhook — a decline is not a terminal outcome, and the customer can try again on the same URL — and is exactly what your checkout has to recover from in live.

What test mode skips

Test mode does not run the eligibility checks a live payment needs. It does not require an approved open banking application, and it does not require a configured settlement account. That is deliberate — it means you can integrate while your account is still being verified, rather than waiting on approval before you write a line of code.

The consequence matters more than the convenience. A request that succeeds with a test key can fail with a live key. Same payload, same endpoint, same code — and a live key returns an eligibility error because something in the portal is not set up yet. A green test suite proves your integration is correct. It does not prove your account is ready to take payments.

Handle those errors explicitly, and read what they mean on Errors before you go live. They are not bugs in your code; they are instructions about your account.

Webhooks in test mode

Webhooks fire in test mode, to the webhookUrl you set on the session, signed with the same secret and the same scheme as live. Completing a test payment posts checkout_session.completed. Letting one expire posts nothing — an expired session is a status you read, not an event.

Because the endpoint is a per-session field, test deliveries go wherever you point them — there is no shared endpoint to fight over and nothing to put back afterwards. Verification is testable before you go live, and it should be. Run your endpoint behind a tunnel, complete a test payment, and confirm the signature check passes on a real delivery rather than on a fixture you wrote yourself. See Webhooks.

Going live

Work through this before you take a payment from a customer.

  1. Swap in a live key

    Replace the credentials in your production configuration with a flik_live_ pair. Nothing else changes — same base URL, same endpoints. Confirm the prefix check from above is running in production too, so a test key in live fails loudly rather than quietly taking no money.

  2. Verify webhook signatures, if you take webhooks

    Skip this if you confirm payments by reading them back, which is what Flik recommends — there is no endpoint to attack. If you do run one, it is public: if it grants goods without checking Flik-Signature, anyone who finds the URL can place free orders. Verify over the raw body, compare in constant time, and reject stale timestamps — Webhooks has working code.

  3. Handle every error code

    Decide what your application does for each code on Errors, including the eligibility ones test mode never showed you. A payment that cannot start should tell the customer something true, not throw a stack trace at them.

  4. Check the portal side

    Confirm your settlement account is configured and your payment methods are enabled for the rails and currencies you actually sell in. Open banking is NZD only; if you charge in AUD, card is the rail those payments will use.

  5. Run one real payment

    Small amount, live key, your own bank account or card. Follow it all the way: the session completes, the webhook arrives and verifies, your order is fulfilled once, and the money reaches your settlement account. This is the only step that tests the parts test mode deliberately skipped.