{
  "openapi": "3.1.0",
  "info": {
    "title": "ident-y Verification API",
    "version": "1.1.0",
    "license": {
      "name": "Proprietary",
      "identifier": "LicenseRef-Proprietary"
    },
    "description": "Synchronous identity verification API. Authenticate on your server using a Bearer API key; never expose keys in browser code. Production and sandbox keys are separate. Sandbox calls execute real verification; they are not simulated. Client per-minute and rolling 24-hour quotas are assigned with each key. Global capacity can also return 429. No automatic retries: honour Retry-After and initiate a fresh request. The public landing demo uses a separate quota (100 per 10 minutes and 1000 per rolling 24 hours per IP, shared across all checks; IPv6 grouped by /64), a shared capacity of 2000/day and two concurrent checks. Files and results are processed transiently and are not persisted by this gateway. Only request counters and short-lived challenge state are stored. Results may contain biometric and document data; handle them according to your privacy requirements. Diagnostic provider details are redacted. JPEG CMYK is converted to lossless RGB PNG without changing dimensions; converted images must fit the same file limit. Upload has a five-minute total budget; engine processing has a separate five-minute budget. Use a total client timeout of at least 620 seconds."
  },
  "externalDocs": {
    "description": "API change and notification policy",
    "url": "https://ident-y.com/api-changelog.html"
  },
  "servers": [
    {
      "url": "https://ident-y.com/api/v1",
      "description": "Production"
    },
    {
      "url": "https://sandbox.ident-y.com/api/v1",
      "description": "Sandbox — separate credentials and quotas"
    }
  ],
  "security": [
    {
      "ApiKey": []
    }
  ],
  "paths": {
    "/document-ocr": {
      "post": {
        "operationId": "extractDocument",
        "tags": [
          "Document OCR"
        ],
        "summary": "Document OCR",
        "description": "Extract fields from a single identity document image.",
        "requestBody": {
          "required": true,
          "content": {
            "multipart/form-data": {
              "schema": {
                "type": "object",
                "required": [
                  "file"
                ],
                "additionalProperties": false,
                "properties": {
                  "file": {
                    "type": "string",
                    "format": "binary",
                    "description": "Image — JPEG/PNG, maximum 30 MiB and 25 megapixels."
                  }
                }
              },
              "encoding": {
                "file": {
                  "contentType": "image/jpeg, image/png"
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Verification completed. Inspect the result to distinguish successful detection, quality failure and negative verification. HTTP 200 does not mean identity approved. Example data is illustrative.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/OCRResult"
                },
                "example": {
                  "Status": "Ok",
                  "Given Names": "ALEX",
                  "Surname": "EXAMPLE",
                  "Document Number": "SPECIMEN0001"
                }
              }
            }
          },
          "400": {
            "description": "Invalid multipart request, missing file or unknown field.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "invalid_request",
                    "message": "Invalid multipart request, missing file or unknown field."
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing, invalid or wrong-environment API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "unauthorized",
                    "message": "Missing, invalid or wrong-environment API key."
                  }
                }
              }
            }
          },
          "405": {
            "description": "Only POST is supported.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "method_not_allowed",
                    "message": "Only POST is supported."
                  }
                }
              }
            }
          },
          "408": {
            "description": "The five-minute upload budget or ingress idle budget expired. Start a fresh upload after correcting the connection.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "upload_timeout",
                    "message": "The five-minute upload budget or ingress idle budget expired. Start a fresh upload after correcting the connection."
                  }
                }
              }
            }
          },
          "413": {
            "description": "File exceeds 30 MiB, request exceeds 61 MiB or image exceeds 25 megapixels.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "invalid_image",
                    "message": "File exceeds 30 MiB, request exceeds 61 MiB or image exceeds 25 megapixels."
                  }
                }
              }
            }
          },
          "415": {
            "description": "Unsupported or invalid image; use JPEG or PNG.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "invalid_image",
                    "message": "Unsupported or invalid image; use JPEG or PNG."
                  }
                }
              }
            }
          },
          "429": {
            "description": "Client quota or service concurrency limit reached.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "rate_limit",
                    "message": "Client quota or service concurrency limit reached."
                  }
                }
              }
            },
            "headers": {
              "Retry-After": {
                "description": "Minimum seconds before a new attempt. Requests admitted to processing count toward rolling quotas, including invalid-image requests and engine failures.",
                "schema": {
                  "type": "integer",
                  "minimum": 1
                }
              }
            }
          },
          "502": {
            "description": "Verification engine unavailable or invalid result.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "upstream_unavailable",
                    "message": "Verification engine unavailable or invalid result."
                  }
                }
              }
            }
          },
          "503": {
            "description": "Quota storage unavailable; request rejected before verification.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "temporarily_unavailable",
                    "message": "Quota storage unavailable; request rejected before verification."
                  }
                }
              }
            }
          },
          "504": {
            "description": "Verification exceeded the five-minute timeout.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "verification_timeout",
                    "message": "Verification exceeded the five-minute timeout."
                  }
                }
              }
            }
          }
        },
        "x-codeSamples": [
          {
            "lang": "Shell",
            "label": "cURL",
            "source": "curl --fail-with-body --max-time 620 \\\n  -H \"Authorization: Bearer $IDENTY_API_KEY\" \\\n  -F file=@image.jpg \\\n  https://ident-y.com/api/v1/document-ocr"
          }
        ]
      }
    },
    "/document-ocr-multi-page": {
      "post": {
        "operationId": "extractDocumentSides",
        "tags": [
          "Document OCR"
        ],
        "summary": "Document OCR — two sides",
        "description": "Extract fields using front and reverse images of the same document. Both images are required.",
        "requestBody": {
          "required": true,
          "content": {
            "multipart/form-data": {
              "schema": {
                "type": "object",
                "required": [
                  "file1",
                  "file2"
                ],
                "additionalProperties": false,
                "properties": {
                  "file1": {
                    "type": "string",
                    "format": "binary",
                    "description": "Front image — JPEG/PNG, maximum 30 MiB and 25 megapixels."
                  },
                  "file2": {
                    "type": "string",
                    "format": "binary",
                    "description": "Reverse image — JPEG/PNG, maximum 30 MiB and 25 megapixels."
                  }
                }
              },
              "encoding": {
                "file1": {
                  "contentType": "image/jpeg, image/png"
                },
                "file2": {
                  "contentType": "image/jpeg, image/png"
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Verification completed. Inspect the result to distinguish successful detection, quality failure and negative verification. HTTP 200 does not mean identity approved. Example data is illustrative.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/OCRResult"
                },
                "example": {
                  "Status": "Ok",
                  "Given Names": "ALEX",
                  "Surname": "EXAMPLE",
                  "Document Number": "SPECIMEN0001"
                }
              }
            }
          },
          "400": {
            "description": "Invalid multipart request, missing file or unknown field.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "invalid_request",
                    "message": "Invalid multipart request, missing file or unknown field."
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing, invalid or wrong-environment API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "unauthorized",
                    "message": "Missing, invalid or wrong-environment API key."
                  }
                }
              }
            }
          },
          "405": {
            "description": "Only POST is supported.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "method_not_allowed",
                    "message": "Only POST is supported."
                  }
                }
              }
            }
          },
          "408": {
            "description": "The five-minute upload budget or ingress idle budget expired. Start a fresh upload after correcting the connection.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "upload_timeout",
                    "message": "The five-minute upload budget or ingress idle budget expired. Start a fresh upload after correcting the connection."
                  }
                }
              }
            }
          },
          "413": {
            "description": "File exceeds 30 MiB, request exceeds 61 MiB or image exceeds 25 megapixels.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "invalid_image",
                    "message": "File exceeds 30 MiB, request exceeds 61 MiB or image exceeds 25 megapixels."
                  }
                }
              }
            }
          },
          "415": {
            "description": "Unsupported or invalid image; use JPEG or PNG.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "invalid_image",
                    "message": "Unsupported or invalid image; use JPEG or PNG."
                  }
                }
              }
            }
          },
          "429": {
            "description": "Client quota or service concurrency limit reached.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "rate_limit",
                    "message": "Client quota or service concurrency limit reached."
                  }
                }
              }
            },
            "headers": {
              "Retry-After": {
                "description": "Minimum seconds before a new attempt. Requests admitted to processing count toward rolling quotas, including invalid-image requests and engine failures.",
                "schema": {
                  "type": "integer",
                  "minimum": 1
                }
              }
            }
          },
          "502": {
            "description": "Verification engine unavailable or invalid result.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "upstream_unavailable",
                    "message": "Verification engine unavailable or invalid result."
                  }
                }
              }
            }
          },
          "503": {
            "description": "Quota storage unavailable; request rejected before verification.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "temporarily_unavailable",
                    "message": "Quota storage unavailable; request rejected before verification."
                  }
                }
              }
            }
          },
          "504": {
            "description": "Verification exceeded the five-minute timeout.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "verification_timeout",
                    "message": "Verification exceeded the five-minute timeout."
                  }
                }
              }
            }
          }
        },
        "x-codeSamples": [
          {
            "lang": "Shell",
            "label": "cURL",
            "source": "curl --fail-with-body --max-time 620 \\\n  -H \"Authorization: Bearer $IDENTY_API_KEY\" \\\n  -F file1=@image.jpg \\\n  -F file2=@reference.jpg \\\n  https://ident-y.com/api/v1/document-ocr-multi-page"
          }
        ]
      }
    },
    "/document-liveness": {
      "post": {
        "operationId": "checkDocumentAuthenticity",
        "tags": [
          "Document authenticity"
        ],
        "summary": "Document authenticity",
        "description": "Evaluate printed copy, screen replay and portrait replacement signals. A score is not an automatic compliance or identity decision.",
        "requestBody": {
          "required": true,
          "content": {
            "multipart/form-data": {
              "schema": {
                "type": "object",
                "required": [
                  "image"
                ],
                "additionalProperties": false,
                "properties": {
                  "image": {
                    "type": "string",
                    "format": "binary",
                    "description": "Image — JPEG/PNG, maximum 30 MiB and 25 megapixels."
                  }
                }
              },
              "encoding": {
                "image": {
                  "contentType": "image/jpeg, image/png"
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Verification completed. Inspect the result to distinguish successful detection, quality failure and negative verification. HTTP 200 does not mean identity approved. Example data is illustrative.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentLivenessResult"
                },
                "example": {
                  "resultCode": "Ok",
                  "result": {
                    "status": "Ok",
                    "printedCopy": 0.95,
                    "screenReply": 0.96,
                    "portraitReplace": 0.94
                  }
                }
              }
            }
          },
          "400": {
            "description": "Invalid multipart request, missing file or unknown field.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "invalid_request",
                    "message": "Invalid multipart request, missing file or unknown field."
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing, invalid or wrong-environment API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "unauthorized",
                    "message": "Missing, invalid or wrong-environment API key."
                  }
                }
              }
            }
          },
          "405": {
            "description": "Only POST is supported.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "method_not_allowed",
                    "message": "Only POST is supported."
                  }
                }
              }
            }
          },
          "408": {
            "description": "The five-minute upload budget or ingress idle budget expired. Start a fresh upload after correcting the connection.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "upload_timeout",
                    "message": "The five-minute upload budget or ingress idle budget expired. Start a fresh upload after correcting the connection."
                  }
                }
              }
            }
          },
          "413": {
            "description": "File exceeds 30 MiB, request exceeds 61 MiB or image exceeds 25 megapixels.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "invalid_image",
                    "message": "File exceeds 30 MiB, request exceeds 61 MiB or image exceeds 25 megapixels."
                  }
                }
              }
            }
          },
          "415": {
            "description": "Unsupported or invalid image; use JPEG or PNG.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "invalid_image",
                    "message": "Unsupported or invalid image; use JPEG or PNG."
                  }
                }
              }
            }
          },
          "429": {
            "description": "Client quota or service concurrency limit reached.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "rate_limit",
                    "message": "Client quota or service concurrency limit reached."
                  }
                }
              }
            },
            "headers": {
              "Retry-After": {
                "description": "Minimum seconds before a new attempt. Requests admitted to processing count toward rolling quotas, including invalid-image requests and engine failures.",
                "schema": {
                  "type": "integer",
                  "minimum": 1
                }
              }
            }
          },
          "502": {
            "description": "Verification engine unavailable or invalid result.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "upstream_unavailable",
                    "message": "Verification engine unavailable or invalid result."
                  }
                }
              }
            }
          },
          "503": {
            "description": "Quota storage unavailable; request rejected before verification.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "temporarily_unavailable",
                    "message": "Quota storage unavailable; request rejected before verification."
                  }
                }
              }
            }
          },
          "504": {
            "description": "Verification exceeded the five-minute timeout.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "verification_timeout",
                    "message": "Verification exceeded the five-minute timeout."
                  }
                }
              }
            }
          }
        },
        "x-codeSamples": [
          {
            "lang": "Shell",
            "label": "cURL",
            "source": "curl --fail-with-body --max-time 620 \\\n  -H \"Authorization: Bearer $IDENTY_API_KEY\" \\\n  -F image=@image.jpg \\\n  https://ident-y.com/api/v1/document-liveness"
          }
        ]
      }
    },
    "/face-liveness": {
      "post": {
        "operationId": "checkFaceLiveness",
        "tags": [
          "Face liveness"
        ],
        "summary": "Face liveness",
        "description": "Evaluate passive liveness and face quality in a still image. No video or active challenge is required. No-face results can contain empty face_state and faces.",
        "requestBody": {
          "required": true,
          "content": {
            "multipart/form-data": {
              "schema": {
                "type": "object",
                "required": [
                  "file"
                ],
                "additionalProperties": false,
                "properties": {
                  "file": {
                    "type": "string",
                    "format": "binary",
                    "description": "Image — JPEG/PNG, maximum 30 MiB and 25 megapixels."
                  }
                }
              },
              "encoding": {
                "file": {
                  "contentType": "image/jpeg, image/png"
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Verification completed. Inspect the result to distinguish successful detection, quality failure and negative verification. HTTP 200 does not mean identity approved. Example data is illustrative.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FaceLivenessResult"
                },
                "example": {
                  "face_state": {
                    "result": "Real",
                    "liveness_score": 0.95
                  },
                  "faces": [
                    {
                      "liveness": 0.95,
                      "face_quality": 0.9
                    }
                  ]
                }
              }
            }
          },
          "400": {
            "description": "Invalid multipart request, missing file or unknown field.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "invalid_request",
                    "message": "Invalid multipart request, missing file or unknown field."
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing, invalid or wrong-environment API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "unauthorized",
                    "message": "Missing, invalid or wrong-environment API key."
                  }
                }
              }
            }
          },
          "405": {
            "description": "Only POST is supported.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "method_not_allowed",
                    "message": "Only POST is supported."
                  }
                }
              }
            }
          },
          "408": {
            "description": "The five-minute upload budget or ingress idle budget expired. Start a fresh upload after correcting the connection.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "upload_timeout",
                    "message": "The five-minute upload budget or ingress idle budget expired. Start a fresh upload after correcting the connection."
                  }
                }
              }
            }
          },
          "413": {
            "description": "File exceeds 30 MiB, request exceeds 61 MiB or image exceeds 25 megapixels.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "invalid_image",
                    "message": "File exceeds 30 MiB, request exceeds 61 MiB or image exceeds 25 megapixels."
                  }
                }
              }
            }
          },
          "415": {
            "description": "Unsupported or invalid image; use JPEG or PNG.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "invalid_image",
                    "message": "Unsupported or invalid image; use JPEG or PNG."
                  }
                }
              }
            }
          },
          "429": {
            "description": "Client quota or service concurrency limit reached.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "rate_limit",
                    "message": "Client quota or service concurrency limit reached."
                  }
                }
              }
            },
            "headers": {
              "Retry-After": {
                "description": "Minimum seconds before a new attempt. Requests admitted to processing count toward rolling quotas, including invalid-image requests and engine failures.",
                "schema": {
                  "type": "integer",
                  "minimum": 1
                }
              }
            }
          },
          "502": {
            "description": "Verification engine unavailable or invalid result.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "upstream_unavailable",
                    "message": "Verification engine unavailable or invalid result."
                  }
                }
              }
            }
          },
          "503": {
            "description": "Quota storage unavailable; request rejected before verification.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "temporarily_unavailable",
                    "message": "Quota storage unavailable; request rejected before verification."
                  }
                }
              }
            }
          },
          "504": {
            "description": "Verification exceeded the five-minute timeout.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "verification_timeout",
                    "message": "Verification exceeded the five-minute timeout."
                  }
                }
              }
            }
          }
        },
        "x-codeSamples": [
          {
            "lang": "Shell",
            "label": "cURL",
            "source": "curl --fail-with-body --max-time 620 \\\n  -H \"Authorization: Bearer $IDENTY_API_KEY\" \\\n  -F file=@image.jpg \\\n  https://ident-y.com/api/v1/face-liveness"
          }
        ]
      }
    },
    "/face-compare": {
      "post": {
        "operationId": "compareFaces",
        "tags": [
          "Face comparison"
        ],
        "summary": "Face comparison",
        "description": "Compare faces in two images. file1 is the selfie; file2 is the reference/document face. Apply your own similarity threshold.",
        "requestBody": {
          "required": true,
          "content": {
            "multipart/form-data": {
              "schema": {
                "type": "object",
                "required": [
                  "file1",
                  "file2"
                ],
                "additionalProperties": false,
                "properties": {
                  "file1": {
                    "type": "string",
                    "format": "binary",
                    "description": "Image — JPEG/PNG, maximum 30 MiB and 25 megapixels."
                  },
                  "file2": {
                    "type": "string",
                    "format": "binary",
                    "description": "Image — JPEG/PNG, maximum 30 MiB and 25 megapixels."
                  }
                }
              },
              "encoding": {
                "file1": {
                  "contentType": "image/jpeg, image/png"
                },
                "file2": {
                  "contentType": "image/jpeg, image/png"
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Verification completed. Inspect the result to distinguish successful detection, quality failure and negative verification. HTTP 200 does not mean identity approved. Example data is illustrative.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FaceComparisonResult"
                },
                "example": {
                  "resultCode": "Ok",
                  "results": [
                    {
                      "face1": 0,
                      "face2": 0,
                      "similarity": 0.91
                    }
                  ]
                }
              }
            }
          },
          "400": {
            "description": "Invalid multipart request, missing file or unknown field.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "invalid_request",
                    "message": "Invalid multipart request, missing file or unknown field."
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing, invalid or wrong-environment API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "unauthorized",
                    "message": "Missing, invalid or wrong-environment API key."
                  }
                }
              }
            }
          },
          "405": {
            "description": "Only POST is supported.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "method_not_allowed",
                    "message": "Only POST is supported."
                  }
                }
              }
            }
          },
          "408": {
            "description": "The five-minute upload budget or ingress idle budget expired. Start a fresh upload after correcting the connection.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "upload_timeout",
                    "message": "The five-minute upload budget or ingress idle budget expired. Start a fresh upload after correcting the connection."
                  }
                }
              }
            }
          },
          "413": {
            "description": "File exceeds 30 MiB, request exceeds 61 MiB or image exceeds 25 megapixels.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "invalid_image",
                    "message": "File exceeds 30 MiB, request exceeds 61 MiB or image exceeds 25 megapixels."
                  }
                }
              }
            }
          },
          "415": {
            "description": "Unsupported or invalid image; use JPEG or PNG.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "invalid_image",
                    "message": "Unsupported or invalid image; use JPEG or PNG."
                  }
                }
              }
            }
          },
          "429": {
            "description": "Client quota or service concurrency limit reached.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "rate_limit",
                    "message": "Client quota or service concurrency limit reached."
                  }
                }
              }
            },
            "headers": {
              "Retry-After": {
                "description": "Minimum seconds before a new attempt. Requests admitted to processing count toward rolling quotas, including invalid-image requests and engine failures.",
                "schema": {
                  "type": "integer",
                  "minimum": 1
                }
              }
            }
          },
          "502": {
            "description": "Verification engine unavailable or invalid result.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "upstream_unavailable",
                    "message": "Verification engine unavailable or invalid result."
                  }
                }
              }
            }
          },
          "503": {
            "description": "Quota storage unavailable; request rejected before verification.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "temporarily_unavailable",
                    "message": "Quota storage unavailable; request rejected before verification."
                  }
                }
              }
            }
          },
          "504": {
            "description": "Verification exceeded the five-minute timeout.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "verification_timeout",
                    "message": "Verification exceeded the five-minute timeout."
                  }
                }
              }
            }
          }
        },
        "x-codeSamples": [
          {
            "lang": "Shell",
            "label": "cURL",
            "source": "curl --fail-with-body --max-time 620 \\\n  -H \"Authorization: Bearer $IDENTY_API_KEY\" \\\n  -F file1=@image.jpg \\\n  -F file2=@reference.jpg \\\n  https://ident-y.com/api/v1/face-compare"
          }
        ]
      }
    }
  },
  "components": {
    "securitySchemes": {
      "ApiKey": {
        "type": "http",
        "scheme": "bearer",
        "description": "Server-side API key issued for the selected environment."
      }
    },
    "schemas": {
      "Error": {
        "type": "object",
        "required": [
          "error"
        ],
        "properties": {
          "error": {
            "type": "object",
            "required": [
              "code",
              "message"
            ],
            "properties": {
              "code": {
                "type": "string"
              },
              "message": {
                "type": "string"
              }
            },
            "additionalProperties": false
          }
        },
        "additionalProperties": false
      },
      "OCRResult": {
        "type": "object",
        "properties": {
          "Status": {
            "type": "string"
          },
          "Document Number": {
            "type": "string"
          },
          "Given Names": {
            "type": "string"
          },
          "Surname": {
            "type": "string"
          },
          "Full Name": {
            "type": "string"
          },
          "Date of Birth": {
            "type": "string"
          },
          "Date of Expiry": {
            "type": "string"
          },
          "Nationality": {
            "type": "string"
          },
          "Issuing State Name": {
            "type": "string"
          },
          "Sex": {
            "type": "string"
          },
          "MRZ Code": {
            "type": "string"
          },
          "MRZ Type": {
            "type": "string"
          },
          "Images": {
            "type": "object",
            "properties": {
              "Portrait": {
                "type": "string",
                "contentEncoding": "base64",
                "description": "Base64-encoded image, when detected."
              },
              "Document front side": {
                "type": "string",
                "contentEncoding": "base64",
                "description": "Base64-encoded image, when detected."
              },
              "Document back side": {
                "type": "string",
                "contentEncoding": "base64",
                "description": "Base64-encoded image, when detected."
              }
            },
            "additionalProperties": true
          },
          "Document Name": {
            "type": "string"
          },
          "MRZ": {
            "$ref": "#/components/schemas/MRZResult",
            "description": "Nested MRZ fields when available. Read MRZ Code and MRZ Type here for passport responses; other document types may expose them at the top level. Missing fields are omitted."
          },
          "Position": {
            "$ref": "#/components/schemas/ImageBounds"
          },
          "Portrait Position": {
            "$ref": "#/components/schemas/ImageBounds"
          }
        },
        "additionalProperties": true,
        "description": "Extracted fields depend on document type, country and image quality; missing fields are omitted. Status indicates processing outcome, not approval. Additional fields may be returned."
      },
      "DocumentLivenessResult": {
        "type": "object",
        "properties": {
          "resultCode": {
            "type": "string"
          },
          "result": {
            "oneOf": [
              {
                "type": "object",
                "properties": {
                  "status": {
                    "type": "string"
                  },
                  "portraitReplace": {
                    "type": "number",
                    "description": "Authenticity confidence for not having a replaced portrait. Higher supports authenticity. Evaluate resultCode and result.status first; zero scores with a quality error are not valid authenticity measurements."
                  },
                  "printedCopy": {
                    "type": "number",
                    "description": "Authenticity confidence for not being a printed copy. Higher supports authenticity. Evaluate resultCode and result.status first; zero scores with a quality error are not valid authenticity measurements."
                  },
                  "screenReply": {
                    "type": "number",
                    "description": "Authenticity confidence for not being a screen replay. Higher supports authenticity. Evaluate resultCode and result.status first; zero scores with a quality error are not valid authenticity measurements."
                  }
                },
                "additionalProperties": true
              },
              {
                "type": "string"
              }
            ]
          }
        },
        "additionalProperties": true,
        "description": "Evaluate resultCode and result.status before scores. Document cropped!, Document not found!, Too small!, Too close to camera!, Too close to border!, Multiple documents and Is Colorless! require a corrected capture, not a pass/fail decision. Keep all document edges and surrounding background visible. result may instead be an error string. HTTP 200 and resultCode Ok alone do not mean that scores are usable."
      },
      "FaceLivenessResult": {
        "type": "object",
        "properties": {
          "face_state": {
            "type": "object",
            "properties": {
              "result": {
                "type": "string"
              },
              "liveness_score": {
                "type": [
                  "number",
                  "null"
                ],
                "description": "Raw engine confidence, usually in [0, 1]. Higher supports the named positive signal. It is not an approval or a calibrated probability; apply a threshold validated for your capture flow."
              },
              "quality": {
                "type": [
                  "string",
                  "null"
                ],
                "description": "Capture quality, for example Low, Medium or High. Reject or recapture inadequate quality before applying a liveness threshold."
              },
              "eye_closed": {
                "type": [
                  "boolean",
                  "null"
                ],
                "description": "Null means not measured."
              },
              "is_occluded": {
                "type": [
                  "boolean",
                  "null"
                ],
                "description": "Null means not measured."
              },
              "is_not_front": {
                "type": [
                  "boolean",
                  "null"
                ],
                "description": "Null means not measured."
              },
              "is_small": {
                "type": [
                  "boolean",
                  "null"
                ],
                "description": "Null means not measured."
              },
              "is_boundary_face": {
                "type": [
                  "boolean",
                  "null"
                ],
                "description": "Null means not measured."
              },
              "mouth_opened": {
                "type": [
                  "boolean",
                  "null"
                ],
                "description": "Null means not measured."
              },
              "luminance": {
                "type": [
                  "string",
                  "null"
                ],
                "description": "Capture illumination, for example Dark, Normal or Light."
              }
            },
            "additionalProperties": true
          },
          "faces": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/FaceRecord"
            }
          }
        },
        "additionalProperties": true,
        "description": "Empty faces or missing/null scores mean no usable measurement. Inspect quality, occlusion, pose, crop, size and eye flags before a threshold decision. Higher liveness_score supports a live-like capture; a synthetic or replayed image may still score highly. This still-image API does not prove active camera presence."
      },
      "FaceComparisonResult": {
        "type": "object",
        "properties": {
          "resultCode": {
            "type": "string"
          },
          "faces1": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/FaceRecord"
            }
          },
          "faces2": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/FaceRecord"
            }
          },
          "results": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "face1": {
                  "type": "integer"
                },
                "face2": {
                  "type": "integer"
                },
                "similarity": {
                  "type": "number",
                  "description": "Raw engine confidence, usually in [0, 1]. Higher supports the named positive signal. It is not an approval or a calibrated probability; apply a threshold validated for your capture flow."
                }
              },
              "additionalProperties": true
            }
          }
        },
        "additionalProperties": true,
        "description": "results lists detected face pairs. Higher similarity supports the same identity, but requires a calibrated threshold. Empty results or a non-Ok resultCode are not a match. Comparing an image to itself is only a self-consistency control, not independent identity evidence."
      },
      "ImageBounds": {
        "type": "object",
        "properties": {
          "x1": {
            "type": "integer"
          },
          "y1": {
            "type": "integer"
          },
          "x2": {
            "type": "integer"
          },
          "y2": {
            "type": "integer"
          }
        },
        "additionalProperties": true
      },
      "MRZResult": {
        "type": "object",
        "properties": {
          "Document Number": {
            "type": "string"
          },
          "Document Class Code": {
            "type": "string"
          },
          "Given Names": {
            "type": "string"
          },
          "Surname": {
            "type": "string"
          },
          "Full Name": {
            "type": "string"
          },
          "Date of Birth": {
            "type": "string"
          },
          "Date of Expiry": {
            "type": "string"
          },
          "Issuing State Code": {
            "type": "string"
          },
          "Issuing State Name": {
            "type": "string"
          },
          "Nationality Code": {
            "type": "string"
          },
          "Personal Number": {
            "type": "string"
          },
          "Sex": {
            "type": "string"
          },
          "MRZ Code": {
            "type": "string"
          },
          "MRZ Type": {
            "type": "string"
          },
          "Validation": {
            "type": "integer",
            "description": "Raw engine MRZ validation indicator. This is not document authenticity or identity approval."
          }
        },
        "additionalProperties": true
      },
      "FaceRecord": {
        "type": "object",
        "properties": {
          "liveness": {
            "type": "number"
          },
          "face_quality": {
            "type": "number"
          },
          "eye_dist": {
            "type": "number"
          },
          "face_luminance": {
            "type": "number"
          },
          "face_occlusion": {
            "type": "number"
          },
          "left_eye_closed": {
            "type": "number"
          },
          "right_eye_closed": {
            "type": "number"
          },
          "mouth_opened": {
            "type": "number"
          },
          "pitch": {
            "type": "number"
          },
          "roll": {
            "type": "number"
          },
          "yaw": {
            "type": "number"
          },
          "x1": {
            "type": "number"
          },
          "x2": {
            "type": "number"
          },
          "y1": {
            "type": "number"
          },
          "y2": {
            "type": "number"
          },
          "landmark_68": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "x": {
                  "type": "number"
                },
                "y": {
                  "type": "number"
                }
              },
              "additionalProperties": true
            }
          }
        },
        "additionalProperties": true
      }
    }
  }
}
