Didit Sessions API

The Sessions API from Didit — 20 operation(s) for sessions.

OpenAPI Specification

didit-sessions-api-openapi.yml Raw ↑
openapi: 3.0.0
info:
  version: 3.0.0
  title: Didit Verification Billing Sessions API
  description: Identity verification API. Authenticate with x-api-key header.
servers:
- url: https://verification.didit.me
tags:
- name: Sessions
paths:
  /v3/session/:
    post:
      summary: Create a verification session
      description: 'Create a User Verification (KYC) or Business Verification (KYB) session and receive a hosted verification `url` plus a `session_token` to redirect or embed for your end user. The `workflow_id` selects which verification steps run and whether the session is KYC or KYB.


        Call this from your backend (never the browser — the API key is a secret) whenever a user or business needs to be verified: at signup, before a sensitive action, or when re-verification is required. Prerequisites: a published workflow (created in the Console [Workflows](https://docs.didit.me/console/workflows) page) and an application API key with available credits. Sandbox applications bypass the credit check.


        **Idempotency:** when `vendor_data` is provided and an unfinished session (`Not Started`, `In Progress`, `Resubmitted`, or `Awaiting User`) with the same `vendor_data` already exists on the workflow''s **current latest published version** (and that session already has a hosted verification URL), the existing session is returned (still `201`) instead of creating a duplicate — with its `callback` and `metadata` updated to the newly provided values. An unfinished session created on an older version of the workflow (one that has since been republished) is **not** reused; a new session pinned to the latest published version is created instead. Sessions in `Approved`, `Declined`, `In Review`, `Expired`, `Abandoned`, or `Kyc Expired` are never reused.


        **Side effects:** the hosted verification URL is generated and stored; if `contact_details.send_notification_emails` is `true` and an email is provided, a verification invite email is sent. The session expires after the workflow''s configured session expiration time. For KYB workflows, `contact_details.phone` and `expected_details` are ignored.'
      operationId: post_v3_session_create
      tags:
      - Sessions
      responses:
        '201':
          description: Session created (or returned, if an unfinished session with the same `vendor_data` already exists on the workflow's latest published version). The response is the serialized session, including the hosted verification `url` to redirect the user to.
          content:
            application/json:
              schema:
                type: object
                required:
                - session_id
                - session_number
                - session_token
                - url
                - vendor_data
                - metadata
                - status
                - workflow_id
                - workflow_version
                - callback
                properties:
                  session_id:
                    type: string
                    format: uuid
                    description: Unique identifier of the verification session. Use this id when calling `GET /v3/session/{sessionId}/decision/`.
                    example: 11111111-2222-3333-4444-555555555555
                  session_number:
                    type: integer
                    description: Sequential, human-friendly number assigned to the session inside your application. Useful for support and dashboards.
                    example: 43762
                  session_token:
                    type: string
                    description: 12-character URL-safe token that authorizes the end user to access the hosted verification flow at `url`. Valid until the session expires. Treat it as a secret — anyone holding it can open the verification flow for this session.
                    example: 3FaJ9wLqX2Mz
                  url:
                    type: string
                    format: uri
                    description: Hosted verification URL to redirect the end user to. The URL embeds the `session_token` and, if configured, uses your white-label domain. When the request includes `language`, the URL contains a language path segment — `https://verify.didit.me/{language}/session/{session_token}` (e.g. `/es/session/...`); without `language`, the segment is omitted.
                    example: https://verify.didit.me/session/3FaJ9wLqX2Mz
                  vendor_data:
                    type: string
                    nullable: true
                    description: Identifier you passed in the request to link the session to a user or business in your own system. Echoed back verbatim. Null when not provided.
                    example: user-123
                  metadata:
                    description: Arbitrary JSON payload you stored with the session at creation time. Echoed back verbatim — whatever JSON value you sent (object, string, number, array) is returned as-is, though a JSON object is recommended. Not shown to the end user. Always present in responses; `null` when not provided at creation time.
                    example:
                      user_type: premium
                      account_id: ABC123
                  status:
                    type: string
                    enum:
                    - Not Started
                    - In Progress
                    - Approved
                    - Declined
                    - In Review
                    - Expired
                    - Abandoned
                    - Kyc Expired
                    - Resubmitted
                    - Awaiting User
                    description: Current status of the session. Newly created sessions return `Not Started`. If a non-finished session already existed for the same `vendor_data` on the workflow's latest published version, the returned status reflects that existing session.
                    example: Not Started
                  callback:
                    type: string
                    format: uri
                    nullable: true
                    description: Final redirect URL the user is sent to after completing the flow. Didit appends `?verificationSessionId={session_id}&status={status}` to this URL. Falls back to the workflow's configured callback URL when not provided in the request; `null` when neither is set.
                    example: https://example.com/verification/callback
                  workflow_id:
                    type: string
                    format: uuid
                    description: Stable identifier of the workflow this session runs on. Always the workflow's stable group identifier — even if you referenced a specific workflow version UUID in the request (backward-compatible lookup), the response carries the stable `workflow_id`. Use it to correlate the session with the workflow you configured in the Console.
                    example: 11111111-2222-3333-4444-555555555555
                  workflow_version:
                    type: integer
                    description: Version number of the published workflow version the session was pinned to at creation. Didit resolves `workflow_id` to the workflow's latest published version when the session is created, and the session keeps running that version even if the workflow is republished later.
                    example: 3
              examples:
                KYC session:
                  summary: KYC session created
                  value:
                    session_id: 11111111-2222-3333-4444-555555555555
                    session_number: 43762
                    session_token: 3FaJ9wLqX2Mz
                    url: https://verify.didit.me/en/session/3FaJ9wLqX2Mz
                    vendor_data: user-123
                    metadata:
                      user_type: premium
                      account_id: ABC123
                    status: Not Started
                    workflow_id: 11111111-2222-3333-4444-555555555555
                    workflow_version: 3
                    callback: https://example.com/verification/callback
                KYB session:
                  summary: KYB session created
                  value:
                    session_id: 22222222-3333-4444-5555-666666666666
                    session_number: 43763
                    session_token: Yk7pQ2vN8aBc
                    url: https://verify.didit.me/en/session/Yk7pQ2vN8aBc
                    vendor_data: company-acme-001
                    metadata:
                      tier: enterprise
                    status: Not Started
                    workflow_id: 33333333-4444-5555-6666-777777777777
                    workflow_version: 1
                    callback: https://example.com/kyb/callback
        '400':
          description: 'Bad request — the payload failed validation (missing or unknown `workflow_id`, invalid `language`, blocklisted `vendor_data`, malformed `portrait_image`, `address` without `country`/`poa_country`, invalid `sandbox_scenario`, etc.) or your organization does not have enough credits to start the session.


            The body is an object keyed by the offending field name (or `detail` for non-field errors). Values are an **array of strings** for input-validation failures (e.g. missing required field, invalid language, oversized portrait image) and a **plain string** for failures detected while creating the session (unknown `workflow_id`, blocklisted `vendor_data`, no reference face available for a Face Match workflow). Handle both shapes.'
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
                properties:
                  detail:
                    type: string
                    description: Human-readable error message for non-field errors (e.g. insufficient credits). Field-level failures use the field name as the key instead, with a string or array-of-strings value.
                    example: You don't have enough credits to perform this request. Please top up at https://business.didit.me
              examples:
                Missing workflow_id:
                  summary: Required field omitted (array-of-strings shape)
                  value:
                    workflow_id:
                    - This field is required.
                Invalid workflow_id:
                  summary: Unknown workflow_id (plain-string shape)
                  value:
                    workflow_id: Invalid workflow_id.
                Insufficient credits:
                  summary: Organization is out of credits
                  value:
                    detail: You don't have enough credits to perform this request. Please top up at https://business.didit.me
                Blocklisted vendor_data:
                  summary: vendor_data is blocklisted
                  value:
                    vendor_data: This user or business has been blocked and cannot create new verification sessions.
                Portrait image too large:
                  summary: portrait_image fails size validation
                  value:
                    portrait_image:
                    - Image size exceeds 2MB.
                No stored face for vendor_data:
                  summary: Face Match workflow without portrait_image and no stored face for the vendor_data user
                  value:
                    portrait_image: No stored face image was found for this user. Send a portrait_image, or complete an approved verification with face liveness or an ID document for this vendor_data first.
                Portrait image required without vendor_data:
                  summary: Face Match workflow without portrait_image and without vendor_data
                  value:
                    portrait_image: A portrait image is required to perform face match for this workflow. Send a portrait_image, or provide the vendor_data of a user with a previously stored face image to reuse it.
        '403':
          description: 'Authentication or authorization failed. The endpoint returns `403` whenever the `x-api-key` header is missing, malformed, the API key has expired, or the API key is valid but the client does not have permission to create sessions in this application (for example the API key belongs to a different organization). Re-fetch the application API key via the [Auth API](/auth-api/get-credentials) and retry.


            **Note:** All four failure modes return the same response body — `{"detail": "You do not have permission to perform this action."}` — and there is no machine-readable discriminator (no error code field, no `WWW-Authenticate` challenge) that lets you tell them apart. If you need to differentiate (for example to surface a more specific error to the end user), check the `x-api-key` header is present and belongs to the intended application before calling this endpoint.'
          content:
            application/json:
              schema:
                type: object
                properties:
                  detail:
                    type: string
                    example: You do not have permission to perform this action.
              examples:
                Missing or invalid API key:
                  summary: No `x-api-key` header or invalid API key
                  value:
                    detail: You do not have permission to perform this action.
                No permission:
                  summary: Client cannot create sessions
                  value:
                    detail: You do not have permission to perform this action.
        '429':
          description: 'Rate limit exceeded — more than 600 session-create requests in a 60-second window from the same API key / IP. Inspect `Retry-After` and back off before retrying.


            **Note:** The source code also defines a `FREE_SESSION_RATE_LIMIT` of 10 calls/minute alongside `PAID_SESSION_RATE_LIMIT=600` (`sessions/serializers/session.py`), but that free-tier ceiling is **not applied to this V3 endpoint** — the rate-limit middleware enforces the 600/min `SESSION_CREATE_RATE_LIMIT` regardless of plan. 600/min is the only limit you can hit here.'
          headers:
            Retry-After:
              description: Seconds the caller must wait before retrying the request.
              schema:
                type: integer
                minimum: 1
                example: 42
            X-RateLimit-Limit:
              description: Maximum number of requests allowed in the current 60-second window for the limit that was breached (600 for session-create). Absent on the sandbox-quota variant.
              schema:
                type: integer
                example: 600
            X-RateLimit-Remaining:
              description: Number of requests still allowed in the current window for the breached limit. Absent on the sandbox-quota variant.
              schema:
                type: integer
                minimum: 0
                example: 0
            X-RateLimit-Reset:
              description: UTC epoch seconds when the current rate-limit window resets. Absent on the sandbox-quota variant.
              schema:
                type: integer
                minimum: 0
                example: 1747497600
          content:
            application/json:
              schema:
                type: object
                properties:
                  detail:
                    type: string
                    description: Human-readable explanation of the rate-limit breach. Use this message to distinguish which of the three limits was hit.
                    example: Session creation rate limit exceeded. You can make up to 600 requests per minute.
              examples:
                Session-create limit:
                  summary: More than 600 session-create requests per minute
                  value:
                    detail: Session creation rate limit exceeded. You can make up to 600 requests per minute.
                Sandbox session quota:
                  summary: Sandbox application exceeded 500 sessions in 24 hours
                  value:
                    detail: Sandbox session quota exceeded (500 sessions per 24h). Wait for the window to reset. Expected available in 3600 seconds.
      security:
      - ApiKeyAuth: []
      x-codeSamples:
      - lang: curl
        label: cURL
        source: "curl -X POST 'https://verification.didit.me/v3/session/' \\\n  -H 'x-api-key: YOUR_API_KEY' \\\n  -H 'Content-Type: application/json' \\\n  -d '{\n    \"workflow_id\": \"11111111-2222-3333-4444-555555555555\",\n    \"vendor_data\": \"user-123\",\n    \"callback\": \"https://example.com/verification/callback\",\n    \"callback_method\": \"both\",\n    \"metadata\": {\"user_type\": \"premium\", \"account_id\": \"ABC123\"},\n    \"language\": \"en\",\n    \"contact_details\": {\n      \"email\": \"john.doe@example.com\",\n      \"send_notification_emails\": true,\n      \"email_lang\": \"en\",\n      \"phone\": \"+14155552671\"\n    },\n    \"expected_details\": {\n      \"first_name\": \"John\",\n      \"last_name\": \"Doe\",\n      \"date_of_birth\": \"1990-05-15\",\n      \"id_country\": \"USA\",\n      \"expected_document_types\": [\"P\", \"ID\"]\n    }\n  }'"
      - lang: python
        label: Python
        source: "import requests\n\nurl = \"https://verification.didit.me/v3/session/\"\nheaders = {\n    'x-api-key': 'YOUR_API_KEY',\n    \"Content-Type\": \"application/json\",\n}\npayload = {\n    \"workflow_id\": \"11111111-2222-3333-4444-555555555555\",\n    \"vendor_data\": \"user-123\",\n    \"callback\": \"https://example.com/verification/callback\",\n    \"callback_method\": \"both\",\n    \"metadata\": {\"user_type\": \"premium\", \"account_id\": \"ABC123\"},\n    \"language\": \"en\",\n    \"contact_details\": {\n        \"email\": \"john.doe@example.com\",\n        \"send_notification_emails\": True,\n        \"email_lang\": \"en\",\n        \"phone\": \"+14155552671\",\n    },\n    \"expected_details\": {\n        \"first_name\": \"John\",\n        \"last_name\": \"Doe\",\n        \"date_of_birth\": \"1990-05-15\",\n        \"id_country\": \"USA\",\n        \"expected_document_types\": [\"P\", \"ID\"],\n    },\n}\n\nresponse = requests.post(url, json=payload, headers=headers, timeout=15)\nresponse.raise_for_status()\nsession = response.json()\nprint(session[\"session_id\"], session[\"url\"])"
      - lang: javascript
        label: JavaScript
        source: "const response = await fetch('https://verification.didit.me/v3/session/', {\n  method: 'POST',\n  headers: {\n    'x-api-key': 'YOUR_API_KEY',\n    'Content-Type': 'application/json',\n  },\n  body: JSON.stringify({\n    workflow_id: '11111111-2222-3333-4444-555555555555',\n    vendor_data: 'user-123',\n    callback: 'https://example.com/verification/callback',\n    callback_method: 'both',\n    metadata: { user_type: 'premium', account_id: 'ABC123' },\n    language: 'en',\n    contact_details: {\n      email: 'john.doe@example.com',\n      send_notification_emails: true,\n      email_lang: 'en',\n      phone: '+14155552671',\n    },\n    expected_details: {\n      first_name: 'John',\n      last_name: 'Doe',\n      date_of_birth: '1990-05-15',\n      id_country: 'USA',\n      expected_document_types: ['P', 'ID'],\n    },\n  }),\n});\n\nif (!response.ok) {\n  throw new Error(`Session create failed: ${response.status}`);\n}\nconst session = await response.json();\nconsole.log(session.session_id, session.url);"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
              - workflow_id
              properties:
                workflow_id:
                  type: string
                  format: uuid
                  description: Stable identifier of the workflow that defines which verification steps the session will run. Workflows are created and managed in the [Workflows](/console/workflows) page of the Console. The `workflow_id` also implicitly selects whether the session is KYC or KYB.
                  example: 11111111-2222-3333-4444-555555555555
                  x-readme-id: '0.0'
                vendor_data:
                  type: string
                  description: 'A unique identifier for the user being verified, such as a UUID, email, or internal user ID. This field is used for: (1) **User grouping** — sessions with the same vendor_data are linked to the same user profile in the Users tab. (2) **Cross-session duplicate detection** — when checking for duplicated faces, documents, phone numbers, emails, IP addresses, or device fingerprints, sessions with the same vendor_data are treated as the same user and excluded from matches. Without vendor_data, every session is treated as a unique user and all potential duplicates are surfaced. We strongly recommend always providing a vendor_data to reduce noise in duplicate detection.'
                  example: user-123
                  x-readme-id: '0.1'
                callback:
                  type: string
                  description: URL to redirect the user to after verification completes. Didit automatically appends `verificationSessionId` and `status` (Approved, Declined, In Review) as query parameters. Custom URL schemes (e.g. `myapp://`) are supported for mobile callbacks. If omitted, the workflow's default `callback_url` is used.
                  example: https://example.com/verification/callback
                  x-readme-id: '0.2'
                callback_method:
                  type: string
                  description: Determines which device should handle the redirect to the provided callback URL. Use `initiator` to redirect only the device that started the flow, `completer` for the device that finishes it, or `both` to allow either device to trigger the callback. If you ever notice the callback not triggering reliably, we recommend setting this value to `both`.
                  enum:
                  - initiator
                  - completer
                  - both
                  default: initiator
                  example: both
                  x-readme-id: '0.3'
                metadata:
                  description: Arbitrary JSON stored with the session and echoed back in the response and webhooks. Any JSON value is accepted (object, string, number, array), but a JSON object of key/value pairs is recommended. Not shown to the end user. Use it to pass your own correlation ids, A/B variants, or business context.
                  example:
                    user_type: premium
                    account_id: ABC123
                  x-readme-id: '0.4'
                language:
                  type: string
                  description: Language code (ISO 639-1) for the verification process interface. Controls the language displayed to the end user during verification. If not provided, the browser's language will be automatically detected and used. Check all the supported languages [here](/integration/supported-languages).
                  enum:
                  - en
                  - ar
                  - bg
                  - bn
                  - bs
                  - ca
                  - cnr
                  - cs
                  - da
                  - de
                  - el
                  - es
                  - et
                  - fa
                  - fi
                  - fr
                  - he
                  - hi
                  - hr
                  - hu
                  - hy
                  - id
                  - it
                  - ja
                  - ka
                  - kk
                  - ko
                  - ky
                  - lt
                  - lv
                  - mk
                  - mn
                  - ms
                  - nl
                  - 'no'
                  - pl
                  - pt-BR
                  - pt
                  - ro
                  - ru
                  - sk
                  - sl
                  - so
                  - sq
                  - sr
                  - sv
                  - th
                  - tr
                  - uk
                  - uz
                  - vi
                  - zh-CN
                  - zh-TW
                  - zh
                  example: en
                  x-readme-id: '0.5'
                contact_details:
                  type: object
                  description: User contact information that can be used for notifications, prefilling verification forms, and phone verification. This includes email address, preferred language for communications, and phone number.
                  example:
                    email: john.doe@example.com
                    send_notification_emails: true
                    email_lang: en
                    phone: '+14155552671'
                  properties:
                    email:
                      type: string
                      format: email
                      description: Email address of the user (e.g., "john.doe@example.com") that will be used during the [Email Verification](/core-technology/email-verification/overview) step. If not provided, the user must provide it during the verification flow.
                      example: john.doe@example.com
                      x-readme-id: '1.0'
                    send_notification_emails:
                      type: boolean
                      default: false
                      description: If true and an email is provided, Didit sends the initial "Verify your identity" email asynchronously when the User Verification (KYC) or Business Verification (KYB) session is created. Didit also sends verification status notifications for sessions requiring manual review to the provided email address (e.g., from 'In Review' to 'Approved' or 'Declined'). This helps users return to your application once their verification is complete. If you have white-label activated for the session, the email sent will be white-labeled.
                      example: true
                      x-readme-id: '1.1'
                    email_lang:
                      type: string
                      description: Language code (ISO 639-1) for email notifications. Controls the language of all email communications (e.g., "en", "es", "fr"). There is no stored default — when omitted, the verification invite email simply falls back to English (`en`) at send time. The enum below is a snapshot; the live source of truth for accepted values is the [supported languages](/integration/supported-languages) doc — always consult it before relying on a specific code.
                      enum:
                      - en
                      - ar
                      - bg
                      - bn
                      - bs
                      - ca
                      - cnr
                      - cs
                      - da
                      - de
                      - el
                      - es
                      - et
                      - fa
                      - fi
                      - fr
                      - he
                      - hi
                      - hr
                      - hu
                      - hy
                      - id
                      - it
                      - ja
                      - ka
                      - kk
                      - ko
                      - ky
                      - lt
                      - lv
                      - mk
                      - mn
                      - ms
                      - nl
                      - 'no'
                      - pl
                      - pt-BR
                      - pt
                      - ro
                      - ru
                      - sk
                      - sl
                      - so
                      - sq
                      - sr
                      - sv
                      - th
                      - tr
                      - uk
                      - uz
                      - vi
                      - zh-CN
                      - zh-TW
                      - zh
                      example: en
                      x-readme-id: '1.2'
                    phone:
                      type: string
                      description: Phone number in E.164 format (e.g., "+14155552671") that will be used during the [Phone Verification](/core-technology/phone-verification/overview) step. If not provided, the user must provide it during the verification flow. Ignored for Business Verification (KYB) workflows. **Important:** This phone number is only enforced if it is a valid E.164 phone number. If the provided number is invalid or cannot be parsed, it will be ignored and the user will be able to input any valid phone number during the Phone Verification step.
                      example: '+14155552671'
                      x-readme-id: '1.3'
                  x-readme-id: '0.4'
                expected_details:
                  type: object
                  description: Expected user details used to cross-validate against the data extracted from the user's ID document, Proof of Address, and other verification steps. Mismatches are surfaced as warnings on the decision; some fields (e.g. `id_country`, `expected_document_types`) also alter the user-facing flow. For Business Verification (KYB) workflows only the business fields (`company_name`, `registry_country`, `registration_number`) are used — they pre-fill the company registry search for the user — and all person-level fields are ignored.
                  example:
                    first_name: John
                    last_name: Doe
                    date_of_birth: '1990-05-15'
                    nationality: USA
                    id_country: USA
                    expected_document_types:
                    - P
                    - ID
                  properties:
                    first_name:
                      type: string
                      description: User's first name. For example, `John`. The matching uses fuzzy comparison, and you can tune the strictness by configuring the name match score threshold in the Console for both ID Document and Proof of Address workflows.
                      example: John
                      x-readme-id: '1.0'
                    last_name:
                      type: string
                      description: User's last name. For example, `Doe`. The matching uses fuzzy comparison, and you can tune the strictness by configuring the name match score threshold in the Console for both ID Document and Proof of Address workflows.
                      example: Doe
                      x-readme-id: '1.1'
                    date_of_birth:
                      type: string
                      format: date
                      description: 'User''s date of birth with format: YYYY-MM-DD. For example, `1990-05-15`.'
                      example: '1990-05-15'
                      x-readme-id: '1.2'
                    gender:
                      type: string
                      nullable: true
                      enum:
                      - M
                      - F
                      default: null
                      description: User's gender. Must be either 'M', 'F', or null.
                      example: M
                      x-readme-id: '1.3'
                    nationality:
                      type: string
                      description: ISO 3166-1 alpha-3 country code representing the applicant's country of origin. For example, `USA`. See the [full list of supported country codes](https://docs.didit.me/core-technology/id-verification/supported-documents-id-verification#supported-documents-by-country).
                      example: USA
                      x-readme-id: '1.4'
                    country:
                      type: string
                      description: ISO 3166-1 alpha-3 country code used as a fallback for both ID Verification and Proof of Address country-mismatch checks. Required when `address` is provided and neither `id_country` nor `poa_country` is set.
                      example: USA
                      x-readme-id: 1.4.1
                    id_country:
                      type: string
                      description: ISO 3166-1 alpha-3 country code representing the expected country of the applicant's ID document, which may differ from nationality. For example, `GBR`. Takes priority over 

# --- truncated at 32 KB (288 KB total) ---
# Full source: https://raw.githubusercontent.com/api-evangelist/didit/refs/heads/main/openapi/didit-sessions-api-openapi.yml