Runbook: Sumsub KYC Failure Runbook: Sumsub KYC/AML Verification Failure Service: Sumsub Identity Verification (KYC/AML) Severity: HIGH (blocks new user registrations) MTTR Target: <30 minutes Owner: John (AI Director) Overview Sumsub provides automated identity verification (KYC - Know Your Customer) and AML (Anti-Money Laundering) checks for Drop. Required for regulatory compliance before users can make payments. KYC Process: User uploads ID document (passport, driver's license, national ID) User takes selfie (liveness check) Sumsub verifies document authenticity Sumsub performs AML sanctions screening Result: APPROVED, REJECTED, or MANUAL_REVIEW Impact: If Sumsub fails, new users cannot complete registration. Existing users are unaffected. Symptoms Users report they cannot complete identity verification: ID upload fails with error Verification stuck at "Processing..." indefinitely Error message: "Verification service unavailable" Webhook never receives result from Sumsub User status stuck at "pending_kyc" User impact: Cannot complete registration, cannot make payments. Diagnosis 1. Check Sumsub Service Status External status: # Sumsub does not have a public status page # Test via API health check curl https://api.sumsub.com/resources/healthcheck \ -H "X-App-Token: " \ -v # Expected: HTTP 200 # If 500/503: Sumsub outage 2. Check Drop Logs # CloudWatch Logs (production) aws logs filter-log-events \ --log-group-name /aws/apprunner/drop-production \ --filter-pattern "sumsub" \ --start-time $(date -u -d '30 minutes ago' +%s)000 \ --region eu-west-1 # Look for: # - "Sumsub API timeout" # - "Sumsub webhook failed" # - "KYC verification failed: document_expired" # - "AML sanctions match: [name]" 3. Check Sumsub Dashboard # Login to Sumsub Dashboard open https://cockpit.sumsub.com # Check: # - Recent applicants (last 1 hour) # - Failed verifications # - Manual review queue length # - Webhook delivery status 4. Check Webhook Delivery Verify webhook endpoint is reachable: # Sumsub sends webhooks to: https://getdrop.no/api/webhooks/sumsub # Test endpoint manually curl -X POST https://getdrop.no/api/webhooks/sumsub \ -H "Content-Type: application/json" \ -H "X-Sumsub-Signature: test" \ -d '{"type":"applicantReviewed","reviewResult":{"reviewAnswer":"GREEN"}}' \ -v # Expected: HTTP 200 # If 404: Webhook endpoint not deployed # If 401: Signature validation issue 5. Test KYC Flow Manual test (staging): # 1. Create test applicant curl -X POST https://api.sumsub.com/resources/applicants \ -H "X-App-Token: " \ -H "Content-Type: application/json" \ -d '{ "externalUserId": "test-user-123", "levelName": "basic-kyc-level", "email": "test@example.com" }' \ -v # Expected: HTTP 201, applicant created # If 400: Invalid request # If 500: Sumsub API issue Common Causes & Solutions Cause 1: Sumsub API Outage (External) Probability: 5% (Sumsub service disruption) Symptoms: All KYC verifications fail Sumsub API health check returns 503 Dashboard shows no recent applicants Logs show API timeouts Solution: Verify outage: # Test Sumsub API from different networks curl https://api.sumsub.com/resources/healthcheck \ -H "X-App-Token: " \ -v # If consistent failure: confirmed outage Contact Sumsub support: Email: support@sumsub.com Live chat: https://cockpit.sumsub.com (bottom-right) Phone: Check Sumsub Dashboard for support number Communicate to users (Norwegian): Emne: Identitetsverifisering midlertidig utilgjengelig Hei, Vi opplever for øyeblikket tekniske problemer med identitetsverifisering. Du kan fortsette registreringen senere. Vi forventer at tjenesten er tilbake innen [X minutter/timer]. Mvh, Drop Queue pending verifications: -- Mark users as pending KYC retry UPDATE users SET kyc_status = 'pending_retry', kyc_retry_at = datetime('now', '+1 hour') WHERE kyc_status = 'pending_kyc' AND created_at > datetime('now', '-2 hours'); Retry when Sumsub is back: # Cron job to retry pending KYC node ~/ALAI/products/Drop/scripts/retry-kyc.js ETA: Depends on Sumsub (typically <2 hours) Cause 2: Document Verification Failure (User Error) Probability: 40% (user uploads poor quality or invalid document) Symptoms: Specific users fail KYC (not all users) Logs show: "document_not_readable", "document_expired", "document_type_mismatch" Sumsub dashboard shows rejection reason Common rejection reasons: Blurry photo (document not readable) Expired document (passport/ID expired) Wrong document type (e.g., bank statement instead of ID) Photo cropped (missing corners/edges) Underage (user < 18 years old) Solution: Identify rejection reason: SELECT user_id, kyc_rejection_reason, kyc_rejected_at FROM users WHERE kyc_status = 'rejected' ORDER BY kyc_rejected_at DESC LIMIT 10; Show clear error to user (Norwegian): Blurry document: Dokumentet er ikke leselig Ta et nytt bilde i godt lys. Sørg for at all tekst er skarp og leselig. Expired document: Dokumentet er utløpt Vennligst last opp et gyldig pass eller førerkort. Dokumentet må være gyldig i minst 1 måned. Wrong document type: Feil dokumenttype Vi godtar kun: Pass, Nasjonalt ID-kort, Førerkort. Bankkort og regninger godtas ikke. Underage: Du må være 18 år eller eldre Drop er kun tilgjengelig for brukere over 18 år. Allow user to retry: Show "Try Again" button in app Provide tips for better photo quality Link to FAQ: "How to take a good ID photo" Track retry success rate: -- How many users succeed on 2nd attempt? SELECT COUNT(*) FILTER (WHERE kyc_attempt = 1 AND kyc_status = 'approved') as first_attempt_success, COUNT(*) FILTER (WHERE kyc_attempt = 2 AND kyc_status = 'approved') as second_attempt_success, COUNT(*) FILTER (WHERE kyc_attempt >= 3) as multiple_retries FROM users; ETA: Immediate (user must retry with better document) Cause 3: AML Sanctions Match (Compliance Issue) Probability: 3% (user flagged by sanctions screening) Symptoms: Specific user's KYC fails with: "AML_SANCTIONS_MATCH" Sumsub dashboard shows "Red flag" or "Manual review required" User name matches sanctions list (OFAC, EU, UN, etc.) Solution: Identify flagged users: SELECT user_id, email, full_name, kyc_rejection_reason FROM users WHERE kyc_rejection_reason LIKE '%sanctions%' OR kyc_status = 'manual_review_aml'; Review Sumsub dashboard: Login: https://cockpit.sumsub.com Navigate to applicant Check AML screening results Review sanctions list match details False positive (common names): Example: "Ali Hassan" may match many sanctioned individuals Sumsub shows match details (date of birth, nationality) If clearly different person: manually approve in Sumsub True positive (actual sanctions match): DO NOT approve. This is a legal/regulatory issue. Reject user registration immediately Document incident for compliance records Notify user (if false positive, manually approved): Din identitetsverifisering er godkjent Takk for tålmodigheten. Du kan nå bruke Drop. Notify user (if true positive, rejected): Vi kan dessverre ikke godkjenne din registrering På grunn av regulatoriske krav kan vi ikke tilby tjenester til deg. Ta kontakt med support@getdrop.no hvis du mener dette er en feil. Escalate to Alem if uncertain: AML compliance is critical False rejection = bad UX, but false approval = legal risk Alem makes final call on borderline cases ETA: 10 minutes (false positive), N/A (true positive - reject) Cause 4: Webhook Delivery Failure Probability: 15% (Drop webhook endpoint down or unreachable) Symptoms: Sumsub completes verification, but Drop never updates user status Logs show: "Webhook not received" Sumsub dashboard shows "Webhook delivery failed" User stuck at "pending_kyc" despite Sumsub showing "approved" Solution: Check webhook endpoint health: # Test webhook endpoint curl -X POST https://getdrop.no/api/webhooks/sumsub \ -H "Content-Type: application/json" \ -d '{"type":"ping"}' \ -v # Expected: HTTP 200 # If 404/500: Drop webhook endpoint broken Check Sumsub webhook delivery logs: Login: https://cockpit.sumsub.com Navigate to Settings → Webhooks Check recent delivery attempts Look for: 404, 500, timeout errors Manually retry failed webhooks: Sumsub Dashboard → Applicant → "Resend Webhook" This triggers new webhook delivery to Drop Verify Drop receives and processes it Fetch verification results via API (if webhook lost): # Manually fetch applicant status from Sumsub curl -X GET https://api.sumsub.com/resources/applicants//status \ -H "X-App-Token: " \ -v # Parse result and update Drop database Update Drop database manually: UPDATE users SET kyc_status = 'approved', kyc_approved_at = datetime('now') WHERE sumsub_applicant_id = ''; Fix webhook endpoint (if broken): Check App Runner deployment status Verify webhook route exists: src/app/api/webhooks/sumsub/route.ts Check signature validation (Sumsub signs webhooks with HMAC) ETA: 10 minutes (manual retry), 30 minutes (if endpoint fix needed) Cause 5: Invalid or Expired API Credentials Probability: 5% (after credential rotation) Symptoms: Logs show: "401 Unauthorized" or "403 Forbidden" All Sumsub API calls fail Webhook signature validation fails Solution: Verify Sumsub API credentials: bw get item "Sumsub API" --session $BW_SESSION # Check: # - App Token is correct # - Secret Key is correct (for webhook signature) # - Environment: production vs sandbox Regenerate API credentials (if needed): Login: https://cockpit.sumsub.com Navigate to Settings → API Generate new App Token + Secret Key Copy to Vaultwarden Update App Runner environment variables: aws apprunner update-service --service-arn \ --instance-configuration "EnvironmentVariables={ SUMSUB_APP_TOKEN=, SUMSUB_SECRET_KEY=, SUMSUB_ENVIRONMENT=production }" Trigger deployment: aws apprunner start-deployment --service-arn --region eu-west-1 Test after deployment: # Try creating test applicant curl -X POST https://getdrop.no/api/kyc/initiate \ -H "Authorization: Bearer " \ -v # Expected: HTTP 200, Sumsub applicant created ETA: 10 minutes Cause 6: Liveness Check Failure (Selfie) Probability: 20% (user fails selfie/liveness verification) Symptoms: Specific users fail at selfie stage Logs show: "liveness_check_failed", "face_mismatch" Sumsub dashboard shows "Selfie does not match ID photo" Common reasons: Poor lighting (too dark, too bright) User wears sunglasses/hat Multiple people in frame Photo of a photo (not live person) Face does not match ID document Solution: Show clear instructions before selfie (Norwegian): Slik tar du et godt selfie-bilde: ✓ God belysning (dagslys er best) ✓ Fjern briller/solbriller ✓ Se rett i kameraet ✓ Kun ditt ansikt i bildet ✗ Ikke bruk foto av foto Allow retry with better instructions: Selfie-verifisering mislyktes Prøv igjen med bedre belysning. Sørg for at ansiktet ditt er tydelig synlig. Improve liveness detection settings (if too strict): Login: https://cockpit.sumsub.com Navigate to Settings → Verification Levels Adjust liveness sensitivity (low/medium/high) Balance: security vs user friction Manual review (if automated fails repeatedly): Some users may need manual review Sumsub team reviews video/photos manually ETA: 1-24 hours depending on Sumsub queue ETA: Immediate (user retry), 1-24 hours (manual review) Emergency Workarounds Option 1: Manual KYC Review (Temporary) Use case: Sumsub down >1 hour, urgent user needs verification Steps: Collect KYC documents manually: Ask user to email ID photo + selfie to support@getdrop.no Subject: "KYC Manual Review - [User ID]" Alem or John reviews manually: Verify ID document authenticity (check security features) Compare selfie to ID photo Check ID expiry date Verify age >= 18 Manual AML check: Search user name on: https://sanctionssearch.ofac.treas.gov Check EU sanctions list: https://eeas.europa.eu/topics/sanctions-policy Document findings Approve in database (if passes checks): UPDATE users SET kyc_status = 'approved_manual', kyc_approved_at = datetime('now'), kyc_approved_by = 'john', kyc_notes = 'Manual review during Sumsub outage' WHERE user_id = ''; Notify user: Din identitet er verifisert Velkommen til Drop! Du kan nå gjøre betalinger. Risk: Manual review is slow, error-prone, not scalable. Only for critical cases. Option 2: Delay Registration, Notify When Ready Use case: Sumsub down, no ETA, non-urgent registrations Steps: Show maintenance message: Identitetsverifisering midlertidig utilgjengelig Vi jobber med å løse problemet. Du vil motta en e-post når du kan fortsette registreringen. Collect user email: // src/app/api/auth/register/route.ts if (sumsubUnavailable) { await db.insert('pending_registrations', { email: userEmail, status: 'waiting_kyc', created_at: new Date(), }); return { success: true, message: 'We will notify you when registration is available', }; } When Sumsub is back, notify users: SELECT email FROM pending_registrations WHERE status = 'waiting_kyc'; Email (Norwegian): Emne: Du kan nå fullføre registreringen i Drop Hei, Identitetsverifisering er tilbake. Klikk her for å fortsette registreringen: [Link] Mvh, Drop ETA: Delayed registration (hours to days) Monitoring & Alerts Metrics to Track KYC success rate: Should be >85% (accounting for user errors) KYC processing time: p50 <5min, p95 <30min, p99 <2h (includes manual review) Rejection reasons: Track document_not_readable, expired, underage, sanctions separately Alert Rules // src/lib/kyc-monitor.ts export async function trackKYCFailure(userId: string, reason: string) { const failureRate = await calculateKYCFailureRate('last_hour'); if (failureRate > 0.3) { // 30% failure rate await sendAlert({ severity: 'high', title: 'KYC failure rate high', message: `${(failureRate * 100).toFixed(1)}% of KYC attempts failing`, reason, }); } } Post-Incident Actions Retry failed KYC verifications: UPDATE users SET kyc_status = 'pending_retry', kyc_retry_at = datetime('now') WHERE kyc_status IN ('failed', 'pending_kyc') AND created_at > datetime('now', '-24 hours'); Document incident: touch ~/ALAI/products/Drop/comms/incidents/$(date +%Y-%m-%d)-sumsub-kyc-failure.md Review rejection reasons: High document_not_readable rate? Improve photo instructions High liveness_check_failed rate? Adjust Sumsub settings Track improvements in next month's KYC metrics Update user onboarding: Add better photo guides Show example of good vs bad ID photos Pre-flight check: "Is your ID expired?" Escalation Time Action 0 min John starts diagnosis 15 min If Sumsub outage confirmed, notify Alem 30 min If urgent user needs KYC, consider manual review (Alem approval) 1 hour Public communication to users 2 hours Contact Sumsub support via phone if no response Contacts Sumsub Support: support@sumsub.com Sumsub Live Chat: https://cockpit.sumsub.com (bottom-right) Sumsub Phone: Check Sumsub Dashboard for support number Internal: Alem (CEO, manual KYC approval authority) Related Documentation docs/architecture/kyc-aml.md — KYC/AML flow diagrams src/app/api/kyc/initiate/route.ts — Sumsub integration code docs/compliance/kyc-requirements.md — Regulatory requirements (age, ID types) Vaultwarden item: "Sumsub API" — Credentials Last Updated: 2026-02-22 Next Review: Before Phase 2 (Banking Integration)