As digital services expand and regulatory frameworks strengthen, identity verification has emerged as an essential component of secure online business operations. Financial regulations increasingly require businesses to verify user identities as part of Know Your Customer (KYC) and anti-money laundering (AML) compliance programs. Beyond regulatory requirements, identity verification protects businesses from fraud, account takeover attacks, and synthetic identity threats that can undermine platform integrity.
Stripe Identity addresses these challenges by providing a unified API that handles document collection, automated verification checks, and reliable result delivery through webhooks. The service supports multiple document types from countries around the world, enabling businesses to implement verification flows tailored to their specific requirements and geographic markets.
This guide covers the complete implementation of Stripe Identity, from creating Verification Sessions and handling the session lifecycle to implementing secure webhook processing with stripe.webhooks.constructEvent. You'll also learn about verification checks and document types, integration patterns with other Stripe services like Payment Intents and Billing, and best practices for production deployments that balance security with user experience. For comprehensive API integration services, our web development services team can help you implement secure verification flows that meet regulatory requirements.
What is Stripe Identity?
Stripe Identity is an identity verification platform that enables businesses to verify the identity of their users through a unified API. Rather than building custom verification systems or integrating with multiple third-party services, Stripe Identity provides a single integration point for document collection, verification, and results processing. This approach significantly reduces development time while ensuring your verification implementation meets industry standards for accuracy and reliability.
The service handles the complexity of identity verification by supporting multiple document types, performing automated verification checks, and delivering results through a reliable webhook system. Stripe's verification engine analyzes submitted documents to confirm authenticity, extract relevant information, and compare live selfies with document photos to verify the person presenting the document is its legitimate owner.
Stripe Identity helps businesses meet KYC and AML requirements that many financial services, marketplaces, and high-risk industries face. By using Stripe's managed verification service, you avoid the operational burden of building document verification expertise in-house while maintaining compliance with applicable regulations. Our web development services include secure API integrations like Stripe Identity to help you implement robust identity verification workflows.
Integrating Stripe Identity alongside other Stripe services creates a cohesive user verification and payment processing experience. The same webhook infrastructure that handles payment events can also process identity verification results, simplifying your backend architecture. If your application already uses Stripe for payments, the authentication mechanisms and API patterns remain consistent, reducing the learning curve and development effort required for identity verification.
This integration extends to Stripe Connect for platform businesses requiring identity verification of connected accounts, and to payment flows where identity verification is a prerequisite for certain transaction types. By implementing Stripe Identity, you gain access to a verification solution that scales with your business and maintains compatibility with new Stripe features as they are released. For comprehensive webhook implementation guidance, see our webhook handling guide that covers best practices for all Stripe webhook events.
Verification Sessions API
The Verification Sessions API forms the foundation of any Stripe Identity integration. Every verification begins with creating a VerificationSession object through the Stripe API, which defines the parameters of the verification attempt including document types to collect and verification checks to perform. The session generates a hosted verification flow that users complete on their devices, after which Stripe processes the documents and returns verification results through webhooks or status retrieval.
Understanding the Verification Sessions API is essential for building effective verification flows that balance security requirements with user experience considerations. The API provides granular control over which documents are accepted and which verification checks are performed.
1import Stripe from 'stripe';2import { NextRequest, NextResponse } from 'next/server';3 4const stripe = new Stripe(process.env.STRIPE_SECRET_KEY!);5 6export async function POST(request: NextRequest) {7 try {8 const { userId, verificationType } = await request.json();9 10 // Create a verification session11 const verificationSession = await stripe.identity.verificationSessions.create({12 type: verificationType || 'document',13 options: {14 document: {15 require_matching_selfie: true,16 require_live_capture: true,17 },18 },19 metadata: {20 user_id: userId,21 platform: 'web',22 },23 });24 25 return NextResponse.json({26 clientSecret: verificationSession.client_secret,27 sessionId: verificationSession.id,28 });29 } catch (error) {30 console.error('Verification session creation failed:', error);31 return NextResponse.json(32 { error: 'Failed to create verification session' },33 { status: 500 }34 );35 }36}A VerificationSession progresses through several states during its lifecycle. Initially, the session is created with status pending, indicating that the session is awaiting user action. During this period, you can update certain session parameters such as the document types accepted or the redirect URL after completion. Once the user completes the verification flow, Stripe processes the documents and updates the status to either verified (successful verification) or not_verified (failed verification).
If the user cancels the verification or the session expires without completion, the status updates to canceled. Terminal states (verified, not_verified, canceled) do not allow further modifications to the session. Understanding this lifecycle is crucial for implementing appropriate user experience flows and error handling that guide users through successful verification.
1export async function GET(request: NextRequest) {2 const sessionId = request.nextUrl.searchParams.get('session_id');3 4 if (!sessionId) {5 return NextResponse.json(6 { error: 'Session ID required' },7 { status: 400 }8 );9 }10 11 try {12 const verificationSession = await stripe.identity.verificationSessions.retrieve(sessionId);13 14 return NextResponse.json({15 id: verificationSession.id,16 status: verificationSession.status,17 verificationOutcome: verificationSession.verification_outcome,18 created: verificationSession.created,19 expiresAt: verificationSession.expires_at,20 });21 } catch (error) {22 console.error('Failed to retrieve verification session:', error);23 return NextResponse.json(24 { error: 'Verification status unavailable' },25 { status: 500 }26 );27 }28}Webhook Implementation
Webhooks provide the most reliable mechanism for receiving verification results, especially for production applications where users may close browser windows before client-side redirects complete. Implementing proper webhook handling ensures you never miss a verification result regardless of how users interact with your application. The primary event types include identity.verification_session.verified when verification succeeds, identity.verification_session.not_verified when verification fails, and identity.verification_session.canceled when the user cancels or the session expires.
For robust production implementations, wire up webhook handlers before launching to users. Webhook processing is critical infrastructure that prevents race conditions and ensures consistent user state updates across your platform.
1import Stripe from 'stripe';2import { NextRequest, NextResponse } from 'next/server';3 4const stripe = new Stripe(process.env.STRIPE_SECRET_KEY!);5const webhookSecret = process.env.STRIPE_WEBHOOK_SECRET!;6 7export async function POST(request: NextRequest) {8 const body = await request.text();9 const signature = request.headers.get('stripe-signature');10 11 if (!signature) {12 return NextResponse.json(13 { error: 'Missing webhook signature' },14 { status: 400 }15 );16 }17 18 let event: Stripe.Event;19 20 try {21 // Verify webhook signature using constructEvent22 event = stripe.webhooks.constructEvent(body, signature, webhookSecret);23 } catch (err) {24 console.error('Webhook signature verification failed:', err);25 return NextResponse.json(26 { error: 'Invalid webhook signature' },27 { status: 400 }28 );29 }30 31 // Handle verification session events32 switch (event.type) {33 case 'identity.verification_session.verified':34 const verifiedSession = event.data.object as Stripe.Identity.VerificationSession;35 await handleVerifiedUser(verifiedSession);36 break;37 38 case 'identity.verification_session.not_verified':39 const failedSession = event.data.object as Stripe.Identity.VerificationSession;40 await handleVerificationFailure(failedSession);41 break;42 43 case 'identity.verification_session.canceled':44 const canceledSession = event.data.object as Stripe.Identity.VerificationSession;45 await handleVerificationCanceled(canceledSession);46 break;47 48 default:49 console.log(`Unhandled event type: ${event.type}`);50 }51 52 return NextResponse.json({ received: true });53}54 55async function handleVerifiedUser(session: Stripe.Identity.VerificationSession) {56 const userId = session.metadata?.user_id;57 if (userId) {58 console.log(`User ${userId} identity verified successfully`);59 }60}61 62async function handleVerificationFailure(session: Stripe.Identity.VerificationSession) {63 const userId = session.metadata?.user_id;64 const failureReason = session.last_verification_error?.reason;65 console.log(`Verification failed for user ${userId}: ${failureReason}`);66}67 68async function handleVerificationCanceled(session: Stripe.Identity.VerificationSession) {69 const userId = session.metadata?.user_id;70 console.log(`Verification canceled for user ${userId}`);71}The stripe.webhooks.constructEvent signature verification step is non-negotiable for security. Without it, attackers could send fabricated events to your endpoint, potentially granting unauthorized access to users who haven't actually completed verification. Always use constructEvent with your actual webhook secret—never skip this validation step regardless of how confident you are in your endpoint's isolation.
Beyond signature verification, implement additional safeguards: use HTTPS for all webhook URLs to prevent interception of verification results, implement idempotency by tracking processed event IDs since Stripe may retry delivery of events that don't receive successful responses, and implement proper error handling that returns appropriate HTTP status codes. Stripe interprets 2xx responses as successful delivery; any other response triggers retry attempts. Implementing secure API endpoints with proper webhook validation is a core component of our web development services that protect your platform from unauthorized access.
Verification Checks and Document Types
Stripe Identity supports government-issued identification documents from numerous countries and territories. Common document types include passports, driver's licenses, and national identity cards. Each document type has specific requirements for image quality and capture methods that affect verification success rates. Stripe maintains an extensive database of valid document specifications to handle country-specific formats and security features.
Passport verification typically offers the highest success rates because passports have standardized security features that are well-documented and consistently applied across issuing countries. Driver's license and ID card verification supports the diverse formats used by different jurisdictions while maintaining rigorous authenticity checks.
1const verificationSession = await stripe.identity.verificationSessions.create({2 type: 'document',3 options: {4 document: {5 require_matching_selfie: true,6 require_live_capture: true,7 allowed_types: ['passport', 'drivers_license', 'national_id_card'],8 },9 },10 metadata: {11 user_id: user.id,12 account_id: account.id,13 onboarding_step: 'identity_verification',14 },15});Integration with Stripe Services
Stripe Identity integrates naturally with other Stripe products, creating a unified platform for user onboarding and payment acceptance. For platforms requiring both identity verification and payment acceptance, the integration between Stripe Identity and Stripe Connect or Payment Intents creates streamlined onboarding flows. Users verify their identity once and can then proceed to payment setup without additional verification steps, reducing friction in the user journey.
The shared webhook infrastructure means you handle identity verification events using the same patterns you use for payment events, reducing code duplication and ensuring reliable event handling across your platform. Both Verification Sessions and webhooks support metadata attachments that help you track verification results within your existing data models, keeping verification records synchronized with user and account records.
Best Practices for Production
Verification failures can occur for various reasons—poor image quality, unsupported document types, or temporary service interruptions. Implement robust error handling that provides clear guidance to users and enables retry attempts when appropriate. Distinguish between recoverable errors (poor image quality) and non-recoverable errors (unsupported document type). Recoverable errors should prompt users to retry with corrected submissions, while non-recoverable errors require different handling such as offering alternative document types or directing users to customer support.
The verification outcome provides detailed information about failure reasons, including specific error codes that help you communicate appropriate next steps to users who need to retry verification. Implementing comprehensive error handling improves verification success rates and reduces user frustration.
The verification flow represents a significant moment in user onboarding—it's often the first time you're asking users to share sensitive personal documents. Design the experience to build trust through clear communication about how documents will be used and protected. Provide context about why verification is required and what happens next, especially for regulated industries where identity verification is a compliance requirement.
Set appropriate expectations about verification timing, typically immediate for simple document uploads but potentially longer for cases requiring manual review. Clear success and failure messaging helps users understand their verification status and any required next steps. Consider guiding users through the verification process at the appropriate point in their journey rather than front-loading it, which can increase conversion rates.
Identity verification generates sensitive personal data that requires careful handling throughout your application. Understand your regulatory obligations regarding data retention, access controls, and user consent. Stripe provides tools for managing document data, but you're responsible for implementing appropriate access controls within your application and ensuring user consent is obtained and documented.
Consider implementing time-limited access to verification features, audit logging for all verification-related actions, and clear data retention policies that align with regulatory requirements. Users should have visibility into what verification data you hold and the ability to request deletion where legally required. Document your data handling practices in privacy policies and terms of service to maintain transparency with your users. Our web development services include secure data handling practices and compliance consulting to help you implement identity verification that meets regulatory standards.
Troubleshooting Common Issues
Webhook signature failures typically result from using the wrong endpoint secret or incorrect body handling. Ensure your webhook handler receives the raw request body exactly as sent by Stripe, without any intermediate parsing that could alter the payload. Many framework auto-parsers can consume the body before signature verification—use raw body access patterns to avoid this issue.
Session creation failures often stem from incorrect API permissions. Verify that your Stripe account has the Identity product enabled and that your API keys have appropriate scopes for verification operations. Verification delays may occur for documents requiring manual review. Implement appropriate user messaging that sets expectations for verification timing, and use webhook events rather than polling to detect completion reliably.
Frequently Asked Questions
Let our team help you integrate Stripe Identity into your application with best practices for security and user experience.