# Integrate the KYC tier system for the Embedded Components onramp Learn about KYC verification tiers, the information required for each, and how to detect when a user's purchase amount is limited by their verification level. All users must pass KYC verification before they can buy crypto with the onramp. Users can provide additional information to increase their purchase limits. This guide covers the KYC tiers, the information required for each tier, and how you can detect when a user’s purchase amount is limited by the amount of KYC information provided. > EU users have additional identifier and attestation requirements beyond the standard KYC tiers. See the [EU KYC integration guide](https://docs.stripe.com/crypto/onramp/eu-kyc-integration-guide.md) for details. ## Before you begin Before you begin, [integrate the Embedded Components Onramp](https://docs.stripe.com/crypto/onramp/embedded-components-integration-guide.md). ## KYC tier comparison The following table summarizes the requirements for each KYC tier. | KYC tier | User inputs | | -------- | --------------------------- | | L0 | Name, phone, email, address | | L1 | + Date of birth, SSN | | L2 | + Photo ID, selfie | ## KYC API ### Use attachKYCInfo for L0 and L1 KYC Call `attachKYCInfo` to initiate the L0 and L1 KYC verification processes for a user. The fields collected by `attachKYCInfo` depend on the tier: - **L0**: `firstName`, `lastName`, `address` - **L1**: All L0 fields, plus `dateOfBirth`, `idNumber`, `idType` L0 and L1 verification are asynchronous. Call this API and check the verification status before you create an onramp session. [Creating a CryptoOnrampSession](https://docs.stripe.com/api/crypto/onramp_sessions/create.md) returns a `400` error if the user has pending verifications. Continue retrieving the verification result until no verification remains pending. See [Determine whether a user is verified](https://docs.stripe.com/crypto/onramp/kyc-integration-guide.md#determine-whether-a-user-is-verified) for details. ### Use verifyIdentity for L2 KYC Call `verifyIdentity` to present a Stripe-hosted flow where the user uploads an identity document and a selfie. L2 verification is asynchronous. Your backend must call the [Retrieve a CryptoCustomer](https://docs.stripe.com/api/crypto/customers/retrieve.md) API with the `customerId`. The API returns the L2 verification status in `id_document_verified`. ### Handling KYC error for createCryptoPaymentToken Users must submit their minimum identity information (name, phone, email, and address) before you can collect payment methods. If a user hasn’t yet provided this minimum information, `createCryptoPaymentToken` returns a `crypto_onramp_missing_minimum_identity_verification` error. Handle this error by prompting the user to submit their information using `attachKYCInfo`. A user’s L0 tier verification status is independent of their ability to use the onramp. If a user submits the minimum identity information but fails L0 verification, they can still use the onramp by completing L1 verification (date of birth and SSN). L1 verification supersedes L0. ### Determining a user’s current KYC tier [Retrieve a CryptoCustomer](https://docs.stripe.com/api/crypto/customers/retrieve.md) with the `customerId` and inspect the `kyc_tiers` field to determine a user’s current KYC tier. The user’s current tier is the highest tier where `verification_status` is not `not_available` or `not_started`. The `verification_status` values for each tier are: | Value | Description | | --------------- | --------------------------------------------------------------- | | `not_available` | Verification is not supported for the user’s region. | | `not_started` | The user hasn’t provided the required fields for this tier yet. | | `pending` | Verification has been submitted and is processing. | | `rejected` | Verification failed. | | `verified` | Verification completed successfully. | For example, given the following `kyc_tiers` response: ```json "kyc_tiers": [ { "tier": "l0", "verification_status": "verified", "verification_errors": [] }, { "tier": "l1", "verification_status": "verified", "verification_errors": [] }, { "tier": "l2", "verification_status": "not_started", "verification_errors": [] } ] ``` The user’s current tier is L1 because it is the highest tier that is not `not_available` or `not_started`. After [Retrieving a CryptoCustomer](https://docs.stripe.com/api/crypto/customers/retrieve.md), use the following snippet to determine the user’s current KYC tier from the `kyc_tiers` field in the response: ```js // Iterates from the highest tier (l2) to the lowest (l0) and returns the first tier // whose verification_status is "pending", "rejected", or "verified" (meaning the user // has at least attempted that tier). Returns undefined if no tier has been started. const currentTier = ["l2", "l1", "l0"].find((t) => ["pending", "rejected", "verified"].includes(customer.kyc_tiers.find((k) => k.tier === t)?.verification_status)); ``` You can also use the `provided_fields` field to determine a user’s tier: | User | Provided fields | | ---- | ------------------------------------------------------------------------------------------------------------------------------------------ | | L0 | `first_name`, `last_name`, `address_line_1`, (`address_line_2`), `address_city`, `address_state`, `address_postal_code`, `address_country` | | L1 | All L0 fields, plus `id_number`, `id_type`, `dob` | | L2 | All L1 fields, plus `id_document`, `selfie` | ### Determine whether a user is verified After retrieving the user’s current KYC tier, check whether the tier entry for that tier has `verification_status: "verified"`. If so, the user is verified at that tier. The following table summarizes how to use the `kyc_tiers` field to check verification status: | User | Verified | | ---- | ----------------------------------------------------------------------------- | | L0 | The `kyc_tiers` entry with `tier: "l0"` has `verification_status: "verified"` | | L1 | The `kyc_tiers` entry with `tier: "l1"` has `verification_status: "verified"` | | L2 | The `kyc_tiers` entry with `tier: "l2"` has `verification_status: "verified"` | The deprecated `verifications` field can also be used to determine verification status: | User | Verified | | ---- | -------------------------------------------------- | | L0 | `kyc_verified: true`, `phone_verified: true` | | L1 | `kyc_verified: true` | | L2 | `kyc_verified: true`, `id_document_verified: true` | ### Interpret limit errors from CryptoOnrampSession Your backend must [Create a CryptoOnrampSession](https://docs.stripe.com/api/crypto/onramp_sessions/create.md) to create a [CryptoOnrampSession](https://docs.stripe.com/api/crypto/onramp_sessions/object.md). If the user reaches a purchase limit, the `Create a CryptoOnrampSession` API returns an HTTP `400` error with a JSON object that describes the error. Your application can use these errors to request more information from the user so they can complete the transaction. If creating a CryptoOnrampSession returns an HTTP `400` error with one of the following error codes, [Retrieve a CryptoCustomer](https://docs.stripe.com/api/crypto/customers/retrieve.md) with the `customerId` to determine the next step. - `crypto_onramp_missing_minimum_identity_verification` - `crypto_onramp_missing_identity_verification` - `crypto_onramp_missing_document_verification` The following table summarizes how to use both the error code from [Creating a CryptoOnrampSession](https://docs.stripe.com/api/crypto/onramp_sessions/create.md) and the `kyc_tiers` field from [Retrieving a CryptoCustomer](https://docs.stripe.com/api/crypto/customers/retrieve.md) to determine the next step. | Error code | Meaning | Next step | | ----------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `crypto_onramp_missing_minimum_identity_verification` | The customer hasn’t yet submitted the minimum identity information required to create a session. The user needs to provide their name, phone, email, and address. | Prompt the user to submit their minimum identity information (name, phone, email, and address) using `attachKYCInfo`. If the user subsequently fails L0 tier verification, they can still use the onramp by completing L1 verification (date of birth and SSN), which supersedes L0. | | `crypto_onramp_missing_identity_verification` | L1 verification is required. The customer must provide full or partial L1 data to complete the transaction: - The user is an L1 user and they didn’t pass the L1 identity verification required to create a session. - The user is a verified L0 user but the transaction requires L1 verification. | Inspect [Retrieve a CryptoCustomer](https://docs.stripe.com/api/crypto/customers/retrieve.md) API response `kyc_tiers` to determine the next step. - If the user’s current tier is L1, prompt the user to provide full L1 KYC information, including name, address, date of birth and Social Security number. - If the user’s current tier is L0, prompt the user to provide only `dob`, `id_number`, `id_type`, then upload partially with `attachKYCInfo` (only include these three fields). | | `crypto_onramp_missing_document_verification` | L2 verification is required. The customer must provide a photo ID and selfie to complete the transaction: - The user is an L2 user and they didn’t pass the L2 document identity verification required to create a session. - The user is a verified L0 user but the transaction requires L2 verification. - The user is a verified L1 user but the transaction requires L2 verification. | Inspect [Retrieve a CryptoCustomer](https://docs.stripe.com/api/crypto/customers/retrieve.md) API response `kyc_tiers` to determine the next step. - If the user’s current tier is L2, prompt the user to complete L2 KYC verification with `verifyIdentity`. - If the user’s current tier is L0, prompt the user to collect only `dob`, `id_number`, `id_type`, upload partially with `attachKYCInfo`, then prompt the user to complete L2 KYC verification with `verifyIdentity`. - If the user’s current tier is L1, prompt the user to complete L2 KYC verification with `verifyIdentity`. |