Handle verification outcomes
Listen for verification results so your integration can automatically trigger reactions.
You wrote code to display a modal to collect identity documents. Now, when your user submits a document, you can listen to verification results to trigger reactions in your application.
In this guide, you’ll learn how to:
- Receive an event notification when a verification finishes processing.
- Handle successful and failed verification checks.
- Turn your event handler on in production.
Verification checks are asynchronous, which means that verification results aren’t immediately available. When the processing completes, the VerificationSession status updates and the verified information is available. Stripe generates events every time a session changes status. In this guide, we’ll implement webhooks to notify your app when verification results become available.
Set up Stripe Server-side
Install our official libraries for access to the Stripe API from your application:
Command Line
Select a language
Ruby
Python
PHP
Java
Node.js
Go
.NET
No results
# Available as a gem
sudo gem install stripe
Gemfile
Select a language
Ruby
Python
PHP
Java
Node.js
Go
.NET
No results
# If you use bundler, you can add this line to your Gemfile
gem 'stripe'
Create a webhook and handle VerificationSession events Server-side
A webhook is an endpoint on your server that receives requests from Stripe, notifying you about events that happen on your account. In this step, we’ll build an endpoint to receive events on VerificationSession status changes.
Webhook endpoints must be publicly accessible so Stripe can send unauthenticated requests. You’ll need to verify that Stripe sent the event by using the Stripe library and request header:
server.js
Select a language
Node.js
Ruby
Python
PHP
Java
Go
.NET
No results
// Don't put any keys in code. See https://docs.stripe.com/keys-best-practices.
// Find your keys at https://dashboard.stripe.com/apikeys.
const stripe = require('stripe')('sk_test_BQokikJOvBiI2HlWgH4olfQ2');
// You can find your endpoint's secret in your webhook settings
const endpointSecret = 'whsec_...';
// This example uses Express to receive webhooks
const express = require('express');
// Use body-parser to retrieve the raw body as a buffer
const bodyParser = require('body-parser');
const app = express();
// Use JSON parser for all non-webhook routes
app.use((req, res, next) => {
if (req.originalUrl === '/webhook') {
next();
} else {
bodyParser.json()(req, res, next);
}
});
app.post('/webhook', bodyParser.raw({type: 'application/json'}), (req, res) => {
let event;
// Verify the event came from Stripe
try {
const sig = req.headers['stripe-signature'];
event = stripe.webhooks.constructEvent(req.body, sig, endpointSecret);
} catch (err) {
// On error, log and return the error message
console.log(`❌ Error message: ${err.message}`);
return res.status(400).send(`Webhook Error: ${err.message}`);
}
// Successfully constructed event
res.json({received: true});
});
app.listen(4242, () => {
console.log('Running on port 4242');
});
Now that you have the basic structure and security in place to listen to notifications from Stripe, update your webhook endpoint to handle verification session events.
All session events include the VerificationSession object, which contains details about the verification checks performed. See Accessing verification results to learn how to retrieve verified information not included in session events.
Stripe sends the following events when the session status changes:
| Event name | Description | Next steps |
|---|---|---|
| identity.verification_session.verified | Processing of all the verification checks have completed, and they’re all successfully verified. | Trigger relevant actions in your application. |
| identity.verification_session.requires_input | Processing of all the verification checks have completed, and at least one of the checks failed. | Trigger relevant actions in your application and potentially allow your user to retry the verification. |
Your webhook code needs to handle the identity.verification_session.verified and identity.verification_session.requires_input events. You can subscribe to other session events to trigger additional reactions in your app.
Handle VerificationSession verified status change
The identity.verification_session.verified event is sent when verification checks have completed and are all successfully verified.
Add code to your event handler to handle all verification checks passing:
server.js
Select a language
Node.js
Ruby
Python
PHP
Java
Go
.NET
No results
// Don't put any keys in code. See https://docs.stripe.com/keys-best-practices.
// Find your keys at https://dashboard.stripe.com/apikeys.
const stripe = require('stripe')('sk_test_BQokikJOvBiI2HlWgH4olfQ2');
// You can find your endpoint's secret in your webhook settings
const endpointSecret = 'whsec_...';
// This example uses Express to receive webhooks
const express = require('express');
// Use body-parser to retrieve the raw body as a buffer
const bodyParser = require('body-parser');
const app = express();
// Use JSON parser for all non-webhook routes
app.use((req, res, next) => {
if (req.originalUrl === '/webhook') {
next();
} else {
bodyParser.json()(req, res, next);
}
});
app.post('/webhook', bodyParser.raw({type: 'application/json'}), (req, res) => {
let event;
// Verify the event came from Stripe
try {
const sig = req.headers['stripe-signature'];
event = stripe.webhooks.constructEvent(req.body, sig, endpointSecret);
} catch (err) {
// On error, log and return the error message
console.log(`❌ Error message: ${err.message}`);
return res.status(400).send(`Webhook Error: ${err.message}`);
}
// Successfully constructed event
switch (event.type) {
case 'identity.verification_session.verified': {
// All the verification checks passed
const verificationSession = event.data.object;
break;
}
}
res.json({received: true});
});
app.listen(4242, () => {
console.log('Running on port 4242');
});
When handling this event, you might also consider:
- Saving the verification status in your own database
- Sending an email to your user letting them know they’ve been verified
- Expanding the VerificationSession verified outputs and comparing them against an expected value.
Handle VerificationSession requires_input status changes
The identity.verification_session.requires_input event is sent when at least one of the checks failed. You can inspect the last_error hash on the verification session to handle specific failure reasons:
- The last_error.code field can be used to programmatically handle verification failures.
- The last_error.reason field contains a descriptive message explaining the failure reason and can be shown to your user.
Event error codes
| Error code | Description |
|---|---|
consent_declined | The user declined to be verified by Stripe. Check with your legal counsel to see if you have an obligation to offer an alternative, non-biometric means to verify, such as through a manual review. |
under_supported_age | Stripe doesn’t verify users under the age of majority. |
country_not_supported | Stripe doesn’t verify users from the provided country. |
Add code to your event handler to handle verification check failure:
server.js
Select a language
Node.js
Ruby
Python
PHP
Java
Go
.NET
No results
// Don't put any keys in code. See https://docs.stripe.com/keys-best-practices.
// Find your keys at https://dashboard.stripe.com/apikeys.
const stripe = require('stripe')('sk_test_BQokikJOvBiI2HlWgH4olfQ2');
// You can find your endpoint's secret in your webhook settings
const endpointSecret = 'whsec_...';
// This example uses Express to receive webhooks
const express = require('express');
// Use body-parser to retrieve the raw body as a buffer
const bodyParser = require('body-parser');
const app = express();
// Use JSON parser for all non-webhook routes
app.use((req, res, next) => {
if (req.originalUrl === '/webhook') {
next();
} else {
bodyParser.json()(req, res, next);
}
});
app.post('/webhook', bodyParser.raw({type: 'application/json'}), (req, res) => {
let event;
// Verify the event came from Stripe
try {
const sig = req.headers['stripe-signature'];
event = stripe.webhooks.constructEvent(req.body, sig, endpointSecret);
} catch (err) {
// On error, log and return the error message
console.log(`❌ Error message: ${err.message}`);
return res.status(400).send(`Webhook Error: ${err.message}`);
}
// Successfully constructed event
switch (event.type) {
case 'identity.verification_session.verified': {
// All the verification checks passed
const verificationSession = event.data.object;
break;
}
case 'identity.verification_session.requires_input': {
// At least one of the verification checks failed
const verificationSession = event.data.object;
console.log('Verification check failed: ' + verificationSession.last_error.reason);
// Handle specific failure reasons
switch (verificationSession.last_error.code) {
case 'document_unverified_other': {
// The document was invalid
break;
}
case 'document_expired': {
// The document was expired
break;
}
case 'document_type_not_supported': {
// document type not supported
break;
}
default: {
// ...
}
}
}
}
res.json({received: true});
});
app.listen(4242, () => {
console.log('Running on port 4242');
});
Depending on your use case, you might want to allow your users to retry the verification if it fails. We recommend that you limit the amount of submission attempts.
When handling this event, you might also consider:
- Manually reviewing the collected information
- Sending an email to your user letting them know that their verification failed
- Providing your user an alternative verification method
Go live in production
After you’ve deployed your event handler endpoint to production, set up the endpoint so Stripe knows where to send live mode events. It’s also helpful to go through the development checklist to ensure a smooth transition when taking your integration live.
Webhook endpoints are configured in Workbench or programmatically using the API.
Add an endpoint in the Dashboard
- In Workbench’s Webhooks tab , click Add destination to add a new webhook endpoint.
- Enter the Stripe API version.
- Select which events to listen to. See the full list of Verification Session events .
- Click Continue and select Webhook endpoint from the list of available destination types.
- Click Continue and enter the URL of your endpoint, optional name, and optional description.
- Click Create destination .
Add endpoint with the API
You can also programmatically create webhook endpoints. As with the form in Workbench, you can enter any URL as the destination for events and which event types to subscribe to.
Command Line
