Migrating from sandbox to live
Sandbox and live are separate environments. A live rollout is a configuration and credential promotion, not an in-place conversion of sandbox data.
Environment mapping
| Setting | Sandbox | Live |
|---|---|---|
| API key | sk_test_... | sk_live_... |
| SDK mode | test | live |
| Base URL | staging Gateway URL | production Gateway URL |
Session livemode | false | true |
| Webhook signing secret | staging secret | production secret |
| Data and queues | staging bindings | production bindings |
API keys can also carry an optional absolute expires_at timestamp. Keep short-lived sandbox keys for CI and pre-production access, and provision a separate future expiry for live credentials according to your rotation policy. An expired key is rejected by the Gateway even if it was previously cached. The key lifecycle resources also expose last_used_at; it is null until the first successful authentication and is updated asynchronously with a bounded write frequency.
Newly issued keys are also bound to their environment at rest. The Gateway rejects a key whose stored environment does not match the current deployment, in addition to rejecting sk_test_/sk_live_ prefix mismatches. Legacy operator-provisioned keys without this metadata remain valid during migration; new provisioning and rotation write the binding automatically.
Restricted-key management is least-privilege: api_keys:manage can list, rotate, and revoke tenant keys, while a child key may only delegate scopes it already has. A session-only key cannot manage keys or account-level webhooks.
Webhook verification accepts an optional atomic replayStore. Use a shared Redis/KV/Durable Object implementation in production; the SDK's createMemoryWebhookReplayStore() is intended for local development and single-process tests only. A delivery is claimed after signature and JSON validation, and a second attempt within the signature tolerance raises DlbrIdWebhookReplayError.
Keep these values in separate secret-manager scopes. Do not copy a sandbox key, webhook secret, tenant database record, or trust-store material into production.
Recommended promotion sequence
1. Freeze the integration contract
Before provisioning live credentials, confirm that the production deployment supports the same API version used by the application:
const id = new DlbrId({
baseUrl: process.env.DLBR_ID_BASE_URL!,
apiKey: process.env.DLBR_ID_API_KEY!,
mode: process.env.DLBR_ID_MODE === "live" ? "live" : "test",
apiVersion: "2026-09-21",
});Use one explicit configuration object per deployment. Do not infer live mode from a hostname alone.
2. Provision live credentials separately
An operator creates a production key and webhook endpoint in the production environment. The plaintext key and signing secret are shown once.
cd apps/gateway
pnpm run provision:client -- \
--client-id acme-bank \
--allowed-origins https://app.acme.example \
--remoteThe production command defaults to the production D1 database and emits an sk_live_... key. Use a separate production webhook endpoint and verify its delivery before switching traffic.
3. Configure live secrets atomically
Update the application deployment as one change:
DLBR_ID_BASE_URL=https://<production-gateway>
DLBR_ID_API_KEY=sk_live_...
DLBR_ID_MODE=live
DLBR_ID_WEBHOOK_SECRET=whsec_live_...Never put these values in NEXT_PUBLIC_*, client-side JavaScript, URLs, or logs. The SDK will reject mode: "live" with a test key and requires an HTTPS base URL.
4. Run a production preflight
Before allowing customer traffic, create one controlled verification session and assert the environment metadata:
const session = await id.sessions.create({
credentials: [{
format: "mso_mdoc",
issuer_id: "https://issuer.example",
namespace: "org.iso.18013.5.1",
claims: ["given_name"],
}],
});
if (!session.livemode) {
throw new Error("Live deployment returned a sandbox session");
}Verify the webhook with the live signing secret and record the returned requestId for the rollout log. Do not use real customer identity data for a preflight unless the approved production test procedure requires it.
5. Switch traffic and monitor
Use a gradual application rollout where available. Monitor:
- session creation error rate and
requestIdcorrelation; livemodevalues in server-side telemetry;- webhook delivery and signature verification failures;
- rate limits and retry volume;
- audit-log entries in the production tenant.
The SDK's onRequest callback is suitable for metrics, but redact API keys, claims, QR URLs, and webhook bodies from telemetry.
Rollback
Rollback is a configuration switch, not a key mutation:
- Stop new live traffic at the application layer.
- Restore the last known-good live configuration or route new traffic back to sandbox only for test tenants.
- Do not send live customer sessions to sandbox.
- Revoke the live key if compromise is suspected; otherwise keep it disabled until the incident is understood.
- Use the captured
requestIdvalues to investigate Gateway errors.
Existing live sessions remain live sessions. A rollback must not retry their identifiers against sandbox.
Post-migration cleanup
- Confirm the production key is stored and access-controlled.
- Revoke temporary preflight keys.
- Confirm staging and production webhook secrets are distinct.
- Update the runbook with deployment version, API version, key IDs, and preflight request ID — never plaintext secrets.
- Keep sandbox credentials available for non-production QA; do not delete them as part of live promotion.