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

# Handles `POST /v1/verify/face-match`.

> # Errors

Returns `400` for undecodable image payloads, `422` when an image cannot
be evaluated, and `503` when evidence or verification storage is
unavailable. A repeated `Idempotency-Key` returns `200` with the original
verification rather than matching the faces again; see [`crate::idempotency`].



## OpenAPI

````yaml /openapi.json post /v1/verify/face-match
openapi: 3.1.0
info:
  title: Esectra API
  description: >-
    Transaction screening, identity verification, and wallet risk.


    Every create route accepts `Idempotency-Key`; replaying one returns the
    original record with `200` where the first call returned `201`. `POST
    /v1/transactions` requires the header, because a duplicated transaction is a
    duplicated financial record.
  license:
    name: proprietary
    identifier: proprietary
  version: 0.1.0
servers:
  - url: https://qa.esectra.com
    description: Esectra QA Documentation
security: []
paths:
  /v1/verify/face-match:
    post:
      tags:
        - Verifications
      summary: Handles `POST /v1/verify/face-match`.
      description: >-
        # Errors


        Returns `400` for undecodable image payloads, `422` when an image cannot

        be evaluated, and `503` when evidence or verification storage is

        unavailable. A repeated `Idempotency-Key` returns `200` with the
        original

        verification rather than matching the faces again; see
        [`crate::idempotency`].
      operationId: face_match_handler
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/FaceMatchRequestBody'
        required: true
      responses:
        '200':
          description: A replayed Idempotency-Key; the original verification
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/FaceMatchResponseBody'
        '201':
          description: Compared and decided
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/FaceMatchResponseBody'
        '400':
          description: An image could not be decoded
        '401':
          description: No usable credentials
        '403':
          description: The caller does not hold VERIFICATIONS_SUBMIT
        '409':
          description: >-
            The Idempotency-Key is held by a request still running, or was used
            for different data
        '422':
          description: An image could not be evaluated
        '503':
          description: A backing store could not be reached
      security:
        - api_key: []
        - session_cookie: []
components:
  schemas:
    FaceMatchRequestBody:
      type: object
      description: >-
        Face-match verification request body.


        There is deliberately no `tenant_id` field. It used to be here, and the

        handler trusted it: any caller could name any tenant, and the route

        required no credentials at all, so biometrics could be submitted and

        evidence written against somebody else's account. The tenant now comes
        from

        the presented credentials like every other `/v1` route, which is the
        only

        place it can come from and still mean anything.
      required:
        - subject_id
        - reference_image_base64
        - candidate_image_base64
      properties:
        candidate_image_base64:
          type: string
          description: Base64-encoded candidate image (for example, a live selfie).
        reference_image_base64:
          type: string
          description: Base64-encoded reference image (for example, an ID document photo).
        subject_id:
          type: string
          description: Subject (platform user) being verified.
    FaceMatchResponseBody:
      type: object
      description: Face-match verification response body.
      required:
        - verification_id
        - decision_id
        - decision
        - risk_level
        - review_status
        - reasons
        - evidence
      properties:
        decision:
          $ref: '#/components/schemas/Decision'
          description: Decision outcome.
        decision_id:
          type: string
          description: Decision record identifier.
        evidence:
          type: array
          items:
            $ref: '#/components/schemas/EvidenceRef'
          description: References to retained evidence.
        reasons:
          type: array
          items:
            $ref: '#/components/schemas/DecisionReason'
          description: Explanation reasons.
        review_case_id:
          type:
            - string
            - 'null'
          description: Manual-review case, when the decision is borderline.
        review_status:
          $ref: '#/components/schemas/ReviewStatus'
          description: Review lifecycle state.
        risk_level:
          $ref: '#/components/schemas/RiskLevel'
          description: Explainable risk level.
        verification_id:
          type: string
          description: Verification attempt identifier.
    Decision:
      type: string
      description: Decision emitted by an automated or human-assisted workflow.
      enum:
        - ALLOW
        - WARN
        - BLOCK
        - HOLD
        - REVIEW_REQUIRED
        - FLAG
        - BLOCK_RECOMMENDED
        - SUSPEND
        - END_STREAM
    EvidenceRef:
      type: object
      description: >-
        Reference to retained evidence without embedding raw evidence in
        decisions.
      required:
        - id
        - kind
        - location
        - retention_policy
      properties:
        id:
          type: string
          description: Internal evidence identifier.
        kind:
          $ref: '#/components/schemas/EvidenceKind'
          description: Evidence type.
        location:
          type: string
          description: Storage URI or provider-specific object key.
        retention_policy:
          type: string
          description: Retention policy identifier applied to this evidence.
    DecisionReason:
      type: object
      description: Human-readable reason with a stable machine code.
      required:
        - code
        - message
      properties:
        code:
          type: string
          description: Stable reason code.
        message:
          type: string
          description: Explainable user/operator-facing message.
    ReviewStatus:
      type: string
      description: Human review lifecycle for a decision.
      enum:
        - PENDING
        - APPROVED
        - OVERTURNED
        - NOT_REQUIRED
    RiskLevel:
      type: string
      description: Explainable risk level.
      enum:
        - LOW
        - MEDIUM
        - HIGH
        - CRITICAL
    EvidenceKind:
      type: string
      description: Kind of evidence captured for a decision or case.
      enum:
        - IMAGE
        - VIDEO
        - TEXT
        - DOCUMENT
        - METADATA
  securitySchemes:
    api_key:
      type: http
      scheme: bearer
      description: >-
        A tenant API key. Acts for exactly one tenant and cannot conclude a
        case, because a conclusion records a person.
    session_cookie:
      type: apiKey
      in: cookie
      name: esectra_session
      description: >-
        A signed-in reviewer's session. httpOnly and SameSite=Lax; set by `POST
        /v1/control/sessions` and only usable once the second factor is met.

````