# Production Readiness

Test the integration in the sandbox. Then complete the go-live checklist.

## Test in the sandbox

Use the sandbox environment and the sandbox API key for integration and tests.
The API contract is the same in both environments. A working sandbox
integration moves to production when you change the hosts and the API key.

Test the full flow from start to end:

1. Create a session.
2. Complete verification in the widget.
3. Receive `privy:success`.
4. Exchange the code.
5. Verify the JWT.
6. Receive the server callback.

Also test the failure branches of the
[user journey](/digital-id/concepts/user-journey): face-match retry, consent
rejection, and consent timeout.

## Go-live checklist

| # | Item | Reference |
| --- | --- | --- |
| 1 | Get the production API key from Privy. Store it only on the merchant backend. | [Authentication](/digital-id/concepts/authentication) |
| 2 | Change the API and widget hosts to the production base URLs. | [Environments](/digital-id/concepts/environments) |
| 3 | Register the production merchant origin in the Privy allowlist. | [Web Integration](/digital-id/guides/web-integration) |
| 4 | Configure the production `callback_url` with the Privy team. | [Server Callback](/digital-id/guides/server-callback) |
| 5 | Create sessions only from the merchant backend. | [Security](/digital-id/guides/security) |
| 6 | Validate `event.origin` against the production widget origin. | [Web Integration](/digital-id/guides/web-integration) |
| 7 | Verify the JWT signature and the `aud`, `exp`, and `iss` claims on the backend. | [Verify the JWT](/digital-id/guides/verify-jwt) |
| 8 | Identity package only: store the RSA private key in the backend secret manager. Decrypt `my_identity` only after JWT verification. | [Encrypted Identity Data](/digital-id/guides/encrypted-identity-data) |
| 9 | Base business decisions only on the verified JWT. Make result processing idempotent by `session_id`. | [Server Callback](/digital-id/guides/server-callback) |
| 10 | Add `allow="camera"` to the iframe. Declare `NSCameraUsageDescription` or `android.permission.CAMERA` in WebView applications. | [Camera and Permissions](/digital-id/guides/camera-and-permissions) |
| 11 | Handle all error surfaces: API statuses, `privy:error`, `privy:cancel`, and camera guard errors. | [Error Catalog](/digital-id/api-reference/errors) |
| 12 | Acknowledge the callback within 60 seconds. Move long work to asynchronous processing. | [Server Callback](/digital-id/guides/server-callback) |
| 13 | Handle the session lifecycle: create-timeout retry, retained `session_id`, `session_url`, and `expires_at`, and expired-session restart. Do not log `session_url`. | [Session Lifecycle](/digital-id/concepts/session-lifecycle) |
| 14 | Confirm the data package and widget settings with Privy: the package and its data items, the consent confirmation window, the default OTP channel, and the terms-of-use and privacy-policy URLs. | [Data Packages](/digital-id/concepts/data-packages) |
| 15 | Review the API contract limitations and include them in the integration design. | [API Limitations](/digital-id/api-reference/limitations) |
