Skip to main content

Smart Enroll (KYC) webhooks

Overview​

Smart Enroll (onboarding) uses the webhook attached to the ProjectFlow. When the flow has an active webhook, Verifik enqueues delivery for lifecycle events on app registration, email/phone OTP, documents, biometrics, and related modules.

For the full event catalog see Supported Events. This page focuses on typical Smart Enroll order, payload shape, and manual verification vs. completed behavior.

Also available: VersiΓ³n en espaΓ±ol.

Payload shape

Every delivery is JSON with a top-level type and object:

{
"type": "onboarding_app_registration_completed",
"object": { }
}
  • type = ${projectFlow.type}_${suffix} β€” for Smart Enroll the prefix is always onboarding.
  • object = primary entity snapshot (appRegistration, emailValidation, documentValidation, etc.). OTP values are stripped.
  • app_registration_* events from sync also include the webhook reference when the flow is linked to one.

Your integration should tolerate new optional fields.

Event name rules
PatternSuffix shapeExample
Sync while status stays ONGOINGapp_registration_sync_<step> (snake_case)app_registration_sync_sign_up_form
Sync when status changes (end, skipKYC)app_registration_<status>app_registration_completed
Admin override (staff auth)app_registration_<new_status>app_registration_completed
Email / Phone OTPemail_validation_<action> or phone_validation_<action>email_validation_validated

All suffixes become full type with the onboarding_ prefix, e.g. onboarding_email_validation_created. Match on the full type in your code.


Smart Enroll timeline​

Order varies by project (optional steps, skip KYC, gateways). The diagram below shows a common happy path and where major events fire.

flowchart TD
start["User opens link"] -->|"app_registration_created"| form["Sign-up form"]
form -->|"app_registration_sync_sign_up_form"| otp["Email + Phone OTP"]
otp -->|"email_validation_created\nphone_validation_created"| otpDone["OTP validated"]
otpDone -->|"email_validation_validated\nphone_validation_validated"| instructions["Instructions"]
instructions -->|"app_registration_sync_instructions"| doc["Document scan"]
doc -->|"document_validation_created"| source["Source lookup"]
source -->|"document_validation_source_lookup"| liveness["Liveness / biometric"]
liveness -->|"biometric_validation_validated"| face["Face comparison"]
face -->|"face_verification_compare"| syncEnd["sync: end"]
syncEnd -->|"app_registration_completed"| done["COMPLETED"]
syncEnd -->|"app_registration_needs_manual_verification"| manual["Manual review"]
manual -->|"resolve blockers"| syncEnd
skipPath["Skip KYC path"] -->|"app_registration_completed_without_kyc"| done

Lifecycle events in order​

The table below lists events in the order they typically fire during a Smart Enroll flow.

#SuffixWhen it firesNotes
1app_registration_createdRegistration record is created (insert)Includes projectFlow context
2app_registration_sync_sign_up_formUser submits sign-up form via syncStatus stays ONGOING
3email_validation_createdFirst OTP email sent
3aemail_validation_resendResend while previous OTP still valid
3bemail_validation_validatedCorrect OTP submitted
3cemail_validation_otp_incorectWrong OTPSpelling matches API
4phone_validation_createdFirst OTP message (SMS / WhatsApp)
4aphone_validation_resendResend for same pending validation
4bphone_validation_validatedCorrect OTP
4cphone_validation_otp_incorectWrong OTP
5app_registration_sync_instructionsInstructions step via syncStatus stays ONGOING
6document_validation_createdDocument validation startsMay include appRegistration, email, phone
7document_validation_source_lookupGovernment / data source lookup finishes
7adocument_validation_data_source_errorSource returned invalid data or name mismatchMay include notSupportedData
8biometric_validation_validatedLiveness passes
8abiometric_validation_liveness_failedLiveness fails
8bbiometrics_liveness_score_not_acceptableScore below project threshold
9face_verification_compareFace compare (selfie vs document)Includes compareResult
10document_validation_manual_verification_requiredDocument moved to manual reviewBlocks COMPLETED
11app_registration_completedsync end β€” all requirements metFinal success event
11app_registration_needs_manual_verificationsync end β€” blockers remainSee warning below
11app_registration_completed_without_kycskipKYC path, flow allows skip
11app_registration_failedsync end β€” completeness = FAILED

Manual verification vs. COMPLETED​

Key behavior
  • NEEDS_MANUAL_VERIFICATION means the registration is blocked from completing until ops resolve outstanding checks (e.g. document manual verification).
  • Do not assume every sync end with status: "COMPLETED" in the request yields app_registration_completed. The server sets status from completeness and flow rules and may emit app_registration_needs_manual_verification instead.
  • After blockers are cleared, a subsequent sync or adminOverride can move the registration to COMPLETED and emit app_registration_completed.
  • Real delivery order over the network can differ by milliseconds β€” design for idempotency.