Go-Live Checklist
Complete every item before switching from staging to production. Each item addresses a specific failure mode observed in real integrations.
Do not go live until every item on this checklist is verified. Skipping items leads to production incidents that are entirely preventable.
Credentials and endpoints
1. Replace staging API key with production key
Update your environment configuration to use the production API key. Staging keys do not work against the production URL.
# Before (staging)
ZENOO_API_KEY=stg_your_staging_key
# After (production)
ZENOO_API_KEY=prod_your_production_key
2. Update base URL to production
Switch from the staging URL to the production URL. This must change everywhere your application makes Zenoo API calls.
# Before (staging)
ZENOO_BASE_URL=https://instance.staging.onboardapp.io
# After (production)
ZENOO_BASE_URL=https://instance.prod.onboardapp.io
3. Update webhook endpoint to production URL
Point Zenoo at your production webhook endpoint. Contact your Zenoo account manager to update the webhook URL, or configure it in the Zenoo dashboard.
Staging and production webhooks use different secrets. Update the secret in your configuration.
Security
4. Verify webhook signature validation works
Confirm that your webhook handler validates the X-Zenoo-Signature header on every request. Test by sending a webhook with a tampered payload and verifying that your handler rejects it.
const crypto = require("crypto");
function verifySignature(rawBody, signature, secret) {
const expected =
"sha256=" +
crypto.createHmac("sha256", secret).update(rawBody).digest("hex");
return crypto.timingSafeEqual(Buffer.from(signature), Buffer.from(expected));
}
// Reject unverified webhooks
if (
!verifySignature(rawBody, req.headers["x-zenoo-signature"], webhookSecret)
) {
return res.status(401).json({ error: "Invalid signature" });
}
Resilience
5. Implement exponential backoff retry logic
Your API client should retry 5xx errors and timeouts with increasing delays. Never retry 4xx errors without fixing the request.
const RETRY_DELAYS = [0, 5000, 25000, 60000]; // 4 attempts max
async function callZenoo(requestFn) {
for (let attempt = 0; attempt < RETRY_DELAYS.length; attempt++) {
if (attempt > 0) await sleep(RETRY_DELAYS[attempt]);
const response = await requestFn();
if (response.status === 429) {
const retryAfter = parseInt(response.headers.get("Retry-After") || "60");
await sleep(retryAfter * 1000);
continue;
}
if (response.status >= 500 && attempt < RETRY_DELAYS.length - 1) {
continue;
}
return response;
}
}
6. Set up idempotency with external_reference
Include external_reference on every verification request. This prevents duplicate verifications caused by retries, user double-clicks, or race conditions.
{
"company_name": "Acme Holdings Ltd",
"registration_number": "12345678",
"country": "GB",
"external_reference": "your-unique-internal-id-here"
}
Use a stable, unique identifier from your system: application ID, customer reference, or order number. If the same external_reference is submitted twice, Zenoo returns the existing case.
Result handling
7. Handle all verdict outcomes
Your application must handle all three overall_verdict values. Verify your decision logic:
| Verdict | Required action |
|---|
Pass | Proceed with onboarding or approval |
Refer | Route to manual compliance review |
Fail | Block onboarding, escalate to compliance team |
Do not assume all results will be
Pass. Test your
Refer and
Fail code paths with the
staging test data.
8. Handle webhook edge cases
Your webhook handler must process all five event types, not just verification.completed:
| Event | Required action |
|---|
verification.completed | Process results, update customer record |
screening.completed | Review matches, update risk profile |
journey.abandoned | Send reminder or create a new journey |
journey.expired | Create a new verification journey |
check.failed | Alert compliance team for manual intervention |
Ignoring journey.abandoned or journey.expired events causes customers to get stuck in your onboarding flow.
9. Implement webhook deduplication
Zenoo may deliver the same webhook more than once. Your handler must be idempotent.
app.post("/webhooks/zenoo", async (req, res) => {
const { journey_id, event_type } = req.body;
// Check for duplicate delivery
const existing = await db.webhookEvents.findOne({ journey_id, event_type });
if (existing) {
return res.status(200).json({ received: true });
}
// Store before processing to prevent race conditions
await db.webhookEvents.create({ journey_id, event_type, payload: req.body });
await processEvent(req.body);
res.status(200).json({ received: true });
});
Always return 200 for duplicates to prevent unnecessary retries.
Monitoring
10. Set up monitoring
Track these metrics from day one:
| Metric | Alert threshold |
|---|
| API error rate (5xx) | > 5% over 10 minutes |
| Webhook delivery failures | > 3 consecutive failures |
| Average response time | > 30 seconds (sync mode) |
| Verification completion rate | < 90% over 1 hour |
| Sanctions hit rate | Sudden spike (> 2x normal) |
Use the request_id from error responses to correlate application logs with Zenoo server logs.
11. Test one real verification in production
After completing items 1-10, run a single real verification in production. Use a real company or individual (not test data). Confirm:
- API call succeeds with
200 response
- Response contains valid
overall_verdict and risk_tier
- Webhook is delivered to your production endpoint
- Webhook signature verifies correctly
- Your application processes the result correctly
Set up automated alerts for:
- 5xx error spikes from the Zenoo API. These indicate server-side issues, contact Zenoo support.
- Webhook delivery failures. If your endpoint returns non-2xx for more than 3 consecutive webhooks, investigate immediately.
- Verification timeout increases. A sustained increase in response times may indicate provider degradation.
- Unusual verdict distributions. A sudden spike in
Fail verdicts may indicate a configuration issue, not actual compliance failures.
Summary
Complete all 12 items before going live. Each item addresses a real production failure mode.
| # | Item | Status |
|---|
| 1 | Replace staging API key with production key | [ ] |
| 2 | Update base URL to production | [ ] |
| 3 | Update webhook endpoint to production URL | [ ] |
| 4 | Verify webhook signature validation works | [ ] |
| 5 | Implement exponential backoff retry logic | [ ] |
| 6 | Set up idempotency with external_reference | [ ] |
| 7 | Handle all verdict outcomes (Pass, Refer, Fail) | [ ] |
| 8 | Handle webhook edge cases (abandoned, expired, failed) | [ ] |
| 9 | Implement webhook deduplication | [ ] |
| 10 | Set up monitoring (error rates, webhooks, response times) | [ ] |
| 11 | Test one real verification in production | [ ] |
| 12 | Configure alerts for 5xx spikes and webhook failures | [ ] |
Next steps