Skip to content
PayDirect Docs

Docs › Reference

Going live

What to verify before you switch from pk_test_ to pk_live_, and what to watch in the first week.

Going live is a credential swap - the code is identical. That is exactly why it is worth a deliberate checklist: nothing will break at the boundary to warn you that something was untested.

Before you switch

Credentials

  • [ ] A PRODUCTION key issued, with explicit scopes - not an unscoped key. See API keys.
  • [ ] PAYOUTS_WRITE granted only if you genuinely disburse to third parties. If you only cash out to yourself, WITHDRAWALS_WRITE alone is strictly safer.
  • [ ] Raw key and secret key in a secret manager, not in a repository, an image, or a .env committed anywhere.
  • [ ] A rotation procedure written down, and rehearsed once with test keys.

Correctness

  • [ ] Idempotency-Key sent on every write, derived from something stable, and persisted before the first attempt.
  • [ ] Your client reads data.status, not just response.ok - a 200 with "status": "error" is handled as a failure. See Errors.
  • [ ] 429 handled without parsing the body as JSON (it is plain text) and retried with jittered exponential backoff.
  • [ ] 409 retried with the same idempotency key, never a new one.
  • [ ] Amounts held in a decimal type, never a binary float.
  • [ ] You display and reconcile totalDebit, not your own arithmetic.

Webhooks

  • [ ] webhookUrl set to a production HTTPS endpoint.
  • [ ] A signing secret held in your secret manager - and unsigned deliveries rejected.
  • [ ] Signature verified against the raw body, with a timestamp tolerance and a constant-time compare.
  • [ ] Handler branches on environment - a TEST event must not be processed as real.
  • [ ] Deduped on eventId, with the claim persisted for at least 30 days.
  • [ ] Returns 2xx in under a couple of seconds; real work happens out of band.
  • [ ] Unknown event types acknowledged and ignored, not 500'd.

Operations

  • [ ] A daily reconciliation sweep, running and alerting - not a script someone runs by hand.
  • [ ] Alerting on: PENDING transactions older than expected, your own webhook handler error rate, and RateLimit-Remaining trending toward zero.
  • [ ] Settlement account registered for each currency you will withdraw in, and verified with one small withdrawal made with a sandbox key.
  • [ ] Someone on your side owns payment incidents and knows where the transaction id, the journey snapshot and the delivery log live.

Tested before launch, not just the happy path

Test keys resolve every payment immediately, so the PENDING cases need a sandbox key and a real GHS 1 payment.

  • [ ] A PENDING collection resolved by a webhook.
  • [ ] A PENDING collection resolved by a reconcile, with the webhook deliberately blocked.
  • [ ] A FAILED payout, and your books left correct afterwards.
  • [ ] A duplicate Idempotency-Key replay (200 identical) and a mismatched-body reuse (422).
  • [ ] A forged webhook signature - rejected.
  • [ ] A missing webhook signature header - rejected.
  • [ ] Your endpoint returning 500, and the delivery retried and eventually succeeding.

The switch

  1. Confirm the live settlement account.
  2. With a sandbox key, run one small real transaction end to end, in each direction you support: a GHS 1 collection and a GHS 1 payout to a phone someone in the room is holding.
  3. Verify it in GET /transactions/find/{id}, in the webhook your endpoint received, and in the ledger entry.
  4. Deploy your production credentials - the code does not change.
  5. Only then open the flow to customers.

Caution

Do not skip step 2. Test keys mock every payment, so a sandbox transaction is the first time a real bank or mobile money network handles your integration's requests. Make it a GHS 1 one you are watching, not a customer's GHS 5,000 one.

The first week

  • Read the changelog before each deploy.
  • Reconcile daily and actually look at the output, even when it is clean - that is how you learn what normal looks like.
  • Watch your PENDING ageing distribution. A rail getting slower shows up there first.
  • Keep your test-key integration alive and deployable. It is where you will reproduce the first production oddity.

Tip

Ramp rather than switch. Route a small share of real volume through the live path for the first few days, with a kill switch back to your previous flow. Payment bugs are cheapest to find at 1% of traffic.

Next

Changelog - contract changes you may need to act on.