Going live
What to have in place before you point a live key at real money, and how to prove each item rather than assume it.
Sandbox and live differ in one thing only: whether the money is real. The API surface is identical, so going live is not a migration. It is a checklist of things that were survivable in testing and are not survivable in production.
Each item below says how to prove it, because "we handle that" and "we tested that failing" are different states.
Credentials
- A live key exists and the sandbox key is not in the deployment. Keys carry
their environment in the token (
sk_live_versussk_sandbox_), so a sandbox key pointed at production fails to authenticate rather than doing something expensive. Prove it by grepping your deployed configuration forsk_sandbox_. - The key is in a secret manager, not in an image, a repository or an environment file in version control. It is shown once at issuance and stored only as an Argon2id hash, so a lost key is reissued, never recovered.
- You know the key expires. Keys are issued with a 365-day lifetime. Put the
date in the same calendar that holds your certificate renewals, because the
expiry arrives as an ordinary
401with no warning. - Rotation is create, deploy, verify, then revoke, in that order. Revoking first is an outage. Revocation reaches the platform within its introspection cache, so allow a minute before assuming an old key is dead.
- Scopes are the narrowest that work. A key with
*is a key whose blast radius is the whole tenant.
Idempotency
- Every money-moving call sends an
Idempotency-Keyderived from a business object, not a fresh UUID per attempt and not a timestamp. A key that changes on retry defeats the entire mechanism. - You have tested a replay. Send the same request twice with one key and assert one movement and an identical response. See Idempotency.
Webhooks
- The receiver verifies the signature over the raw bytes, in constant time, before parsing. Re-serialising the body changes the hash.
- The receiver rejects deliveries outside a tolerance you chose. The platform signs with the current time on every attempt and enforces no window of its own, so replay protection is yours. Five minutes is a reasonable default.
- The receiver is idempotent on the verified body’s
(tenant_id, id).X-Wallet-Event-Idis unsigned and advisory; changing it must not create work. - It acknowledges only after durable inbox acceptance, then works asynchronously. A slow receiver does not slow your payments, but it does burn your retry budget.
- You have tested a bad signature. Flip one byte of a delivery body and assert your endpoint refuses it. See Webhooks.
Money handling
- Nothing treats a client-side callback as a credit. A balance rises when a verified gateway confirmation arrives, never when a browser says the payment succeeded. See Top-ups.
- Your UI shows
available, notbalance. Showingbalancetells a user they have money that an uncaptured authorization has already spoken for. - Amounts are integer minor units end to end, with no float anywhere on the path in or out.
- You branch on the
codefield of an error, never ontitleordetail. See Errors.
Reconciliation and monitoring
- You reconcile against
GET /v1/ledger/summary, which reports the identity that has to hold between what entered, what users and merchants hold, and what has left. See The money model. - You alert on the events that mean something went wrong rather than nothing
happening:
topup.amount_mismatch(the processor took a different amount than the intent),payment.expired(a hold was never captured), and the dunning events on subscriptions. - You have a retry and dead-letter path for your own webhook processing. Event history is retained for 30 days and redelivery is available inside that window, but the platform's history is a recovery buffer, not your system of record.
Limits
- You have read the rate budgets and concurrency compartments and your traffic shape fits them, including your retry behaviour under failure. A retry storm is a traffic shape.
- You handle
429and503by honouringRetry-Afterrather than retrying immediately.
Support
- You know your severity levels and how to raise an incident. See Support, SLAs and status.
- You know that WalletD support cannot read your data without a grant you create, and who on your side is allowed to create one.
Sign-off
| Area | Proven by | Owner | Date |
|---|---|---|---|
| Credentials in a secret manager, scoped, rotation rehearsed | |||
| Idempotent replay tested | |||
| Webhook signature, tolerance and replay tested | |||
| No client-side credit path | |||
| Reconciliation running against the ledger summary | |||
| Alerts on mismatch, expiry and dunning | |||
| Behaviour under 429 and 503 tested | |||
| Incident path and contacts agreed |
Environments, limits and quotas
Sandbox and live credentials, the base URL convention, the rate budgets and concurrency compartments the gateway enforces, and what a 429 or a 503 means.
Security for integrators
Credential formats and lifecycles, scopes, user tokens, webhook signing, what the platform records and for how long, what is not offered today, and how to report a vulnerability.