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

# Liveness verification link

> Issue a hosted link for a liveness check, and relay it to the person who has to take it. A liveness check needs an interactive session, so it cannot be done from an uploaded image.

You get one link for an individual, and one per beneficial owner for a business. Each entry says whose it is. The result arrives on the `user.liveness_completed` webhook — see [Webhooks](/webhooks/overview) — which is the only place to read it: a person can reach your success page before the check is finished.

<Info>
  Liveness is switched on per account, not per user. While it is off, every call answers `404` whichever `user_id` you pass. Ask your Kira contact to enable it before you build against this.
</Info>


## OpenAPI

````yaml /openapi/kira-api.2026-04-14.json post /v1/users/{user_id}/liveness-link
openapi: 3.1.0
info:
  title: Kira API
  version: '2026-04-14'
  description: >-
    REST API for users, KYC/KYB verification, virtual accounts, payouts,
    recipients, and webhooks. Every request requires an `x-api-key` header and a
    bearer access token (see Authentication). Pin your account to version
    `2026-04-14` before integrating.
  contact:
    name: Kira API Support
    email: support@kirafin.ai
servers:
  - url: https://api.balampay.com
    description: Production
  - url: https://api.balampay.com/sandbox
    description: Sandbox
security:
  - bearerAuth: []
    apiKeyAuth: []
tags:
  - name: Authentication
  - name: Versioning
  - name: Users
  - name: Virtual Accounts
  - name: Recipients
  - name: Quotations
  - name: Payouts
  - name: Reference
paths:
  /v1/users/{user_id}/liveness-link:
    post:
      tags:
        - Users
      summary: Liveness verification link
      description: >-
        Issue a hosted link for a liveness check, and relay it to the person who
        has to take it. A liveness check needs an interactive session, so it
        cannot be done from an uploaded image.


        You get one link for an individual, and one per beneficial owner for a
        business. Each entry says whose it is. The result arrives on the
        `user.liveness_completed` webhook — see [Webhooks](/webhooks/overview) —
        which is the only place to read it: a person can reach your success page
        before the check is finished.
      operationId: post_v1-users-user-id-liveness-link
      parameters:
        - in: path
          name: user_id
          required: true
          schema:
            type: string
            format: uuid
          description: >-
            The user the check is for. For a business, this is the business —
            the links come back per beneficial owner.
        - in: header
          name: X-Api-Version
          required: false
          description: >-
            Version applied to this request. It wins over your account's pinned
            version — see [Versioning](/using-the-api/versioning).
          schema:
            type: string
            example: '2026-04-14'
      requestBody:
        required: false
        content:
          application/json:
            schema:
              type: object
              description: >-
                The body is optional. Send it only to land the person on your
                own page afterwards; unknown fields are ignored.
              properties:
                redirect:
                  type: object
                  description: >-
                    Where to send the person after the session, instead of the
                    default completion screen. Both URLs have to be HTTPS and
                    their host has to be on your redirect allowlist, which your
                    Kira contact sets up.
                  properties:
                    success_url:
                      type: string
                      description: >-
                        Where the person lands after finishing. Required once
                        you send `redirect`.
                    reject_url:
                      type: string
                      description: Where the person lands if the check is refused.
            examples:
              no-body:
                summary: The default completion screen
                value: {}
              with-redirect:
                summary: Send the person back to your page
                value:
                  redirect:
                    success_url: https://app.example.com/kyc/done
                    reject_url: https://app.example.com/kyc/failed
      responses:
        '200':
          description: One link per person who has to take the check.
          content:
            application/json:
              schema:
                type: object
                properties:
                  links:
                    type: array
                    description: >-
                      One entry for an individual, one per beneficial owner for
                      a business.
                    items:
                      type: object
                      properties:
                        subject:
                          type: string
                          description: >-
                            Who the link is for. Available options: `user`,
                            `ubo`. See [User
                            values](/reference/users/values#liveness-subject).
                        person_reference_id:
                          type: string
                          description: >-
                            Which beneficial owner the link is for. Only on a
                            `ubo` entry, and it comes back on the webhook so you
                            can match the result.
                        name:
                          type: string
                          description: >-
                            That beneficial owner's name, so you know who to
                            send the link to. Only on a `ubo` entry.
                        liveness_link:
                          type: string
                          description: >-
                            The hosted session. Relay it to the person; do not
                            open it yourself.
                        expires_at:
                          type: string
                          description: >-
                            When the link stops working, as an ISO 8601
                            timestamp. A link lasts 7 days.
              example:
                links:
                  - subject: ubo
                    person_reference_id: 0123456789abcdef0123456789abcdef
                    name: Alice Smith
                    liveness_link: https://kyc.example.com/s/abc123
                    expires_at: '2026-09-08T12:00:00.000Z'
                  - subject: ubo
                    person_reference_id: fedcba9876543210fedcba9876543210
                    name: Bob Jones
                    liveness_link: https://kyc.example.com/s/def456
                    expires_at: '2026-09-08T12:00:00.000Z'
        '400':
          description: >-
            `user_id` is not a UUID, or `redirect` is not an object. Anything
            else in the body is ignored rather than rejected.
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    description: Always `Invalid request data`.
                  details:
                    type: array
                    description: One entry per rejected value.
                    items:
                      type: object
                      properties:
                        path:
                          type: string
                          description: The value that was rejected.
                        message:
                          type: string
                          description: What is wrong with it.
                        code:
                          type: string
                          description: The validation rule that failed.
              example:
                error: Invalid request data
                details:
                  - path: user_id
                    message: Invalid uuid
                    code: invalid_string
        '401':
          description: >-
            Your credentials were not accepted. The message talks about routing,
            but it is the same body for every cause, so it is not a guide to
            which one:


            - The `Authorization` header is missing, expired or wrong. Get a new
            token from [Get access
            token](/api-reference/authentication/get-access-token).

            - The `x-api-key` header is missing or wrong.

            - One is present and the other is not.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
              example:
                code: invalid_request
                message: >-
                  The request could not be matched to a valid route, or was
                  malformed. Verify the path and HTTP method against the API
                  reference. This is a routing or request error, not a
                  credentials or signature problem.
        '404':
          description: >-
            Either no user of yours has that id, or liveness is not switched on
            for your account — it is enabled per account, so ask your Kira
            contact. Both answer the same way, so check the `message`.


            A path or method that is not routed answers `404` instead, with
            `code: route_not_found` and a different message. `PATCH` is not
            routed on any user path.
          content:
            application/json:
              schema:
                type: object
                properties:
                  statusCode:
                    type: integer
                    description: Repeats the HTTP status.
                  error:
                    type: string
                    description: The status name.
                  message:
                    type: string
                    description: What went wrong, in one sentence.
                  timestamp:
                    type: string
                    description: When the call was rejected, as an ISO 8601 timestamp.
                  path:
                    type: string
                    description: The path you called.
                  code:
                    type: string
                    description: A short machine-readable reason.
              examples:
                not-enabled:
                  summary: Liveness is not switched on for your account
                  value:
                    statusCode: 404
                    error: Not Found
                    message: Not found
                    timestamp: '2026-09-01T12:00:00.000Z'
                    path: >-
                      /v1/users/11111111-2222-3333-4444-555555555555/liveness-link
                    code: not_found
                no-user:
                  summary: No user of yours has that id
                  value:
                    statusCode: 404
                    error: Not Found
                    message: >-
                      User with ID 11111111-2222-3333-4444-555555555555 not
                      found
                    timestamp: '2026-09-01T12:00:00.000Z'
                    path: >-
                      /v1/users/11111111-2222-3333-4444-555555555555/liveness-link
                    code: not_found
        '422':
          description: >-
            The request was fine but no link could be minted, and the most
            common reason is that there is nothing to attach the result to yet.
            `code` says which — see the enum for all eight.
          content:
            application/json:
              schema:
                type: object
                properties:
                  statusCode:
                    type: integer
                    description: Repeats the HTTP status.
                  error:
                    type: string
                    description: Always `Unprocessable Entity`.
                  message:
                    type: string
                    description: What is missing, in one sentence.
                  timestamp:
                    type: string
                    description: When the call was rejected, as an ISO 8601 timestamp.
                  path:
                    type: string
                    description: The path you called.
                  code:
                    type: string
                    description: >-
                      Why no link could be minted, and what to branch on. Eight
                      values — see [User
                      values](/reference/users/values#liveness-code).
              examples:
                nothing-to-attach:
                  summary: The person has no identity check to attach the result to
                  value:
                    statusCode: 422
                    error: Unprocessable Entity
                    message: >-
                      User has no identity verification to attach a liveness
                      check to — complete verification first
                    timestamp: '2026-09-01T12:00:00.000Z'
                    path: >-
                      /v1/users/11111111-2222-3333-4444-555555555555/liveness-link
                    code: liveness_applicant_missing
                kyb-not-submitted:
                  summary: The business has not submitted its verification yet
                  value:
                    statusCode: 422
                    error: Unprocessable Entity
                    message: >-
                      Business KYB has not been submitted — complete
                      verification submission before requesting liveness
                    timestamp: '2026-09-01T12:00:00.000Z'
                    path: >-
                      /v1/users/11111111-2222-3333-4444-555555555555/liveness-link
                    code: liveness_company_applicant_missing
                redirect-rejected:
                  summary: >-
                    The redirect URL is not HTTPS, not allowlisted, or has no
                    success_url
                  value:
                    statusCode: 422
                    error: Unprocessable Entity
                    message: 'redirect URL host not allowed: app.example.org'
                    timestamp: '2026-09-01T12:00:00.000Z'
                    path: >-
                      /v1/users/11111111-2222-3333-4444-555555555555/liveness-link
                    code: liveness_redirect_url_not_allowed
        '500':
          description: >-
            Liveness is not configured in this environment, so no link can be
            minted for anyone. Nothing you send changes it — contact your Kira
            contact.
          content:
            application/json:
              schema:
                type: object
                properties:
                  statusCode:
                    type: integer
                    description: Repeats the HTTP status.
                  error:
                    type: string
                    description: Always `Internal Server Error`.
                  message:
                    type: string
                    description: Which part of the liveness configuration is missing.
                  timestamp:
                    type: string
                    description: When the call was rejected, as an ISO 8601 timestamp.
                  path:
                    type: string
                    description: The path you called.
                  code:
                    type: string
                    description: Always `liveness_levels_unconfigured`.
              example:
                statusCode: 500
                error: Internal Server Error
                message: Liveness verification is not configured for this environment
                timestamp: '2026-09-01T12:00:00.000Z'
                path: /v1/users/11111111-2222-3333-4444-555555555555/liveness-link
                code: liveness_levels_unconfigured
      servers:
        - url: https://api.balampay.com/sandbox
          description: Sandbox
        - url: https://api.balampay.com
          description: Production
components:
  schemas:
    ErrorResponse:
      type: object
      properties:
        message:
          type: string
        code:
          type: string
        statusCode:
          type: number
        error:
          type: string
        timestamp:
          type: string
        path:
          type: string
        details: {}
      required:
        - message
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      bearerFormat: JWT
      description: >-
        The `data.access_token` value from [Get access
        token](/api-reference/authentication/get-access-token).
    apiKeyAuth:
      type: apiKey
      in: header
      name: x-api-key
      description: API key issued by Kira.

````