Frontend:
Backend:
Identity verification
The modal integration allows you to collect documents for identity verification in your existing flow. You can customize the interface to match your branding and support users on a variety of platforms and in multiple programming languages, while limiting the amount of private information you handle on your site.
For an integration solution that requires minimal coding, see the redirect integration.
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8" /><title>Stripe Identity Sample</title><meta name="description" content="A demo of Stripe Identity" /><link rel="stylesheet" href="css/normalize.css" /><link rel="stylesheet" href="css/global.css" /><script src="https://js.stripe.com/v3/"></script></head><body><div class="sr-root"><div class="sr-main"><section class="container"><div><h1>Verify your identity to book</h1><h4>Get ready to take a photo of your ID and a selfie</h4><button id="verify-button">Verify me</button></div></section></div></div><script type="text/javascript">document.addEventListener('DOMContentLoaded', async () => {// Set your publishable key: remember to change this to your live publishable key in production// Find your keys here: https://dashboard.stripe.com/apikeysconst {publishableKey} = await fetch('/config').then(r=>r.json());const stripe = Stripe(publishableKey);var verifyButton = document.getElementById('verify-button');verifyButton.addEventListener('click', async () => {// Get the VerificationSession client secret using the server-side// endpoint you created in step 3.try {// Create the VerificationSession on the server.const {client_secret} = await fetch('/create-verification-session', {method: 'POST',}).then(r => r.json())// Open the modal on the client.const {error} = await stripe.verifyIdentity(client_secret);if(!error) {window.location.href = '/submitted.html';} else {alert(error.message);}} catch(e) {alert(e.message);}})})</script></body></html>
/* Variables */:root {--gray-offset: rgba(0, 0, 0, 0.03);--gray-border: rgba(0, 0, 0, 0.15);--gray-light: rgba(0, 0, 0, 0.4);--gray-mid: rgba(0, 0, 0, 0.7);--gray-dark: rgba(0, 0, 0, 0.9);--body-color: var(--gray-mid);--headline-color: var(--gray-dark);--accent-color: #0066f0;--body-font-family: -apple-system, BlinkMacSystemFont, sans-serif;--radius: 6px;--form-width: 343px;}/* Base */* {box-sizing: border-box;}body {font-family: var(--body-font-family);font-size: 16px;color: var(--body-color);-webkit-font-smoothing: antialiased;}h1,h2,h3,h4,h5,h6 {color: var(--body-color);margin-top: 2px;margin-bottom: 4px;}h1 {font-size: 27px;color: var(--headline-color);}h4 {font-weight: 500;font-size: 14px;color: var(--gray-light);}/* Layout */.sr-root {display: flex;flex-direction: row;width: 100%;max-width: 980px;padding: 48px;align-content: center;justify-content: center;height: auto;min-height: 100vh;margin: 0 auto;}.sr-header {margin-bottom: 32px;}.sr-payment-summary {margin-bottom: 20px;}.sr-main,.sr-content {display: flex;flex-direction: column;justify-content: center;height: 100%;align-self: center;}.sr-main {width: var(--form-width);}.sr-content {padding-left: 48px;}.sr-header__logo {background-image: var(--logo-image);height: 24px;background-size: contain;background-repeat: no-repeat;width: 100%;}.sr-legal-text {color: var(--gray-light);text-align: center;font-size: 13px;line-height: 17px;margin-top: 12px;}.sr-field-error {color: var(--accent-color);text-align: left;font-size: 13px;line-height: 17px;margin-top: 12px;}/* Form */.sr-form-row {margin: 16px 0;}label {font-size: 13px;font-weight: 500;margin-bottom: 8px;display: inline-block;}/* Inputs */.sr-input,.sr-select,input[type="text"] {border: 1px solid var(--gray-border);border-radius: var(--radius);padding: 5px 12px;height: 44px;width: 100%;transition: box-shadow 0.2s ease;background: white;-moz-appearance: none;-webkit-appearance: none;appearance: none;color: #32325d;}.sr-input:focus,input[type="text"]:focus,button:focus,.focused {box-shadow: 0 0 0 1px rgba(50, 151, 211, 0.3), 0 1px 1px 0 rgba(0, 0, 0, 0.07),0 0 0 4px rgba(50, 151, 211, 0.3);outline: none;z-index: 9;}.sr-input::placeholder,input[type="text"]::placeholder {color: var(--gray-light);}/* Checkbox */.sr-checkbox-label {position: relative;cursor: pointer;}.sr-checkbox-label input {opacity: 0;margin-right: 6px;}.sr-checkbox-label .sr-checkbox-check {position: absolute;left: 0;height: 16px;width: 16px;background-color: white;border: 1px solid var(--gray-border);border-radius: 4px;transition: all 0.2s ease;}.sr-checkbox-label input:focus ~ .sr-checkbox-check {box-shadow: 0 0 0 1px rgba(50, 151, 211, 0.3), 0 1px 1px 0 rgba(0, 0, 0, 0.07),0 0 0 4px rgba(50, 151, 211, 0.3);outline: none;}.sr-checkbox-label input:checked ~ .sr-checkbox-check {background-color: var(--accent-color);background-repeat: no-repeat;background-size: 16px;background-position: -1px -1px;}/* Select */.sr-select {display: block;height: 44px;margin: 0;background-repeat: no-repeat, repeat;background-position: right 12px top 50%, 0 0;background-size: 0.65em auto, 100%;}.sr-select::-ms-expand {display: none;}.sr-select:hover {cursor: pointer;}.sr-select:focus {box-shadow: 0 0 0 1px rgba(50, 151, 211, 0.3), 0 1px 1px 0 rgba(0, 0, 0, 0.07),0 0 0 4px rgba(50, 151, 211, 0.3);outline: none;}.sr-select option {font-weight: 400;}.sr-select:invalid {color: var(--gray-light);}/* Combo inputs */.sr-combo-inputs {display: flex;flex-direction: column;}.sr-combo-inputs input,.sr-combo-inputs .sr-select {border-radius: 0;border-bottom: 0;}.sr-combo-inputs > input:first-child,.sr-combo-inputs > .sr-select:first-child {border-radius: var(--radius) var(--radius) 0 0;}.sr-combo-inputs > input:last-child,.sr-combo-inputs > .sr-select:last-child {border-radius: 0 0 var(--radius) var(--radius);border-bottom: 1px solid var(--gray-border);}.sr-combo-inputs > .sr-combo-inputs-row:last-child input:first-child {border-radius: 0 0 0 var(--radius);border-bottom: 1px solid var(--gray-border);}.sr-combo-inputs > .sr-combo-inputs-row:last-child input:last-child {border-radius: 0 0 var(--radius) 0;border-bottom: 1px solid var(--gray-border);}.sr-combo-inputs > .sr-combo-inputs-row:first-child input:first-child {border-radius: var(--radius) 0 0 0;}.sr-combo-inputs > .sr-combo-inputs-row:first-child input:last-child {border-radius: 0 var(--radius) 0 0;}.sr-combo-inputs > .sr-combo-inputs-row:first-child input:only-child {border-radius: var(--radius) var(--radius) 0 0;}.sr-combo-inputs-row {width: 100%;display: flex;}.sr-combo-inputs-row > input {width: 100%;border-radius: 0;}.sr-combo-inputs-row > input:first-child:not(:only-child) {border-right: 0;}.sr-combo-inputs-row:not(:first-of-type) .sr-input {border-radius: 0 0 var(--radius) var(--radius);}.sr-result {height: 44px;-webkit-transition: height 1s ease;-moz-transition: height 1s ease;-o-transition: height 1s ease;transition: height 1s ease;color: var(--font-color);overflow: auto;}.sr-result code {overflow: scroll;}.sr-result.expand {height: 350px;}/* Buttons and links */button {background: var(--accent-color);border-radius: var(--radius);color: white;border: 0;padding: 12px 16px;margin-top: 16px;font-weight: 600;cursor: pointer;transition: all 0.2s ease;display: block;}button:hover {filter: contrast(115%);}button:active {transform: translateY(0px) scale(0.98);filter: brightness(0.9);}button:disabled {opacity: 0.5;cursor: not-allowed;}.sr-payment-form button,.fullwidth {width: 100%;}a {color: var(--accent-color);text-decoration: none;transition: all 0.2s ease;}a:hover {filter: brightness(0.8);}a:active {filter: brightness(0.5);}/* Code block */.sr-callout {background: var(--gray-offset);padding: 12px;border-radius: var(--radius);max-height: 200px;overflow: auto;}code,pre {font-family: "SF Mono", "IBM Plex Mono", "Menlo", monospace;font-size: 12px;}/* Stripe Element placeholder */.sr-card-element {padding-top: 12px;}/* Responsiveness */@media (max-width: 720px) {.sr-root {flex-direction: column;justify-content: flex-start;padding: 48px 20px;min-width: 320px;}.sr-header__logo {background-position: center;}.sr-payment-summary {text-align: center;}.sr-content {display: none;}.sr-main {width: 100%;}}/* Pasha styles – Brand-overrides, can split these out */:root {--accent-color: #ed5f74;--headline-color: var(--accent-color);}.pasha-image-stack {display: grid;grid-gap: 12px;grid-template-columns: auto auto;}.pasha-image-stack img {border-radius: var(--radius);background-color: var(--gray-border);box-shadow: 0 7px 14px 0 rgba(50, 50, 93, 0.1),0 3px 6px 0 rgba(0, 0, 0, 0.07);transition: all 0.8s ease;opacity: 0;}.pasha-image-stack img:nth-child(1) {transform: translate(12px, -12px);opacity: 1;}.pasha-image-stack img:nth-child(2) {transform: translate(-24px, 16px);opacity: 1;}.pasha-image-stack img:nth-child(3) {transform: translate(68px, -100px);opacity: 1;}/* todo: spinner/processing state, errors, animations */.spinner,.spinner:before,.spinner:after {border-radius: 50%;}.spinner {color: #ffffff;font-size: 22px;text-indent: -99999px;margin: 0px auto;position: relative;width: 20px;height: 20px;box-shadow: inset 0 0 0 2px;-webkit-transform: translateZ(0);-ms-transform: translateZ(0);transform: translateZ(0);}.spinner:before,.spinner:after {position: absolute;content: "";}.spinner:before {width: 10.4px;height: 20.4px;background: var(--accent-color);border-radius: 20.4px 0 0 20.4px;top: -0.2px;left: -0.2px;-webkit-transform-origin: 10.4px 10.2px;transform-origin: 10.4px 10.2px;-webkit-animation: loading 2s infinite ease 1.5s;animation: loading 2s infinite ease 1.5s;}.spinner:after {width: 10.4px;height: 10.2px;background: var(--accent-color);border-radius: 0 10.2px 10.2px 0;top: -0.1px;left: 10.2px;-webkit-transform-origin: 0px 10.2px;transform-origin: 0px 10.2px;-webkit-animation: loading 2s infinite ease;animation: loading 2s infinite ease;}@-webkit-keyframes loading {0% {-webkit-transform: rotate(0deg);transform: rotate(0deg);}100% {-webkit-transform: rotate(360deg);transform: rotate(360deg);}}@keyframes loading {0% {-webkit-transform: rotate(0deg);transform: rotate(0deg);}100% {-webkit-transform: rotate(360deg);transform: rotate(360deg);}}/* Animated form */.sr-root {animation: 0.4s form-in;animation-fill-mode: both;animation-timing-function: ease;}.sr-payment-form .sr-form-row {animation: 0.4s field-in;animation-fill-mode: both;animation-timing-function: ease;transform-origin: 50% 0%;}/* need saas for loop :D */.sr-payment-form .sr-form-row:nth-child(1) {animation-delay: 0;}.sr-payment-form .sr-form-row:nth-child(2) {animation-delay: 60ms;}.sr-payment-form .sr-form-row:nth-child(3) {animation-delay: 120ms;}.sr-payment-form .sr-form-row:nth-child(4) {animation-delay: 180ms;}.sr-payment-form .sr-form-row:nth-child(5) {animation-delay: 240ms;}.sr-payment-form .sr-form-row:nth-child(6) {animation-delay: 300ms;}.hidden {display: none;}@keyframes field-in {0% {opacity: 0;transform: translateY(8px) scale(0.95);}100% {opacity: 1;transform: translateY(0px) scale(1);}}@keyframes form-in {0% {opacity: 0;transform: scale(0.98);}100% {opacity: 1;transform: scale(1);}}
/*! normalize.css v8.0.1 | MIT License | github.com/necolas/normalize.css *//* Document========================================================================== *//*** 1. Correct the line height in all browsers.* 2. Prevent adjustments of font size after orientation changes in iOS.*/html {line-height: 1.15; /* 1 */-webkit-text-size-adjust: 100%; /* 2 */}/* Sections========================================================================== *//*** Remove the margin in all browsers.*/body {margin: 0;}/*** Render the `main` element consistently in IE.*/main {display: block;}/*** Correct the font size and margin on `h1` elements within `section` and* `article` contexts in Chrome, Firefox, and Safari.*/h1 {font-size: 2em;margin: 0.67em 0;}/* Grouping content========================================================================== *//*** 1. Add the correct box sizing in Firefox.* 2. Show the overflow in Edge and IE.*/hr {box-sizing: content-box; /* 1 */height: 0; /* 1 */overflow: visible; /* 2 */}/*** 1. Correct the inheritance and scaling of font size in all browsers.* 2. Correct the odd `em` font sizing in all browsers.*/pre {font-family: monospace, monospace; /* 1 */font-size: 1em; /* 2 */}/* Text-level semantics========================================================================== *//*** Remove the gray background on active links in IE 10.*/a {background-color: transparent;}/*** 1. Remove the bottom border in Chrome 57-* 2. Add the correct text decoration in Chrome, Edge, IE, Opera, and Safari.*/abbr[title] {border-bottom: none; /* 1 */text-decoration: underline; /* 2 */text-decoration: underline dotted; /* 2 */}/*** Add the correct font weight in Chrome, Edge, and Safari.*/b,strong {font-weight: bolder;}/*** 1. Correct the inheritance and scaling of font size in all browsers.* 2. Correct the odd `em` font sizing in all browsers.*/code,kbd,samp {font-family: monospace, monospace; /* 1 */font-size: 1em; /* 2 */}/*** Add the correct font size in all browsers.*/small {font-size: 80%;}/*** Prevent `sub` and `sup` elements from affecting the line height in* all browsers.*/sub,sup {font-size: 75%;line-height: 0;position: relative;vertical-align: baseline;}sub {bottom: -0.25em;}sup {top: -0.5em;}/* Embedded content========================================================================== *//*** Remove the border on images inside links in IE 10.*/img {border-style: none;}/* Forms========================================================================== *//*** 1. Change the font styles in all browsers.* 2. Remove the margin in Firefox and Safari.*/button,input,optgroup,select,textarea {font-family: inherit; /* 1 */font-size: 100%; /* 1 */line-height: 1.15; /* 1 */margin: 0; /* 2 */}/*** Show the overflow in IE.* 1. Show the overflow in Edge.*/button,input { /* 1 */overflow: visible;}/*** Remove the inheritance of text transform in Edge, Firefox, and IE.* 1. Remove the inheritance of text transform in Firefox.*/button,select { /* 1 */text-transform: none;}/*** Correct the inability to style clickable types in iOS and Safari.*/button,[type="button"],[type="reset"],[type="submit"] {-webkit-appearance: button;}/*** Remove the inner border and padding in Firefox.*/button::-moz-focus-inner,[type="button"]::-moz-focus-inner,[type="reset"]::-moz-focus-inner,[type="submit"]::-moz-focus-inner {border-style: none;padding: 0;}/*** Restore the focus styles unset by the previous rule.*/button:-moz-focusring,[type="button"]:-moz-focusring,[type="reset"]:-moz-focusring,[type="submit"]:-moz-focusring {outline: 1px dotted ButtonText;}/*** Correct the padding in Firefox.*/fieldset {padding: 0.35em 0.75em 0.625em;}/*** 1. Correct the text wrapping in Edge and IE.* 2. Correct the color inheritance from `fieldset` elements in IE.* 3. Remove the padding so developers are not caught out when they zero out* `fieldset` elements in all browsers.*/legend {box-sizing: border-box; /* 1 */color: inherit; /* 2 */display: table; /* 1 */max-width: 100%; /* 1 */padding: 0; /* 3 */white-space: normal; /* 1 */}/*** Add the correct vertical alignment in Chrome, Firefox, and Opera.*/progress {vertical-align: baseline;}/*** Remove the default vertical scrollbar in IE 10+.*/textarea {overflow: auto;}/*** 1. Add the correct box sizing in IE 10.* 2. Remove the padding in IE 10.*/[type="checkbox"],[type="radio"] {box-sizing: border-box; /* 1 */padding: 0; /* 2 */}/*** Correct the cursor style of increment and decrement buttons in Chrome.*/[type="number"]::-webkit-inner-spin-button,[type="number"]::-webkit-outer-spin-button {height: auto;}/*** 1. Correct the odd appearance in Chrome and Safari.* 2. Correct the outline style in Safari.*/[type="search"] {-webkit-appearance: textfield; /* 1 */outline-offset: -2px; /* 2 */}/*** Remove the inner padding in Chrome and Safari on macOS.*/[type="search"]::-webkit-search-decoration {-webkit-appearance: none;}/*** 1. Correct the inability to style clickable types in iOS and Safari.* 2. Change font properties to `inherit` in Safari.*/::-webkit-file-upload-button {-webkit-appearance: button; /* 1 */font: inherit; /* 2 */}/* Interactive========================================================================== *//** Add the correct display in Edge, IE 10+, and Firefox.*/details {display: block;}/** Add the correct display in all browsers.*/summary {display: list-item;}/* Misc========================================================================== *//*** Add the correct display in IE 10+.*/template {display: none;}/*** Add the correct display in IE 10.*/[hidden] {display: none;}
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8" /><title>Identity verification submitted</title><link rel="stylesheet" href="css/normalize.css" /><link rel="stylesheet" href="css/global.css" /></head><body><div class="sr-root"><div class="sr-main"><section class="container"><div><h1>Thanks for submitting your identity document.</h1><p>We are processing your verification.</p><a href="/">Restart demo</a></div></section></div></div></body></html>
# Identity verificationThis sample shows you how to integrate with Stripe [Identity](https://stripe.com/docs/identity).### Integrations included:- [**Modal**] The modal integration allows you to collect identity documents as part of your existing flows. It also limits the amount of private information you handle on your site, allows you to support users in a variety of platforms and languages, and allows you to customize the style to match your branding.## How to run locallyThis sample includes several server implementations.Follow the steps below to run locally.**1. Clone and configure the sample**The Stripe CLI is the fastest way to clone and configure a sample to run locally.**Using the Stripe CLI**If you haven't already installed the CLI, follow the [installation steps](https://github.com/stripe/stripe-cli#installation) in the project README. The CLI is useful for cloning samples and locally testing webhooks and Stripe integrations.In your terminal shell, run the Stripe CLI command to clone the sample:```stripe samples create identity```The CLI will walk you through picking your integration type, server and clientlanguages, and configuring your `.env` config file with your Stripe API keys.**Installing and cloning manually**If you do not want to use the Stripe CLI, you can manually clone and configure the sample yourself:```git clone https://github.com/stripe-samples/identity```Copy the `.env` file into a file named `.env` in the 'server' folder. For example:```cp .env server/.env```You will need a Stripe account in order to run the demo. Once you set up youraccount, go to the Stripe [developerdashboard](https://stripe.com/docs/development#api-keys) to find your API keys.```STRIPE_PUBLISHABLE_KEY=<replace-with-your-publishable-key>STRIPE_SECRET_KEY=<replace-with-your-secret-key>````STATIC_DIR` tells the server where to the client files are located and does not need to be modified unless you move the server files.**2. Follow the server instructions on how to run:**follow the instructions in the 'server' folder README on how to run.For example, if you are running the Node server:```cd server/ # there's a README in this folder with instructionsnpm installnpm start```**3. [Optional] Run a webhook locally:**If you want to test webhook piece of the integration with a local webhook onyour machine, you can use the Stripe CLI to easily spin one up.Make sure to [install the CLI](https://stripe.com/docs/stripe-cli) and [link your Stripe account](https://stripe.com/docs/stripe-cli#link-account).```stripe listen --forward-to localhost:4242/webhook```The CLI will print a webhook secret key to the console. Set`STRIPE_WEBHOOK_SECRET` to this value in your `.env` file.You should see events logged in the console where the CLI is running.When you are ready to create a live webhook endpoint, follow our guide in thedocs on [configuring a webhook endpoint in thedashboard](https://stripe.com/docs/webhooks/setup#configure-webhook-settings).## FAQQ: Why did you pick these frameworks?A: We chose the most minimal framework to convey the key Stripe calls and concepts you need to understand. These demos are meant as an educational tool that helps you roadmap how to integrate Stripe within your own system independent of the framework.## Get supportIf you found a bug or want to suggest a new [feature/use case/sample], please [file an issue](../../issues).If you have questions, comments, or need help with code, we're here to help:- on [Discord](https://stripe.com/go/developer-chat)- on Twitter at [@StripeDev](https://twitter.com/StripeDev)- on Stack Overflow at the [stripe-payments](https://stackoverflow.com/tags/stripe-payments/info) tagSign up to [stay updated with developer news](https://go.stripe.global/dev-digest).## Authors- [@bz-stripe](https://twitter.com/atav32)- [@cjavilla-stripe](https://twitter.com/cjav_dev)
# Stripe keys# https://dashboard.stripe.com/test/apikeysSTRIPE_PUBLISHABLE_KEY=pk_test_TYooMQauvdEDq54NiTphI7jxSTRIPE_SECRET_KEY=sk_test_BQokikJOvBiI2HlWgH4olfQ2# https://stripe.com/docs/webhooks#verify-eventsSTRIPE_WEBHOOK_SECRET=whsec_1234# Environment variablesSTATIC_DIR=../client
MIT LicenseCopyright (c) 2020 Stripe, Inc. (https://stripe.com)Permission is hereby granted, free of charge, to any person obtaining a copyof this software and associated documentation files (the "Software"), to dealin the Software without restriction, including without limitation the rightsto use, copy, modify, merge, publish, distribute, sublicense, and/or sellcopies of the Software, and to permit persons to whom the Software isfurnished to do so, subject to the following conditions:The above copyright notice and this permission notice shall be included in allcopies or substantial portions of the Software.THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS ORIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THEAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHERLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THESOFTWARE.
.env.DS_Store.vscode# Dependenciesnode_modulespackage-lock.jsonyarn.lock!/yarn.lockcomposer.lock# Ruby filesGemfile.lock# Python files__pycache__venvenv# PHP filesvendorlogs# Java files.settingstarget/.classpath.factorypath.project# Typescriptdist# Dotnet filesobj/bin/
# frozen_string_literal: truerequire 'stripe'require 'sinatra'require 'dotenv'# Replace if using a different env file or configDotenv.load# For sample support and debugging, not required for production:Stripe.set_app_info('stripe-samples/identity/modal',version: '0.0.1',url: 'https://github.com/stripe-samples')Stripe.api_version = '2020-08-27'Stripe.api_key = ENV['STRIPE_SECRET_KEY']set :static, trueset :public_folder, File.join(File.dirname(__FILE__), ENV['STATIC_DIR'])set :port, 4242get '/' docontent_type 'text/html'send_file File.join(settings.public_folder, 'index.html')endget '/config' docontent_type 'application/json'{publishableKey: ENV['STRIPE_PUBLISHABLE_KEY'],}.to_jsonendpost '/create-verification-session' docontent_type 'application/json'# See https://stripe.com/docs/api/identity/verification_sessions/create# for the full list of accepted parameters.verification_session = Stripe::Identity::VerificationSession.create({type: 'document', # 'id_number' | 'address'metadata: {user_id: '{{USER_ID}}', # Optionally pass the ID of the user in your system.},# Additional options for configuring the verification session:# options: {# document: {# # Array of strings of allowed identity document types.# allowed_types: ['driving_license'], # passport | id_card## # Collect an ID number and perform an ID number check with the# # document’s extracted name and date of birth.# require_id_number: true,## # Disable image uploads, identity document images have to be captured# # using the device’s camera.# require_live_capture: true,## # Capture a face image and perform a selfie check comparing a photo# # ID and a picture of your user’s face.# require_matching_selfie: true,# }# },})# Send the VerificationSession client_secret to the client.{client_secret: verification_session.client_secret}.to_jsonendpost '/webhook' do# You can use webhooks to receive information about asynchronous payment events.# For more about our webhook events check out https://stripe.com/docs/webhooks.webhook_secret = ENV['STRIPE_WEBHOOK_SECRET']payload = request.body.readif !webhook_secret.empty?# Retrieve the event by verifying the signature using the raw body and secret if webhook signing is configured.sig_header = request.env['HTTP_STRIPE_SIGNATURE']event = nilbeginevent = Stripe::Webhook.construct_event(payload, sig_header, webhook_secret)rescue JSON::ParserError => e# Invalid payloadstatus 400returnrescue Stripe::SignatureVerificationError => e# Invalid signatureputs '⚠️ Webhook signature verification failed.'status 400returnendelsedata = JSON.parse(payload, symbolize_names: true)event = Stripe::Event.construct_from(data)endcase event.typewhen 'identity.verification_session.requires_input'verification_session = event.data.objectputs " ❌ Identity requires input from user: #{verification_session.id}"# At least one of the verification checks failedcase verification_session.last_error.codewhen 'document_unverified_other'# The document was invalidwhen 'document_expired'# The document was expiredwhen 'document_type_not_suported'# The document type was not supportedelse# ...endwhen 'identity.verification_session.verified'verification_session = event.data.objectputs " ✅ Identity verified: #{verification_session.id}"when 'identity.verification_session.canceled', 'identity.verification_session.created', 'identity.verification_session.processing'verification_session = event.data.objectputs " 🟡 #{event.type}: #{verification_session.id}"endcontent_type 'application/json'{status: 'success'}.to_jsonend
source 'https://rubygems.org/'gem 'dotenv'gem 'json'gem 'sinatra'gem 'stripe', '5.55.0'gem 'webrick'
# Name of sampleA [Sinatra](http://sinatrarb.com/) implementation.## Requirements- Ruby v2.4.5+- [Configured .env file](../README.md)## How to run1. Install dependencies```bundle install```2. Run the application```ruby server.rb```3. Go to `http://localhost:4242` in your browser to see the demo