> ## Documentation Index
> Fetch the complete documentation index at: https://docs.dhmad.tn/llms.txt
> Use this file to discover all available pages before exploring further.

# Create Identity Verification

> Start pre-account KYC and send a verification email to the user

<Endpoint method="POST" path="/api/v1/identity-verifications" />

Start Didit identity verification for a user who does not yet have a DHMAD account. DHMAD sends a **verification email** with the Didit link. The Didit session URL is **not** included in the API response.

<Warning>
  Configure **allowed redirect URLs** in your [Developer Dashboard](https://developer.dhmad.tn/dashboard/settings) before passing `redirect_url`. Unlisted URLs return **400**.
</Warning>

<Info>
  On **sandbox**, verifications are auto-approved immediately — no email is sent. See [Identity Verifications overview](/api-reference/identity-verifications/overview#sandbox-behavior).
</Info>

<RequestExample>
  ```bash cURL theme={null}
  curl -X POST https://sandbox.dhmad.tn/api/v1/identity-verifications \
    -H "Authorization: Bearer sk_sandbox_your_api_key_here" \
    -H "Content-Type: application/json" \
    -d '{
      "email": "seller@example.com",
      "external_user_id": "seller_42",
      "redirect_url": "https://yourapp.com/onboarding/kyc-done",
      "metadata": { "source": "onboarding" }
    }'
  ```

  ```javascript JavaScript theme={null}
  const response = await fetch('https://sandbox.dhmad.tn/api/v1/identity-verifications', {
    method: 'POST',
    headers: {
      'Authorization': 'Bearer sk_sandbox_your_api_key_here',
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({
      email: 'seller@example.com',
      external_user_id: 'seller_42',
      redirect_url: 'https://yourapp.com/onboarding/kyc-done',
      metadata: { source: 'onboarding' }
    })
  });

  const data = await response.json();
  ```

  ```python Python theme={null}
  import requests

  response = requests.post(
      'https://sandbox.dhmad.tn/api/v1/identity-verifications',
      headers={
          'Authorization': 'Bearer sk_sandbox_your_api_key_here',
          'Content-Type': 'application/json'
      },
      json={
          'email': 'seller@example.com',
          'external_user_id': 'seller_42',
          'redirect_url': 'https://yourapp.com/onboarding/kyc-done',
          'metadata': {'source': 'onboarding'}
      }
  )

  data = response.json()
  ```
</RequestExample>

<ResponseExample>
  ```json theme={null}
  {
    "id": "6655abc1234567890abcdef12",
    "email": "seller@example.com",
    "external_user_id": "seller_42",
    "kyc_status": "pending",
    "didit_session_status": "in_progress",
    "needs_admin_review": false,
    "claim_status": "pending",
    "linked_user_id": null,
    "linked_at": null,
    "created_at": "2026-06-06T12:00:00.000Z",
    "updated_at": "2026-06-06T12:00:00.000Z",
    "expires_at": "2026-09-04T12:00:00.000Z",
    "verification_email_sent": true,
    "verification_email_sent_at": "2026-06-06T12:00:00.000Z",
    "message": "A verification email has been sent to the user."
  }
  ```
</ResponseExample>

## Request Body

<ParamField body="email" type="string" required>
  Email address for the user. Lowercased on input. Must match the email they will use when registering on DHMAD.
</ParamField>

<ParamField body="external_user_id" type="string">
  Your internal user or seller ID. Returned in webhooks so you can update your database.
</ParamField>

<ParamField body="redirect_url" type="string">
  URL to redirect the user after they complete Didit. Must match one of your **allowed redirect URLs** in developer settings. Must use HTTPS in production (`http://localhost` allowed for development).
</ParamField>

<ParamField body="metadata" type="object">
  Optional key-value pairs (string values, max 500 characters each). Not returned in webhooks; stored on the verification record.
</ParamField>

## Response Fields

<ParamField response="id" type="string">
  Verification record ID. Store this to poll status or correlate webhooks.
</ParamField>

<ParamField response="kyc_status" type="string">
  `pending`, `approved`, or `rejected`. Sandbox create returns `approved` immediately.
</ParamField>

<ParamField response="verification_email_sent" type="boolean">
  Whether DHMAD successfully sent the invite email. If `false`, retry this request with the same email while status is still `pending`.
</ParamField>

<ParamField response="verification_email_sent_at" type="string">
  ISO 8601 timestamp of the last invite email, or `null` if none was sent.
</ParamField>

<ParamField response="message" type="string">
  Human-readable status (e.g. email sent, sandbox auto-approved, or resend cooldown message).
</ParamField>

<ParamField response="claim_status" type="string">
  `pending` until the user registers on DHMAD and KYC is linked; then `linked`.
</ParamField>

<ParamField response="linked_user_id" type="string">
  DHMAD user ID after linking, or `null` while pre-account.
</ParamField>

<ParamField response="expires_at" type="string">
  ISO 8601 expiry hint for the verification record (default 90 days).
</ParamField>

<Note>
  There is **no** `verification_url` field. The Didit link is only delivered by email to the end user.
</Note>

## Duplicate pending sessions

If you `POST` again with the same developer account and email while a **pending** session exists, the API returns **200** with the existing record and may **resend** the invite email (5-minute cooldown between resends).

## Error Responses

**User already has approved KYC on DHMAD:**

```json theme={null}
{
  "error": "Conflict",
  "message": "User already has approved KYC on DHMAD.",
  "kyc_status": "approved",
  "user_exists": true
}
```

**Redirect URL not allowed:**

```json theme={null}
{
  "error": "Bad Request",
  "message": "Redirect URL does not match any allowed redirect URLs configured in developer settings."
}
```

**Blocked email domain:**

```json theme={null}
{
  "error": "Forbidden",
  "message": "Verification is not allowed for this email domain."
}
```

***

<Info>
  After creation, subscribe to `identity.verification.updated` and `identity.verification.linked` webhooks. See the [Webhooks guide](/guides/webhooks#identity-verification-events).
</Info>
