Test mode

A qb_test_sk_… key works on the sandbox app. You can run the whole flow without any real money.

What changes with a test key

  • No call is made to Wave.
  • No invoice email is sent.
  • Invoice numbers start with TEST-INV-.
  • Webhook events carry livemode: false.

The simulated checkout page

Call payments.initiate (POST /v1/payments/initiate) with a test key: the answer holds a redirectUrl, which leads to a QBill test checkout page. That page has two buttons, Pay and Decline.

curl -X POST https://api.qbill.dev/v1/payments/initiate \
  -H "x-api-key: qb_test_sk_…" \
  -H "content-type: application/json" \
  -d '{"invoice_id":"<invoice id>","phone_number":"+2250700000000","provider":"wave"}'
  • Pay: the invoice becomes paid and the invoice.paid event is sent.
  • Decline: the payment becomes failed and reminders start (see Dunning).

With the Node SDK (coming to npm): qbill.payments.initiate({ invoice_id, phone_number }).

To receive the events, see Webhooks.

Going live

Create a qb_live_sk_… key on the live app and swap it in for the test key. Your code does not change: same routes, same request bodies. Only the key changes, and with it the app (see Authentication & keys).