---
updatedAt: 2026-10-13T20:42:28.000Z
agentTools:
  projectIndex: https://docs.cybrid.xyz/llms.txt
---

# Verify an Individual Customer

How do I create a customer identity verification?

## Overview

After you create a customer, the customer state progresses from `storing` to `unverified`. The `unverified` state indicates that you must create an identity verification before the customer can perform account activities like fiat transfers or crypto trading.

The Cybrid Platform verifies customers via government ID and selfie check using the `id_and_selfie` method. Verification flows may request additional documentation if the system cannot validate portions of the identity.

## Prepare your customers for verification

Share the following guidance with your customers before they start the identity verification flow. A smooth verification experience reduces drop-off and support requests.

> ✅ Reduce drop-off with a pre-flight screen
>
> Launch a "what you need" screen in your app **before** opening the Persona SDK. Customers surprised by a sudden camera request drop off far more often than those primed for it. Set clear expectations on the screen:
>
> * **What to bring**: a physical, unexpired ID (no photos or photocopies), a well-lit room, and \~3 minutes of
>   uninterrupted time.
> * **Why it matters**: verification keeps the customer's account secure and meets financial regulations.
> * **How data is handled**: reassure customers that their data is encrypted and used only for verification.
>
> Pair the intro screen with the lighting and surface tips below to push first-attempt pass rates higher.

### What you need

Customers must provide a valid, unexpired government-issued photo ID and complete a live selfie check. Customers do not need to provide their name upfront during registration — Persona collects it during the KYC process and uses it for screening. You can let customers register and interact with your app before collecting their name, as long as KYC is complete before enabling bank connections or transaction activity. The name on the ID must match the customer's legal name as returned by Persona.

**Accepted ID types:**

* Driver's license (front and back)
* Passport
* Passport card
* Visa
* Residence card

### Government ID photo tips

Poor image quality is the most common reason a verification attempt fails. Advise your customers to follow these steps when photographing their ID:

* Remove the ID from any plastic case, sleeve, or holder.
* Place the ID flat on a dark, non-reflective surface.
* Ensure all four corners of the ID are visible in the frame.
* Avoid glare, shadows, and backlighting — turn off nearby lamps or move away from windows if light reflects off the ID surface.
* Hold the camera steady and wait for auto-focus before capturing.
* If the ID has a back side (for example, a driver's license), capture both sides when prompted.
* Use a mobile phone rather than a desktop or laptop webcam. Mobile cameras produce higher resolution images that are easier to verify.

### Selfie check tips

The selfie check confirms that the person completing the verification matches the photo on the government ID. Advise your customers to:

* Face the camera directly with a neutral expression.
* Use even, front-facing lighting. Avoid backlighting from windows or harsh overhead light that casts shadows on the face.
* Remove hats, sunglasses, masks, or anything that obscures the face.
* Use a plain, uncluttered background.
* Hold the device at eye level and keep it steady.

### Device and browser requirements

* A device with a working camera is required. A mobile phone is recommended for the best experience.
* Grant camera permissions when the browser or app prompts for access. If the camera prompt does not appear, check the device or browser settings to enable camera access.
* Disable Low Power Mode (iOS) or Battery Saver (Android) before starting. These modes restrict camera functionality and can cause capture failures.
* Ensure the device is sufficiently charged.
* Use a supported, up-to-date browser such as Chrome or Safari.

### Session and timing tips

* Complete the verification in a single session when possible. Verification sessions expire after a set period, and an expired session requires a new identity verification.
* If a customer starts on a desktop, the flow can hand off to a mobile device via QR code or a short link. This is useful when the desktop webcam produces low-quality images.
* If a customer navigates away or closes the browser mid-flow, you can [resume the session](https://docs.cybrid.xyz/docs/resume-persona-inquiry-session) by generating a new session token.

## Verify with Persona SDK

Integrate the Persona SDK directly in your application to handle identity verification. Cybrid creates the Persona inquiry via the identity verification API, and you pass the inquiry ID to the Persona SDK.

Persona offers multiple integration methods including Hosted Flow, Embedded Flow, and Mobile SDKs. See [Choosing your integration method](https://docs.withpersona.com/choosing-an-integration-method) to select the approach that best fits your needs. The examples below demonstrate the Persona Embedded Flow integration.

### Prerequisites

Before integrating the Persona SDK, ensure you have:

* Created a customer via [POST /api/customers](https://docs.cybrid.xyz/reference/createcustomer)
* Obtained a customer GUID from the customer creation response

### Create an identity verification

Create an identity verification by calling `POST /api/identity_verifications`:

```http Request
POST /api/identity_verifications
Content-Type: application/json
Authorization: Bearer YOUR_TOKEN

{
  "type": "kyc",
  "method": "id_and_selfie",
  "customer_guid": "customer_guid",
  "country_code": "US",
  "expected_behaviours": ["passed_immediately"],
  "require_tax_id": true
}
```
```json Response
{
  "guid": "identity_verification_guid",
  "customer_guid": "customer_guid",
  "type": "kyc",
  "method": "id_and_selfie",
  "created_at": "2023-03-23T16:01:58.074Z",
  "state": "storing"
}
```

The create response does not include `country_code`.

> ℹ️ Sandbox testing options
>
> The `expected_behaviours` field is available in the sandbox to specify how you want the verification to be returned. This is helpful for testing success/failure scenarios. Remove the `expected_behaviours` key completely for normal operation, or include `passed_immediately` or `failed_immediately` for testing purposes.

> ✅ Match the Persona name for end-to-end Plaid testing
>
> To test an external bank account via Plaid Link in sandbox, enter `Alberta` as the **first name** and `Charleson` as the **last name** during the Persona step. This matches Plaid's default sandbox identity (see [Plaid: Testing identity](https://plaid.com/docs/identity/#testing-identity)). The downstream bank account verification (`type: bank_account`, `method: account_ownership`) then auto-passes without `expected_behaviours` and without failing into Persona document submission. See [Verify External Bank Accounts](https://docs.cybrid.xyz/docs/verifying-external-bank-accounts).

> ℹ️ Tax ID collection
>
> The `require_tax_id` flag is optional and, if set, enforces tax ID collection during verification.

> ℹ️ Country code
>
> The `country_code` field is the ISO 3166-1 alpha-2 country code of the country the customer is being verified in. It is optional; if you omit it, the verification defaults to the Bank's configured country code.

### Retrieve the Persona inquiry ID

After creating the identity verification, poll `GET /api/identity_verifications/{identity_verification_guid}` until the `persona_inquiry_id` field changes from null to the Inquiry ID.

```json Response
{
  "guid": "identity_verification_guid",
  "customer_guid": "customer_guid",
  "type": "kyc",
  "method": "id_and_selfie",
  "created_at": "2023-03-23T16:05:40.757Z",
  "state": "waiting",
  "outcome": null,
  "persona_inquiry_id": "persona_inquiry_id",
  "persona_state": "waiting"
}
```

> ✅ Use webhooks, with polling as a fallback
>
> Subscribe to identity verification webhooks (e.g., `identity_verification.waiting`) to know when to fetch `persona_inquiry_id`. You can also listen for `identity_verification.completed` to track completion, and use polling only as a fallback. See [Webhooks](https://docs.cybrid.xyz/docs/webhooks) to set up event subscriptions.

### Integrate the Persona SDK

Choose the integration method that works best for your application:

#### NPM integration

Install the Persona SDK in your application using npm:

```bash
npm install persona@5.5.0 --save
```

Import and initialize the Persona client with the inquiry ID from the identity verification:

```javascript
import Persona from 'persona';

const client = new Persona.Client({
  inquiryId: 'persona_inquiry_id',
  language: 'en',
  onReady: () => client.open(),
  onComplete: ({ inquiryId, status, fields }) => {
    console.log(`Sending finished inquiry ${inquiryId} to backend`);
    // Poll Cybrid API to confirm verification completion
    // Or use Webhooks to be updated on identity_verification.completed
  },
  onCancel: ({ inquiryId, sessionToken }) => {
    console.log('User cancelled verification');
  },
  onError: (error) => {
    console.error('Verification error:', error);
  }
});
```

#### CDN integration

Load the Persona SDK via CDN and initialize with your inquiry ID:

```html
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>Identity Verification</title>
  <script src="https://cdn.withpersona.com/dist/persona-v5.5.0.js"></script>
</head>
<body>
  <script>
    const client = new Persona.Client({
      inquiryId: 'persona_inquiry_id',
      language: 'en',
      onReady: () => client.open(),
      onComplete: ({ inquiryId, status, fields }) => {
        console.log(`Completed: ${inquiryId}`);
        // Poll Cybrid API to confirm verification completion
        // Or use Webhooks to be updated on identity_verification.completed
      },
      onCancel: ({ inquiryId, sessionToken }) => {
        console.log('Cancelled');
      },
      onError: (error) => {
        console.error(error);
      }
    });
  </script>
</body>
</html>
```

### Handle verification events

The Persona SDK provides event callbacks to track the verification flow. For detailed event handling, see [Persona's event handling documentation](https://docs.withpersona.com/docs/embedded-flow-event-handling).

**Key callbacks:**

* `onReady`: Called when the SDK is ready to display
* `onComplete`: Called when the user completes verification flow (the identity verification could still fail)
* `onCancel`: Called when the user cancels the flow
* `onError`: Called when an error occurs

> ⚠️ Logging for troubleshooting
>
> Implement logging in each callback handler. This helps troubleshoot verification issues and track user progress through the identity verification flow.

**Language support:**

The `language` parameter accepts ISO 639-1 language codes. See [Persona's supported languages](https://docs.withpersona.com/docs/languages) for the full list.

### Resume incomplete sessions

Customers can resume incomplete verification sessions if they navigate away or close their browser. Generate a new session token using the Cybrid API and pass it to the Persona SDK.

Create a session token for an existing inquiry:

```http Request
POST /api/persona_sessions
Content-Type: application/json
Authorization: Bearer YOUR_TOKEN

{
  "persona_inquiry_id": "persona_inquiry_id",
  "identity_verification_guid": "identity_verification_guid"
}
```
```json Response
{
  "persona_session_token": "persona_session_token",
  "persona_inquiry_id": "persona_inquiry_id",
  "identity_verification_guid": "identity_verification_guid"
}
```

Use the session token to resume the inquiry:

```javascript
import Persona from 'persona';

const client = new Persona.Client({
  sessionToken: 'persona_session_token',
  language: 'en',
  onReady: () => client.open(),
  onComplete: ({ inquiryId, status, fields }) => {
    console.log(`Completed: ${inquiryId}`);
  }
});
```

For more details on session resumption, see [Resume Persona Inquiry Session](https://docs.cybrid.xyz/docs/resume-persona-inquiry-session).

### Verify completion status

When the customer completes the Persona flow, poll the Cybrid API to confirm verification success.

#### Check identity verification status

Poll `GET /api/identity_verifications/{identity_verification_guid}` until `state: completed` and `outcome: passed`:

```json Response
{
  "guid": "identity_verification_guid",
  "customer_guid": "customer_guid",
  "type": "kyc",
  "method": "id_and_selfie",
  "created_at": "2026-01-01T16:05:40.757Z",
  "state": "completed",
  "outcome": "passed",
  "persona_inquiry_id": "persona_inquiry_id",
  "persona_state": "completed"
}
```

The `persona_state` also shows `completed`. If the verification fails, check the `failure_codes` array for specific issues encountered during verification.

#### Confirm customer verification

After the identity verification completes and passes, confirm the customer entered the `verified` state. Call `GET /api/customers/{customer_guid}` and verify `state: verified`:

```json Response
{
  "guid": "customer_guid",
  "type": "individual",
  "created_at": "2026-01-01T17:07:08.118Z",
  "state": "verified"
}
```

### Handle failed verifications

If the identity verification completes with `outcome: failed`, the `failure_codes` array and the individual `compliance_checks` entries indicate what went wrong and whether the customer can retry.

#### Compliance check outcomes

Each compliance check in the response has its own `outcome` value:

| Outcome        | Meaning                                                                                                                  | Action                                                                                                       |
| :------------- | :----------------------------------------------------------------------------------------------------------------------- | :----------------------------------------------------------------------------------------------------------- |
| `passed`       | The check succeeded.                                                                                                     | No action required.                                                                                          |
| `failed`       | The check definitively failed.                                                                                           | Check `failure_codes` to determine retry eligibility.                                                        |
| `insufficient` | Not enough data to make a determination (for example, the photo was too blurry or a required document side was missing). | Allow the customer to retry immediately. The customer remains `unverified`.                                  |
| `inconclusive` | The results are ambiguous and require human judgment.                                                                    | Wait for Cybrid's compliance team to complete their review. Do not prompt a retry until the review finishes. |

#### Retry eligibility by failure code

After the overall verification reaches `state: completed` with `outcome: failed`, check the `failure_codes` array and the customer's state to determine next steps:

**Customer stays `unverified` -- retry allowed:**

Create a new identity verification without contacting support. These failures are typically caused by poor image quality or incorrect documents:

* `id_check_failure`
* `id_quality_check_failure`
* `id_expiration_check_failure`
* `id_double_side_check_failure`
* `id_type_allowed_check_failure`
* `id_country_allowed_check_failure`
* `phone_number_check_failure`
* `email_address_check_failure`
* `document_type_check_failure`
* `document_quality_check_failure`
* `document_check_failure`
* `user_canceled`
* `decision_timeout`

> ℹ️ Improve retry success rates
>
> When prompting a customer to retry, surface the relevant tips from the [Prepare your customers for verification](#prepare-your-customers-for-verification) section. For example, if the failure was `id_quality_check_failure`, remind the customer to place the ID on a flat surface, ensure all four corners are visible, and avoid glare.

**Sent to compliance review -- wait for decision:**

These failures are escalated to Cybrid's compliance team. The identity verification enters the `reviewing` state and the team makes a final determination:

* `database_check_failure`
* `id_barcode_check_failure`
* `id_number_check_failure`
* `duplicate_person_check_failure`
* `country_comparison_check_failure`
* `name_check_failure`
* `address_check_failure`
* `dob_check_failure`
* `review_required`
* `pep_check_failure`
* `media_check_failure`
* `watchlist_check_failure`

**Customer is `rejected` -- contact support:**

These failures indicate fraud signals or compliance issues. The customer cannot retry without Cybrid compliance team resetting the customer state to `unverified`:

* `id_mrz_check_failure`
* `id_presence_check_failure`
* `id_digital_replica_check_failure`
* `id_paper_replica_check_failure`
* `prohibited_person_check_failure`
* `selfie_failure`
* `selfie_pose_check_failure`
* `selfie_quality_check_failure`
* `compliance_rejection`

> ⚠️ Reset customer state
>
> Please use [Cybrid Ticketing System](https://cybridhelp.zendesk.com) while providing the customer GUID and request compliance team to reset the customer state back to the `unverified` state.

For the full list of failure codes and their descriptions, see the [Identity Verification Overview](https://docs.cybrid.xyz/docs/identity-verification).

## Next steps

Now that the customer is `verified`, you can proceed with account funding and trading.

* [Create a platform account](https://docs.cybrid.xyz/docs/creating-platform-accounts)
* [Add Customer External Bank Accounts](https://docs.cybrid.xyz/docs/add-customer-external-bank-accounts)
* [Transfer Process](https://docs.cybrid.xyz/docs/transfer-process)

## Related resources

For detailed reference information about identity verification:

* [Identity Verification Overview](https://docs.cybrid.xyz/docs/identity-verification) - Verification states, return codes, and concepts
* [Verify a Business Customer with KYB](https://docs.cybrid.xyz/docs/kyb) - Business customer verification
* [Persona Theming](https://docs.cybrid.xyz/docs/persona-theming) - Customize the Persona verification UI
* [Resume Persona Inquiry Session](https://docs.cybrid.xyz/docs/resume-persona-inquiry-session) - Handle incomplete verification sessions
* [Persona Inquiry Expiry](https://docs.cybrid.xyz/docs/persona-inquiry-expiry) - Session expiration reference