---
openapi: 3.1.0
info:
  title: INE API
  version: 0.5.1
  description: >-
    Use /api/v3/ine and its request_id lookup route on https://ocr.ecostudios.dev. Literal OCR of
    one or both sides of a Mexican INE credential using Gemma. It does not verify authenticity, identity,
    or registry validity. v3 is the English contract: field names, warnings, and error messages are
    English; OCR values remain exactly as read, without translation. v1 and v2 retain their legacy
    contracts and share jobs and idempotency with v3. All extracted data requires review. Encrypted
    Gemma results are accessible for 23 hours after reservation, followed by hourly cleanup in the
    active database. Integrate from a backend: keep the API key secret and never send it to a browser.
    Multiple users of one company can submit concurrently with a distinct stable Idempotency-Key
    per business transaction. The current limits of two active jobs and ten new jobs per rolling
    minute apply to the API client; users, keys, and API versions do not multiply these limits. The
    default standard response remains compact. profile=extended opts into twenty literal scalar fields,
    MRZ, provenance and separate deterministic checks; it does not verify authenticity. A newly accepted
    job reserves one reading, whether both sides or one side are supplied. Completed readings and
    no_fields failures retain that unit. Persisted technical failures and expired processing reservations
    credit the unit back; historical failures keep their recorded usage. Credits are quota adjustments,
    not cash refunds or automatic retries. Credited attempts still count toward the rolling-minute
    limit. GET and same-job replay never consume an additional unit.
servers:
- url: https://ocr.ecostudios.dev
  description: Primary API origin; request paths below explicitly include /api/v3.
- url: https://ine-api.acessloop.workers.dev
  description: Fallback Worker origin with the same routes and API contracts.
security:
- ApiKey: []
paths:
  "/api/v3/ine":
    post:
      operationId: createApiV3Extraction
      summary: Read an INE using the English standard or opt-in extended contract.
      description: >-
        Send multipart images with optional mode=both|front|back and profile=standard|extended. Defaults
        are both and standard; only v3 accepts alternate modes, the extended profile and WEBP. Supply
        one stable Idempotency-Key of 8–128 allowed characters per business transaction. Reuse exactly
        the same key, image bytes, mode and profile after a disconnect. A changed option or image
        with the same key returns 409; defaults preserve cross-version idempotency. The initial POST
        waits for a result; replay of an active job returns 202. Check a known request_id before
        recovery; there is no durable queue or automatic POST retry. A newly accepted job reserves
        one reading, whether both sides or one side are supplied. Completed readings and no_fields
        failures retain that unit. Persisted technical failures and expired processing reservations
        credit the unit back; historical failures keep their recorded usage. Credits are quota adjustments,
        not cash refunds or automatic retries. Credited attempts still count toward the rolling-minute
        limit. GET and same-job replay never consume an additional unit. Rejections before reservation
        consume no unit. A manually provisioned pilot allows 20 lifetime billable readings for 14
        days: trial_expired is 403, trial_exhausted is 429. Monthly and pilot allowances do not reset
        the company limits of two active jobs and ten new accepted jobs per rolling minute. English
        response keys and messages never translate the printed values. Results require review and
        expire 23 hours after reservation. Configure INE_API_URL with the origin only. Pending status_url
        and Location use /api/v3/ine/{request_id}.
      parameters:
      - "$ref": "#/components/parameters/IdempotencyKey"
      requestBody:
        required: true
        content:
          multipart/form-data:
            schema:
              "$ref": "#/components/schemas/V3CredentialImages"
      responses:
        '200':
          "$ref": "#/components/responses/EnglishResult"
        '202':
          "$ref": "#/components/responses/ApiV3Processing"
        '400':
          "$ref": "#/components/responses/EnglishError"
        '401':
          "$ref": "#/components/responses/EnglishError"
        '409':
          "$ref": "#/components/responses/EnglishError"
        '410':
          "$ref": "#/components/responses/EnglishError"
        '413':
          "$ref": "#/components/responses/EnglishError"
        '415':
          "$ref": "#/components/responses/EnglishError"
        '422':
          "$ref": "#/components/responses/EnglishError"
        '429':
          "$ref": "#/components/responses/EnglishError"
        '502':
          "$ref": "#/components/responses/EnglishError"
        '503':
          "$ref": "#/components/responses/EnglishError"
        '504':
          "$ref": "#/components/responses/EnglishError"
        default:
          "$ref": "#/components/responses/EnglishError"
        '403':
          description: >-
            Pilot expired. error.code is trial_expired and action is contact_support. No new job
            is reserved.
          content:
            application/json:
              schema:
                "$ref": "#/components/schemas/EnglishError"
      tags:
      - API v3
  "/api/v3/ine/{request_id}":
    get:
      operationId: getApiV3Extraction
      summary: Retrieve the English result without repeating OCR or consuming another unit.
      description: >-
        Requires the owning API client’s key. A job created through v1 or v2 can be retrieved through
        v3 with English field names and unchanged OCR values. Returns 202 while processing; respect
        Retry-After and poll the relative /api/v3/ine/{request_id} URL. GET does not resume an interrupted
        job. Failed jobs return an English error and recommended action; expired Gemma results return
        410 after 23 hours. Quota or new-job admission limits do not prevent retrieval. This route
        aliases the same v3 contract and shared jobs. Pending responses use /api/v3/ine/{request_id}
        in status_url and Location. Configure clients with the origin only; do not append /api/v3
        to INE_API_URL. The examples default to https://ocr.ecostudios.dev.
      parameters:
      - "$ref": "#/components/parameters/RequestId"
      responses:
        '200':
          "$ref": "#/components/responses/EnglishResult"
        '202':
          "$ref": "#/components/responses/ApiV3Processing"
        '401':
          "$ref": "#/components/responses/EnglishError"
        '404':
          "$ref": "#/components/responses/EnglishError"
        '409':
          "$ref": "#/components/responses/EnglishError"
        '410':
          "$ref": "#/components/responses/EnglishError"
        '422':
          "$ref": "#/components/responses/EnglishError"
        '503':
          "$ref": "#/components/responses/EnglishError"
        default:
          "$ref": "#/components/responses/EnglishError"
      tags:
      - API v3
  "/v3/ine":
    post:
      operationId: createEnglishExtraction
      summary: Read an INE using the English standard or opt-in extended contract.
      description: >-
        Send multipart images with optional mode=both|front|back and profile=standard|extended. Defaults
        are both and standard; only v3 accepts alternate modes, the extended profile and WEBP. Supply
        one stable Idempotency-Key of 8–128 allowed characters per business transaction. Reuse exactly
        the same key, image bytes, mode and profile after a disconnect. A changed option or image
        with the same key returns 409; defaults preserve cross-version idempotency. The initial POST
        waits for a result; replay of an active job returns 202. Check a known request_id before
        recovery; there is no durable queue or automatic POST retry. A newly accepted job reserves
        one reading, whether both sides or one side are supplied. Completed readings and no_fields
        failures retain that unit. Persisted technical failures and expired processing reservations
        credit the unit back; historical failures keep their recorded usage. Credits are quota adjustments,
        not cash refunds or automatic retries. Credited attempts still count toward the rolling-minute
        limit. GET and same-job replay never consume an additional unit. Rejections before reservation
        consume no unit. A manually provisioned pilot allows 20 lifetime billable readings for 14
        days: trial_expired is 403, trial_exhausted is 429. Monthly and pilot allowances do not reset
        the company limits of two active jobs and ten new accepted jobs per rolling minute. English
        response keys and messages never translate the printed values. Results require review and
        expire 23 hours after reservation. Configure INE_API_URL with the origin only. Pending status_url
        and Location use /v3/ine/{request_id}.
      parameters:
      - "$ref": "#/components/parameters/IdempotencyKey"
      requestBody:
        required: true
        content:
          multipart/form-data:
            schema:
              "$ref": "#/components/schemas/V3CredentialImages"
      responses:
        '200':
          "$ref": "#/components/responses/EnglishResult"
        '202':
          "$ref": "#/components/responses/EnglishProcessing"
        '400':
          "$ref": "#/components/responses/EnglishError"
        '401':
          "$ref": "#/components/responses/EnglishError"
        '409':
          "$ref": "#/components/responses/EnglishError"
        '410':
          "$ref": "#/components/responses/EnglishError"
        '413':
          "$ref": "#/components/responses/EnglishError"
        '415':
          "$ref": "#/components/responses/EnglishError"
        '422':
          "$ref": "#/components/responses/EnglishError"
        '429':
          "$ref": "#/components/responses/EnglishError"
        '502':
          "$ref": "#/components/responses/EnglishError"
        '503':
          "$ref": "#/components/responses/EnglishError"
        '504':
          "$ref": "#/components/responses/EnglishError"
        default:
          "$ref": "#/components/responses/EnglishError"
        '403':
          description: >-
            Pilot expired. error.code is trial_expired and action is contact_support. No new job
            is reserved.
          content:
            application/json:
              schema:
                "$ref": "#/components/schemas/EnglishError"
      tags:
      - v3
  "/v3/ine/{request_id}":
    get:
      operationId: getEnglishExtraction
      summary: Retrieve the English result without repeating OCR or consuming another unit.
      description: >-
        Requires the owning API client’s key. A job created through v1 or v2 can be retrieved through
        v3 with English field names and unchanged OCR values. Returns 202 while processing; respect
        Retry-After and poll the relative /v3/ine/{request_id} URL. GET does not resume an interrupted
        job. Failed jobs return an English error and recommended action; expired Gemma results return
        410 after 23 hours. Quota or new-job admission limits do not prevent retrieval.
      parameters:
      - "$ref": "#/components/parameters/RequestId"
      responses:
        '200':
          "$ref": "#/components/responses/EnglishResult"
        '202':
          "$ref": "#/components/responses/EnglishProcessing"
        '401':
          "$ref": "#/components/responses/EnglishError"
        '404':
          "$ref": "#/components/responses/EnglishError"
        '409':
          "$ref": "#/components/responses/EnglishError"
        '410':
          "$ref": "#/components/responses/EnglishError"
        '422':
          "$ref": "#/components/responses/EnglishError"
        '503':
          "$ref": "#/components/responses/EnglishError"
        default:
          "$ref": "#/components/responses/EnglishError"
      tags:
      - v3
  "/v2/ine":
    post:
      operationId: createSimpleExtraction
      summary: Read both sides using the legacy compact contract.
      description: >-
        Supply a stable Idempotency-Key of 8–128 characters for the business transaction. The same
        API client, key, and image bytes retrieve the same job across v1, v2, and v3 without another
        inference or quota unit. The first POST waits for completion; a replay of an active job returns
        202. Different image bytes with the same key return 409. A disconnect does not establish
        failure: keep the key and bytes, check request_id when available, and never automatically
        create a replacement key. There is no durable queue or automatic retry. A newly accepted
        job reserves one reading, whether both sides or one side are supplied. Completed readings
        and no_fields failures retain that unit. Persisted technical failures and expired processing
        reservations credit the unit back; historical failures keep their recorded usage. Credits
        are quota adjustments, not cash refunds or automatic retries. Credited attempts still count
        toward the rolling-minute limit. GET and same-job replay never consume an additional unit.
        v2 preserves Spanish data-field names and its existing error messages. Values are literal
        text or null, not calibrated confidence or identity verification. Gemma results expire 23
        hours after reservation.
      parameters:
      - "$ref": "#/components/parameters/IdempotencyKey"
      requestBody:
        required: true
        content:
          multipart/form-data:
            schema:
              "$ref": "#/components/schemas/CredentialImages"
      responses:
        '200':
          "$ref": "#/components/responses/SimpleResult"
        '202':
          "$ref": "#/components/responses/Processing"
        '400':
          "$ref": "#/components/responses/SimpleError"
        '401':
          "$ref": "#/components/responses/SimpleError"
        '409':
          "$ref": "#/components/responses/SimpleError"
        '410':
          "$ref": "#/components/responses/SimpleError"
        '413':
          "$ref": "#/components/responses/SimpleError"
        '415':
          "$ref": "#/components/responses/SimpleError"
        '422':
          "$ref": "#/components/responses/SimpleError"
        '429':
          "$ref": "#/components/responses/SimpleError"
        '502':
          "$ref": "#/components/responses/SimpleError"
        '503':
          "$ref": "#/components/responses/SimpleError"
        '504':
          "$ref": "#/components/responses/SimpleError"
        default:
          "$ref": "#/components/responses/SimpleError"
      tags:
      - Legacy v2
  "/v2/ine/{request_id}":
    get:
      operationId: getSimpleExtraction
      summary: Retrieve the same job using the legacy compact contract.
      description: >-
        Requires an API key belonging to the owning client, including jobs created through another
        API version. Returns 202 while processing; respect Retry-After before polling. GET does not
        resume interrupted jobs. Failed jobs return their error and action; expired Gemma results
        return 410 after 23 hours. GET remains available when the client reaches its quota or new-job
        admission limits.
      parameters:
      - "$ref": "#/components/parameters/RequestId"
      responses:
        '200':
          "$ref": "#/components/responses/SimpleResult"
        '202':
          "$ref": "#/components/responses/Processing"
        '401':
          "$ref": "#/components/responses/SimpleError"
        '404':
          "$ref": "#/components/responses/SimpleError"
        '409':
          "$ref": "#/components/responses/SimpleError"
        '410':
          "$ref": "#/components/responses/SimpleError"
        '422':
          "$ref": "#/components/responses/SimpleError"
        '503':
          "$ref": "#/components/responses/SimpleError"
        default:
          "$ref": "#/components/responses/SimpleError"
      tags:
      - Legacy v2
  "/health":
    get:
      operationId: health
      security: []
      summary: HTTP availability; does not verify dependencies or deployed version.
      responses:
        '200':
          description: The API is responding.
          content:
            application/json:
              schema:
                type: object
                required:
                - status
                - service
                properties:
                  status:
                    type: string
                    const: ok
                  service:
                    type: string
                    const: ine-api
  "/v1/ine":
    post:
      operationId: createExtraction
      summary: Read both sides or retrieve the same job using the legacy detailed contract.
      description: >-
        The initial POST processes both sides and returns 200 on completion. Completed replays return
        200; concurrent replays return 202. Different bytes with the same key return 409. Inspection
        and preparation have a 10-second deadline per stage and side; inference has 25 seconds per
        call. Reservation occupies one monthly unit. Completed readings and no_fields retain it;
        recorded new technical failures are credited in quota. Historical failures keep their recorded
        usage. IMAGES.info() validates images before reservation; four crops and two model calls
        follow reservation. There is no automatic retry or durable queue. waitUntil allows up to
        30 seconds of continuation after disconnect. A job still starting after 60 seconds returns
        409 submission_unknown. Defaults are ten new jobs per client in a rolling 60-second window
        and two active reservations. Reservations last 90 seconds and release on completion or failure.
        These are not an SLA or guaranteed provider cancellation. Admission is checked before reading
        a new body and confirmed atomically after image validation. Pre-reservation rejections consume
        neither quota nor AI; replays and GET do not consume another unit. Admission errors rate_limited,
        concurrency_limited, and admission_changed return 429 with Retry-After; keep the same Idempotency-Key.
        Only newly reserved Gemma jobs generate anonymous operational metrics.
      parameters:
      - name: Idempotency-Key
        in: header
        required: true
        schema:
          type: string
          minLength: 8
          maxLength: 128
          pattern: "^[A-Za-z0-9._:-]{8,128}$"
      requestBody:
        required: true
        content:
          multipart/form-data:
            schema:
              type: object
              required:
              - front
              - back
              properties:
                front:
                  type: string
                  format: binary
                  description: >-
                    A static JPG/PNG image distinct from the other side, up to 5 MiB. Minimum 240
                    × 140 pixels, maximum 6000 pixels per side and 16 megapixels. APNG is rejected.
                back:
                  type: string
                  format: binary
                  description: A static JPG/PNG image distinct from the front, subject to the same
                    size and dimension limits.
      responses:
        '200':
          "$ref": "#/components/responses/Result"
        '202':
          "$ref": "#/components/responses/Pending"
        '400':
          "$ref": "#/components/responses/Error"
        '401':
          "$ref": "#/components/responses/Error"
        '409':
          "$ref": "#/components/responses/Error"
        '410':
          "$ref": "#/components/responses/Error"
        '413':
          "$ref": "#/components/responses/Error"
        '415':
          "$ref": "#/components/responses/Error"
        '422':
          "$ref": "#/components/responses/Error"
        '429':
          "$ref": "#/components/responses/Error"
        '502':
          "$ref": "#/components/responses/Error"
        '503':
          "$ref": "#/components/responses/Error"
        '504':
          "$ref": "#/components/responses/Error"
        default:
          "$ref": "#/components/responses/Error"
      tags:
      - Legacy v1
  "/v1/ine/{request_id}":
    get:
      operationId: getExtraction
      summary: Retrieve the owning client’s result without another inference or quota unit.
      description: >-
        Requires the owning client’s API key. A failed job returns 422 with its stored error code.
        Gemma results return 410 after 23 hours. GET does not resume interrupted jobs.
      parameters:
      - name: request_id
        in: path
        required: true
        schema:
          type: string
          format: uuid
      responses:
        '200':
          "$ref": "#/components/responses/Result"
        '202':
          "$ref": "#/components/responses/Pending"
        '401':
          "$ref": "#/components/responses/Error"
        '404':
          "$ref": "#/components/responses/Error"
        '409':
          "$ref": "#/components/responses/Error"
        '410':
          "$ref": "#/components/responses/Error"
        '422':
          "$ref": "#/components/responses/Error"
        '503':
          "$ref": "#/components/responses/Error"
        default:
          "$ref": "#/components/responses/Error"
      tags:
      - Legacy v1
components:
  parameters:
    IdempotencyKey:
      name: Idempotency-Key
      in: header
      required: true
      description: >-
        A stable identifier for one business transaction. Keep it with the same image bytes when
        retrying; never automatically generate another key after a timeout. In v3, retain mode and
        profile as well; changing either requires a new transaction key.
      schema:
        type: string
        minLength: 8
        maxLength: 128
        pattern: "^[A-Za-z0-9._:-]{8,128}$"
    RequestId:
      name: request_id
      in: path
      required: true
      schema:
        type: string
        format: uuid
  headers:
    RequestId:
      description: The request or retrieved job identifier, useful for status checks and support.
      schema:
        type: string
        format: uuid
  securitySchemes:
    ApiKey:
      type: apiKey
      in: header
      name: X-API-Key
  responses:
    EnglishResult:
      description: >-
        Completed standard or extended reading, selected by the original job profile. Literal values
        require review; shape and checks do not prove accuracy or authenticity. GET and replay preserve
        the saved result rather than rerunning checks at the current time.
      headers:
        X-Request-Id:
          "$ref": "#/components/headers/RequestId"
        Cache-Control:
          schema:
            type: string
            const: no-store
        Server-Timing:
          description: >-
            Only a newly reserved Gemma POST: stage durations and total ocr in milliseconds. Front
            and back calls overlap; do not sum parallel stages. Absent from GET and replay responses.
          schema:
            type: string
      content:
        application/json:
          schema:
            anyOf:
            - "$ref": "#/components/schemas/EnglishResult"
            - "$ref": "#/components/schemas/ExtendedResult"
          example:
            request_id: 00000000-0000-4000-8000-000000000001
            status: succeeded
            needs_review: true
            data:
              full_name: PERSONA DE EJEMPLO
              curp: 
              address: 
              date_of_birth: 
              validity: 
              elector_key: 
              cic: 
              ocr: 
              mrz: 
            warnings:
            - code: model_confidence_unavailable
            - code: authenticity_not_verified
            - code: missing_or_unreadable
              field: curp
            - code: missing_or_unreadable
              field: address
            - code: missing_or_unreadable
              field: date_of_birth
            - code: missing_or_unreadable
              field: validity
            - code: missing_or_unreadable
              field: elector_key
            - code: missing_or_unreadable
              field: cic
            - code: missing_or_unreadable
              field: ocr
            expires_at: '2026-09-30T00:00:00.000Z'
    EnglishProcessing:
      description: >-
        The job is processing. Poll status_url after Retry-After; this does not guarantee durable
        execution.
      headers:
        X-Request-Id:
          "$ref": "#/components/headers/RequestId"
        Retry-After:
          schema:
            type: integer
            const: 2
        Location:
          schema:
            type: string
            pattern: "^/v3/ine/[0-9a-f-]{36}$"
        Cache-Control:
          schema:
            type: string
            const: no-store
      content:
        application/json:
          schema:
            "$ref": "#/components/schemas/EnglishProcessing"
          example:
            request_id: 00000000-0000-4000-8000-000000000001
            status: processing
            status_url: "/v3/ine/00000000-0000-4000-8000-000000000001"
    EnglishError:
      description: >-
        A stable code, English explanation and recovery action. Actions are guidance, not permission
        to create another key or proof of no usage. Respect Retry-After and retain the key, bytes,
        mode and profile. check_status means retrieving the known request_id first. trial_expired
        uses 403/contact_support; trial_exhausted uses 429/check_quota. invalid_options uses 400/fix_request.
        A newly accepted job reserves one reading, whether both sides or one side are supplied. Completed
        readings and no_fields failures retain that unit. Persisted technical failures and expired
        processing reservations credit the unit back; historical failures keep their recorded usage.
        Credits are quota adjustments, not cash refunds or automatic retries. Credited attempts still
        count toward the rolling-minute limit. GET and same-job replay never consume an additional
        unit.
      headers:
        X-Request-Id:
          "$ref": "#/components/headers/RequestId"
        Cache-Control:
          schema:
            type: string
            const: no-store
        Retry-After:
          description: >-
            Seconds to wait after admission rejection; not guaranteed for monthly quota errors or
            every error.
          schema:
            type: integer
            minimum: 1
            maximum: 60
        Server-Timing:
          description: May appear on errors from an already reserved new Gemma POST.
          schema:
            type: string
      content:
        application/json:
          schema:
            "$ref": "#/components/schemas/EnglishError"
          example:
            request_id: 00000000-0000-4000-8000-000000000002
            error:
              code: concurrency_limited
              message: The company has reached its limit of active readings. Follow Retry-After.
              action: retry_later
    SimpleResult:
      description: >-
        Completed legacy compact extraction. All data requires review; keep identifiers as strings
        to preserve leading zeros. Null can indicate absence, illegibility, or conflicting values;
        inspect warnings for detected conflicts. A valid JSON shape does not demonstrate accuracy
        or authenticity.
      headers:
        X-Request-Id:
          "$ref": "#/components/headers/RequestId"
        Cache-Control:
          schema:
            type: string
            const: no-store
        Server-Timing:
          description: >-
            Only a newly reserved Gemma POST: stage durations and total ocr in milliseconds. Front
            and back calls overlap; do not sum parallel stages. Absent from GET and replay responses.
          schema:
            type: string
      content:
        application/json:
          schema:
            "$ref": "#/components/schemas/SimpleResult"
          example:
            request_id: 00000000-0000-4000-8000-000000000001
            status: succeeded
            needs_review: true
            data:
              nombre: PERSONA DE EJEMPLO
              curp: 
              domicilio: 
              fecha_nacimiento: 
              vigencia: 
              clave_elector: 
              cic: 
              ocr: 
              mrz: 
            warnings:
            - code: model_confidence_unavailable
            - code: authenticity_not_verified
            - code: missing_or_unreadable
              field: curp
            - code: missing_or_unreadable
              field: domicilio
            - code: missing_or_unreadable
              field: fecha_nacimiento
            - code: missing_or_unreadable
              field: vigencia
            - code: missing_or_unreadable
              field: clave_elector
            - code: missing_or_unreadable
              field: cic
            - code: missing_or_unreadable
              field: ocr
            expires_at: '2026-09-30T00:00:00.000Z'
    Processing:
      description: >-
        The job is processing. Poll status_url after Retry-After; this does not guarantee durable
        execution.
      headers:
        X-Request-Id:
          "$ref": "#/components/headers/RequestId"
        Retry-After:
          schema:
            type: integer
            const: 2
        Location:
          schema:
            type: string
            pattern: "^/v2/ine/[0-9a-f-]{36}$"
        Cache-Control:
          schema:
            type: string
            const: no-store
      content:
        application/json:
          schema:
            "$ref": "#/components/schemas/Processing"
          example:
            request_id: 00000000-0000-4000-8000-000000000001
            status: processing
            status_url: "/v2/ine/00000000-0000-4000-8000-000000000001"
    SimpleError:
      description: >-
        Legacy v2 error envelope. Error codes and action names are stable; existing v2 messages remain
        in their original language. The action is guidance, not permission to automatically change
        Idempotency-Key or proof of no usage. retry_later may accompany an admission 429; respect
        Retry-After and keep the same key and bytes. check_status means checking the known job; contact_support
        requires retaining request_id. A newly accepted job reserves one reading, whether both sides
        or one side are supplied. Completed readings and no_fields failures retain that unit. Persisted
        technical failures and expired processing reservations credit the unit back; historical failures
        keep their recorded usage. Credits are quota adjustments, not cash refunds or automatic retries.
        Credited attempts still count toward the rolling-minute limit. GET and same-job replay never
        consume an additional unit.
      headers:
        X-Request-Id:
          "$ref": "#/components/headers/RequestId"
        Cache-Control:
          schema:
            type: string
            const: no-store
        Retry-After:
          description: >-
            Seconds to wait after admission rejection; not guaranteed for monthly quota errors or
            every error.
          schema:
            type: integer
            minimum: 1
            maximum: 60
        Server-Timing:
          description: May appear on errors from an already reserved new Gemma POST.
          schema:
            type: string
      content:
        application/json:
          schema:
            "$ref": "#/components/schemas/SimpleError"
          example:
            request_id: 00000000-0000-4000-8000-000000000002
            error:
              code: concurrency_limited
              message: La empresa tiene el máximo de lecturas activas. Respeta Retry-After.
              action: retry_later
    Pending:
      description: >-
        The legacy job is in progress. Poll status_url after Retry-After; this does not guarantee
        durable execution.
      headers:
        Retry-After:
          schema:
            type: integer
            const: 2
        Location:
          schema:
            type: string
        Cache-Control:
          schema:
            type: string
            const: no-store
      content:
        application/json:
          schema:
            "$ref": "#/components/schemas/Pending"
    Result:
      description: >-
        Literal extracted text, including leading zeros. Null may indicate absence or illegibility;
        conflicts include candidate values. Schema compliance does not establish accuracy.
      headers:
        Cache-Control:
          schema:
            type: string
            const: no-store
        Server-Timing:
          description: >-
            Only a newly reserved Gemma POST: auth, upload, inspect, reserve, prepare, ai_front,
            ai_back, store, and total ocr in milliseconds. Do not sum parallel stages. Excludes complete
            client network time and metrics persistence; absent from GET and replay responses.
          schema:
            type: string
            example: auth;dur=10.0, prepare;dur=150.0, ai_front;dur=2000.0, ai_back;dur=2100.0, ocr;dur=2400.0
      content:
        application/json:
          schema:
            "$ref": "#/components/schemas/Result"
    Error:
      description: >-
        Legacy structured error. HTTP 400 indicates parameters; 401 API key; 404 missing job; 409
        conflict or uncertain state; 410 expiry; 413 size; 415 media type; 422 image, sides, fields,
        or failed job; 429 quota or admission; 502 provider response; 503 configuration, Images,
        database, or recovery; 504 inspection, preparation, inference, or processing-reservation
        timeout. image_too_complex requires smaller dimensions or less background. A newly accepted
        job reserves one reading, whether both sides or one side are supplied. Completed readings
        and no_fields failures retain that unit. Persisted technical failures and expired processing
        reservations credit the unit back; historical failures keep their recorded usage. Credits
        are quota adjustments, not cash refunds or automatic retries. Credited attempts still count
        toward the rolling-minute limit. GET and same-job replay never consume an additional unit.
        Admission 429 uses rate_limited with Retry-After 1–60, concurrency_limited with 2, or admission_changed
        with 1. Monthly quota_exceeded does not guarantee Retry-After.
      headers:
        Cache-Control:
          schema:
            type: string
            const: no-store
        Retry-After:
          description: >-
            Seconds before retrying the same key after admission rejection; not guaranteed for monthly
            quota errors.
          schema:
            type: integer
            minimum: 1
            maximum: 60
        Server-Timing:
          description: May appear on errors from an already reserved new Gemma POST.
          schema:
            type: string
      content:
        application/json:
          schema:
            type: object
            required:
            - error
            properties:
              request_id:
                type: string
                format: uuid
              error:
                type: object
                required:
                - code
                - message
                properties:
                  code:
                    type: string
                  message:
                    type: string
    ApiV3Processing:
      description: >-
        The job is processing. Poll status_url after Retry-After; this does not guarantee durable
        execution.
      headers:
        X-Request-Id:
          "$ref": "#/components/headers/RequestId"
        Retry-After:
          schema:
            type: integer
            const: 2
        Location:
          schema:
            type: string
            pattern: "^/api/v3/ine/[0-9a-f-]{36}$"
        Cache-Control:
          schema:
            type: string
            const: no-store
      content:
        application/json:
          schema:
            "$ref": "#/components/schemas/ApiV3Processing"
          example:
            request_id: 00000000-0000-4000-8000-000000000001
            status: processing
            status_url: "/api/v3/ine/00000000-0000-4000-8000-000000000001"
  schemas:
    EnglishResult:
      type: object
      required:
      - request_id
      - status
      - needs_review
      - data
      - warnings
      - expires_at
      properties:
        request_id:
          type: string
          format: uuid
        status:
          type: string
          const: succeeded
        needs_review:
          type: boolean
          const: true
        data:
          type: object
          required:
          - full_name
          - curp
          - address
          - date_of_birth
          - validity
          - elector_key
          - cic
          - ocr
          - mrz
          properties:
            full_name:
              type:
              - string
              - 'null'
              description: Printed name as read; the value is not translated.
            curp:
              type:
              - string
              - 'null'
              description: Printed CURP preserved as text; missing characters are not inferred.
            address:
              type:
              - string
              - 'null'
              description: Printed address as read; the value is not translated.
            date_of_birth:
              type:
              - string
              - 'null'
              description: Printed date text, not a guaranteed ISO date.
            validity:
              type:
              - string
              - 'null'
              description: Literal printed year or year range, such as 2035 or 2025-2035; not a registry-validity
                check.
            elector_key:
              type:
              - string
              - 'null'
              description: Printed voter identifier preserved as text, including leading zeros.
            cic:
              type:
              - string
              - 'null'
              description: Printed CIC preserved as text, including leading zeros.
            ocr:
              type:
              - string
              - 'null'
              description: Printed OCR identifier preserved as text, including leading zeros.
            mrz:
              description: Three literal lines; does not derive fields or certify check digits.
              anyOf:
              - type: 'null'
              - type: array
                minItems: 3
                maxItems: 3
                items:
                  type: string
          description: >-
            English field names with unchanged OCR values. Spanish names, addresses, punctuation,
            and printed date formats are preserved.
        warnings:
          type: array
          items:
            type: object
            required:
            - code
            properties:
              code:
                type: string
              field:
                type: string
                description: When present, refers to an English data-field name.
                enum:
                - full_name
                - curp
                - address
                - date_of_birth
                - validity
                - elector_key
                - cic
                - ocr
                - mrz
        expires_at:
          type:
          - string
          - 'null'
          format: date-time
          description: >-
            For Gemma, access expires 23 hours after reservation; this is not physical deletion from
            backups. May be null for historical Azure jobs.
    EnglishProcessing:
      type: object
      required:
      - request_id
      - status
      - status_url
      properties:
        request_id:
          type: string
          format: uuid
        status:
          type: string
          const: processing
        status_url:
          type: string
          pattern: "^/v3/ine/[0-9a-f-]{36}$"
    EnglishError:
      type: object
      required:
      - request_id
      - error
      properties:
        request_id:
          type: string
          format: uuid
        error:
          type: object
          required:
          - code
          - message
          - action
          properties:
            code:
              type: string
            message:
              type: string
              description: An English explanation for the API integrator.
            action:
              type: string
              enum:
              - fix_request
              - check_api_key
              - replace_images
              - retry_later
              - check_quota
              - check_status
              - contact_support
    CredentialImages:
      type: object
      required:
      - front
      - back
      properties:
        front:
          type: string
          format: binary
          description: >-
            A static JPG/PNG image distinct from the other side, up to 5 MiB. Minimum 240 × 140 pixels,
            maximum 6000 pixels per side and 16 megapixels. APNG is rejected.
        back:
          type: string
          format: binary
          description: A static JPG/PNG image distinct from the front, subject to the same size and
            dimension limits.
    Processing:
      type: object
      required:
      - request_id
      - status
      - status_url
      properties:
        request_id:
          type: string
          format: uuid
        status:
          type: string
          const: processing
        status_url:
          type: string
          pattern: "^/v2/ine/[0-9a-f-]{36}$"
    SimpleResult:
      type: object
      required:
      - request_id
      - status
      - needs_review
      - data
      - warnings
      - expires_at
      properties:
        request_id:
          type: string
          format: uuid
        status:
          type: string
          const: succeeded
        needs_review:
          type: boolean
          const: true
        data:
          type: object
          required:
          - nombre
          - curp
          - domicilio
          - fecha_nacimiento
          - vigencia
          - clave_elector
          - cic
          - ocr
          - mrz
          properties:
            nombre:
              type:
              - string
              - 'null'
            curp:
              type:
              - string
              - 'null'
            domicilio:
              type:
              - string
              - 'null'
            fecha_nacimiento:
              type:
              - string
              - 'null'
            vigencia:
              type:
              - string
              - 'null'
            clave_elector:
              type:
              - string
              - 'null'
            cic:
              type:
              - string
              - 'null'
            ocr:
              type:
              - string
              - 'null'
            mrz:
              description: Three literal lines; does not derive fields or certify check digits.
              anyOf:
              - type: 'null'
              - type: array
                minItems: 3
                maxItems: 3
                items:
                  type: string
        warnings:
          type: array
          items:
            type: object
            required:
            - code
            properties:
              code:
                type: string
              field:
                type: string
        expires_at:
          type:
          - string
          - 'null'
          format: date-time
          description: >-
            For Gemma, access expires 23 hours after reservation; this is not physical deletion from
            backups. May be null for historical Azure jobs.
    SimpleError:
      type: object
      required:
      - request_id
      - error
      properties:
        request_id:
          type: string
          format: uuid
        error:
          type: object
          required:
          - code
          - message
          - action
          properties:
            code:
              type: string
            message:
              type: string
            action:
              type: string
              enum:
              - fix_request
              - check_api_key
              - replace_images
              - retry_later
              - check_quota
              - check_status
              - contact_support
    Pending:
      type: object
      required:
      - request_id
      - status
      - status_url
      properties:
        request_id:
          type: string
          format: uuid
        status:
          type: string
          enum:
          - starting
          - pending
        status_url:
          type: string
    Result:
      type: object
      required:
      - request_id
      - status
      - provider
      - needs_review
      - fields
      - mrz
      - warnings
      - expires_at
      properties:
        request_id:
          type: string
          format: uuid
        status:
          type: string
          const: succeeded
        provider:
          type: string
          const: gemma
        needs_review:
          type: boolean
          const: true
        fields:
          type: object
          required:
          - nombre
          - curp
          - domicilio
          - fecha_nacimiento
          - vigencia
          - clave_elector
          - cic
          - ocr
          properties:
            nombre:
              "$ref": "#/components/schemas/Field"
            curp:
              "$ref": "#/components/schemas/Field"
            domicilio:
              "$ref": "#/components/schemas/Field"
            fecha_nacimiento:
              "$ref": "#/components/schemas/Field"
            vigencia:
              "$ref": "#/components/schemas/Field"
            clave_elector:
              "$ref": "#/components/schemas/Field"
            cic:
              "$ref": "#/components/schemas/Field"
            ocr:
              "$ref": "#/components/schemas/Field"
        mrz:
          type: object
          required:
          - lines
          - needs_review
          properties:
            lines:
              description: >-
                Literal text without deriving other fields; the back is preferred. Characters and
                check digits are not certified.
              anyOf:
              - type: 'null'
              - type: array
                minItems: 3
                maxItems: 3
                items:
                  type: string
            needs_review:
              type: boolean
              const: true
        warnings:
          type: array
          items:
            type: string
            enum:
            - model_confidence_unavailable
            - authenticity_not_verified
            - front_contains_mrz_check_sides
            - mrz_requires_review
            - conflicting_mrz
        expires_at:
          type: string
          format: date-time
          description: Access expires 23 hours after reservation. This is not physical deletion from
            backups.
    Field:
      type: object
      required:
      - value
      - confidence
      - needs_review
      - review_reasons
      properties:
        value:
          type:
          - string
          - 'null'
        confidence:
          type: 'null'
          description: No calibrated model confidence is available.
        needs_review:
          type: boolean
          const: true
        review_reasons:
          type: array
          minItems: 1
          items:
            type: string
            enum:
            - model_confidence_unavailable
            - missing_or_unreadable
            - conflicting_values
            - unexpected_format
        side:
          type:
          - string
          - 'null'
          enum:
          - front
          - back
          - 
        conflict:
          type: boolean
        candidates:
          type: array
          items:
            type: object
            required:
            - value
            - confidence
            - side
            properties:
              value:
                type: string
              confidence:
                type: 'null'
              side:
                type: string
                enum:
                - front
                - back
    ApiV3Processing:
      type: object
      required:
      - request_id
      - status
      - status_url
      properties:
        request_id:
          type: string
          format: uuid
        status:
          type: string
          const: processing
        status_url:
          type: string
          pattern: "^/api/v3/ine/[0-9a-f-]{36}$"
    V3CredentialImages:
      type: object
      description: >-
        Default: send both sides with profile standard. A single-side mode still reserves one reading.
        Include exactly the files required by mode. Changing mode, profile or bytes requires a new
        Idempotency-Key. Extended is opt-in and not yet validated on representative customer photographs.
      properties:
        front:
          type: string
          format: binary
          description: >-
            A static JPG, PNG or WEBP image, 32 bytes to 5 MiB. Minimum 240 × 140 pixels; maximum
            6000 pixels per side and 16 megapixels. Animated images are rejected. With both sides,
            images must differ. Preparation may reject a crop over 2 MiB after reservation.
        back:
          type: string
          format: binary
          description: >-
            A static JPG, PNG or WEBP image, 32 bytes to 5 MiB. Minimum 240 × 140 pixels; maximum
            6000 pixels per side and 16 megapixels. Animated images are rejected. With both sides,
            images must differ. Preparation may reject a crop over 2 MiB after reservation.
        mode:
          type: string
          enum:
          - both
          - front
          - back
          default: both
        profile:
          type: string
          enum:
          - standard
          - extended
          default: standard
      oneOf:
      - required:
        - front
        - back
        properties:
          mode:
            const: both
      - required:
        - mode
        - front
        properties:
          mode:
            const: front
        not:
          required:
          - back
      - required:
        - mode
        - back
        properties:
          mode:
            const: back
        not:
          required:
          - front
      additionalProperties: false
    DeterministicCheck:
      type: object
      additionalProperties: false
      required:
      - status
      - reason
      properties:
        status:
          type: string
          enum:
          - pass
          - fail
          - not_checked
        reason:
          type: string
      description: >-
        A format, checksum or consistency check; pass does not establish identity, authenticity or
        registry validity.
    CurpBirthDateCheck:
      type: object
      additionalProperties: false
      required:
      - status
      - reason
      properties:
        status:
          type: string
          enum:
          - pass
          - fail
          - not_checked
        reason:
          type: string
        normalized:
          type: 'null'
        century_inferred:
          type: boolean
          const: false
    PrintedDateCheck:
      type: object
      additionalProperties: false
      required:
      - status
      - reason
      - normalized
      - granularity
      properties:
        status:
          type: string
          enum:
          - pass
          - fail
          - not_checked
        reason:
          type: string
        normalized:
          type:
          - string
          - 'null'
          format: date
        granularity:
          enum:
          - day
          - 
      description: Only an unambiguous supported calendar date is normalized. The literal data field
        is unchanged.
    ValidityChecks:
      type: object
      additionalProperties: false
      required:
      - format
      - comparison
      - normalized
      - registry
      properties:
        format:
          "$ref": "#/components/schemas/DeterministicCheck"
        comparison:
          "$ref": "#/components/schemas/DeterministicCheck"
        normalized:
          anyOf:
          - type: 'null'
          - type: object
            additionalProperties: false
            required:
            - granularity
            - start_year
            - end_year
            - expires_on
            properties:
              granularity:
                type: string
                enum:
                - year
                - day
              start_year:
                type:
                - integer
                - 'null'
              end_year:
                type:
                - integer
                - 'null'
              expires_on:
                type:
                - string
                - 'null'
                format: date
        registry:
          "$ref": "#/components/schemas/DeterministicCheck"
      description: >-
        Compares printed year bounds or an unambiguous date at extraction time. No official registry
        lookup is performed.
    ParsedMrz:
      type: object
      additionalProperties: false
      required:
      - document_code
      - issuing_state
      - document_number
      - date_of_birth_yymmdd
      - date_of_expiry_yymmdd
      - sex
      - nationality
      - primary_identifier
      - secondary_identifier
      - names_may_be_truncated
      - century_inferred
      properties:
        document_code:
          type: string
        issuing_state:
          type: string
        document_number:
          type:
          - string
          - 'null'
        date_of_birth_yymmdd:
          type: string
        date_of_expiry_yymmdd:
          type: string
        sex:
          type: string
        nationality:
          type: string
        primary_identifier:
          type: string
        secondary_identifier:
          type:
          - string
          - 'null'
        names_may_be_truncated:
          type: boolean
        century_inferred:
          type: boolean
          const: false
      description: >-
        Parsed only for a supported three-line TD1 layout. Encoded dates retain two-digit years;
        parsed values never fill printed OCR fields.
    MrzChecks:
      type: object
      additionalProperties: false
      required:
      - format
      - document_number
      - birth_date
      - expiry_date
      - composite
      - parsed
      properties:
        format:
          "$ref": "#/components/schemas/DeterministicCheck"
        document_number:
          "$ref": "#/components/schemas/DeterministicCheck"
        birth_date:
          "$ref": "#/components/schemas/DeterministicCheck"
        expiry_date:
          "$ref": "#/components/schemas/DeterministicCheck"
        composite:
          "$ref": "#/components/schemas/DeterministicCheck"
        parsed:
          anyOf:
          - type: 'null'
          - "$ref": "#/components/schemas/ParsedMrz"
    PairCheck:
      type: object
      additionalProperties: false
      required:
      - status
      - reason
      - comparisons
      properties:
        status:
          type: string
          enum:
          - pass
          - fail
          - not_checked
        reason:
          type: string
        comparisons:
          type: array
          items:
            type: object
            additionalProperties: false
            required:
            - field
            - status
            - basis
            properties:
              field:
                type: string
                enum:
                - curp
                - elector_key
                - cic
                - ocr
                - full_name
                - date_of_birth
              status:
                type: string
                enum:
                - pass
                - fail
              basis:
                type: string
                enum:
                - printed_text
                - printed_dates
                - printed_date_vs_mrz_yymmdd
      description: >-
        Compares available observations; it does not establish that the faces belong to one person.
        Single-side readings return not_checked.
    ExtendedChecks:
      type: object
      additionalProperties: false
      required:
      - curp
      - elector_key
      - date_of_birth
      - validity
      - mrz
      - pair
      - authenticity
      properties:
        curp:
          type: object
          additionalProperties: false
          required:
          - format
          - check_digit
          - birth_date
          - registry
          properties:
            format:
              "$ref": "#/components/schemas/DeterministicCheck"
            check_digit:
              "$ref": "#/components/schemas/DeterministicCheck"
            birth_date:
              "$ref": "#/components/schemas/CurpBirthDateCheck"
            registry:
              "$ref": "#/components/schemas/DeterministicCheck"
        elector_key:
          "$ref": "#/components/schemas/DeterministicCheck"
        date_of_birth:
          "$ref": "#/components/schemas/PrintedDateCheck"
        validity:
          "$ref": "#/components/schemas/ValidityChecks"
        mrz:
          "$ref": "#/components/schemas/MrzChecks"
        pair:
          "$ref": "#/components/schemas/PairCheck"
        authenticity:
          type: object
          additionalProperties: false
          required:
          - status
          - reason
          properties:
            status:
              type: string
              const: not_checked
            reason:
              type: string
              const: not_an_authenticity_verification
    ImageQualityObservation:
      type: object
      additionalProperties: false
      required:
      - assessment
      - observed_side
      - observed_document_type
      - blur
      - glare
      - cropped
      - rotation
      properties:
        assessment:
          type: string
          const: unvalidated_model_observation
        observed_side:
          type: string
          enum:
          - front
          - back
          - unknown
        observed_document_type:
          type: string
          enum:
          - ine
          - other
          - unknown
        blur:
          type: string
          enum:
          - suspected
          - not_observed
          - unknown
        glare:
          type: string
          enum:
          - suspected
          - not_observed
          - unknown
        cropped:
          type: string
          enum:
          - suspected
          - not_observed
          - unknown
        rotation:
          type: string
          enum:
          - suspected
          - not_observed
          - unknown
      description: >-
        Uncalibrated model observations of the full image, not confidence scores, deterministic quality
        measurements or authenticity checks.
    ExtendedResult:
      type: object
      additionalProperties: false
      required:
      - request_id
      - status
      - profile
      - needs_review
      - data
      - sources
      - checks
      - quality
      - warnings
      - expires_at
      properties:
        request_id:
          type: string
          format: uuid
        status:
          type: string
          const: succeeded
        profile:
          type: string
          const: extended
        needs_review:
          type: boolean
          const: true
        data:
          type: object
          additionalProperties: false
          required:
          - full_name
          - curp
          - address
          - date_of_birth
          - validity
          - elector_key
          - cic
          - ocr
          - given_names
          - paternal_surname
          - maternal_surname
          - sex
          - section
          - registration_year
          - issue_year
          - street
          - neighborhood
          - municipality
          - state
          - postal_code
          - mrz
          properties:
            full_name:
              type:
              - string
              - 'null'
            curp:
              type:
              - string
              - 'null'
            address:
              type:
              - string
              - 'null'
            date_of_birth:
              type:
              - string
              - 'null'
            validity:
              type:
              - string
              - 'null'
            elector_key:
              type:
              - string
              - 'null'
            cic:
              type:
              - string
              - 'null'
            ocr:
              type:
              - string
              - 'null'
            given_names:
              type:
              - string
              - 'null'
            paternal_surname:
              type:
              - string
              - 'null'
            maternal_surname:
              type:
              - string
              - 'null'
            sex:
              type:
              - string
              - 'null'
            section:
              type:
              - string
              - 'null'
            registration_year:
              type:
              - string
              - 'null'
            issue_year:
              type:
              - string
              - 'null'
            street:
              type:
              - string
              - 'null'
            neighborhood:
              type:
              - string
              - 'null'
            municipality:
              type:
              - string
              - 'null'
            state:
              type:
              - string
              - 'null'
            postal_code:
              type:
              - string
              - 'null'
            mrz:
              anyOf:
              - type: 'null'
              - type: array
                minItems: 3
                maxItems: 3
                items:
                  type: string
            address_parts:
              "$ref": "#/components/schemas/AddressParts"
              description: >-
                Added to new extended readings and saved at creation. Optional only because older
                cached readings can omit it; GET and replay do not reparse saved results.
          description: >-
            Twenty literal scalar fields plus three literal MRZ lines or null. Values are not translated,
            repaired, enriched or filled from encoded data. Conflicting observations produce null.
        sources:
          type: object
          additionalProperties: false
          required:
          - full_name
          - curp
          - address
          - date_of_birth
          - validity
          - elector_key
          - cic
          - ocr
          - given_names
          - paternal_surname
          - maternal_surname
          - sex
          - section
          - registration_year
          - issue_year
          - street
          - neighborhood
          - municipality
          - state
          - postal_code
          - mrz
          properties:
            full_name:
              type: array
              items:
                type: object
                additionalProperties: false
                required:
                - side
                - region
                properties:
                  side:
                    type: string
                    enum:
                    - front
                    - back
                  region:
                    type: string
                    enum:
                    - printed_label
                    - name_block
                    - address_block
            curp:
              type: array
              items:
                type: object
                additionalProperties: false
                required:
                - side
                - region
                properties:
                  side:
                    type: string
                    enum:
                    - front
                    - back
                  region:
                    type: string
                    enum:
                    - printed_label
                    - name_block
                    - address_block
            address:
              type: array
              items:
                type: object
                additionalProperties: false
                required:
                - side
                - region
                properties:
                  side:
                    type: string
                    enum:
                    - front
                    - back
                  region:
                    type: string
                    enum:
                    - printed_label
                    - name_block
                    - address_block
            date_of_birth:
              type: array
              items:
                type: object
                additionalProperties: false
                required:
                - side
                - region
                properties:
                  side:
                    type: string
                    enum:
                    - front
                    - back
                  region:
                    type: string
                    enum:
                    - printed_label
                    - name_block
                    - address_block
            validity:
              type: array
              items:
                type: object
                additionalProperties: false
                required:
                - side
                - region
                properties:
                  side:
                    type: string
                    enum:
                    - front
                    - back
                  region:
                    type: string
                    enum:
                    - printed_label
                    - name_block
                    - address_block
            elector_key:
              type: array
              items:
                type: object
                additionalProperties: false
                required:
                - side
                - region
                properties:
                  side:
                    type: string
                    enum:
                    - front
                    - back
                  region:
                    type: string
                    enum:
                    - printed_label
                    - name_block
                    - address_block
            cic:
              type: array
              items:
                type: object
                additionalProperties: false
                required:
                - side
                - region
                properties:
                  side:
                    type: string
                    enum:
                    - front
                    - back
                  region:
                    type: string
                    enum:
                    - printed_label
                    - name_block
                    - address_block
            ocr:
              type: array
              items:
                type: object
                additionalProperties: false
                required:
                - side
                - region
                properties:
                  side:
                    type: string
                    enum:
                    - front
                    - back
                  region:
                    type: string
                    enum:
                    - printed_label
                    - name_block
                    - address_block
            given_names:
              type: array
              items:
                type: object
                additionalProperties: false
                required:
                - side
                - region
                properties:
                  side:
                    type: string
                    enum:
                    - front
                    - back
                  region:
                    type: string
                    enum:
                    - printed_label
                    - name_block
                    - address_block
            paternal_surname:
              type: array
              items:
                type: object
                additionalProperties: false
                required:
                - side
                - region
                properties:
                  side:
                    type: string
                    enum:
                    - front
                    - back
                  region:
                    type: string
                    enum:
                    - printed_label
                    - name_block
                    - address_block
            maternal_surname:
              type: array
              items:
                type: object
                additionalProperties: false
                required:
                - side
                - region
                properties:
                  side:
                    type: string
                    enum:
                    - front
                    - back
                  region:
                    type: string
                    enum:
                    - printed_label
                    - name_block
                    - address_block
            sex:
              type: array
              items:
                type: object
                additionalProperties: false
                required:
                - side
                - region
                properties:
                  side:
                    type: string
                    enum:
                    - front
                    - back
                  region:
                    type: string
                    enum:
                    - printed_label
                    - name_block
                    - address_block
            section:
              type: array
              items:
                type: object
                additionalProperties: false
                required:
                - side
                - region
                properties:
                  side:
                    type: string
                    enum:
                    - front
                    - back
                  region:
                    type: string
                    enum:
                    - printed_label
                    - name_block
                    - address_block
            registration_year:
              type: array
              items:
                type: object
                additionalProperties: false
                required:
                - side
                - region
                properties:
                  side:
                    type: string
                    enum:
                    - front
                    - back
                  region:
                    type: string
                    enum:
                    - printed_label
                    - name_block
                    - address_block
            issue_year:
              type: array
              items:
                type: object
                additionalProperties: false
                required:
                - side
                - region
                properties:
                  side:
                    type: string
                    enum:
                    - front
                    - back
                  region:
                    type: string
                    enum:
                    - printed_label
                    - name_block
                    - address_block
            street:
              type: array
              items:
                type: object
                additionalProperties: false
                required:
                - side
                - region
                properties:
                  side:
                    type: string
                    enum:
                    - front
                    - back
                  region:
                    type: string
                    enum:
                    - printed_label
                    - name_block
                    - address_block
            neighborhood:
              type: array
              items:
                type: object
                additionalProperties: false
                required:
                - side
                - region
                properties:
                  side:
                    type: string
                    enum:
                    - front
                    - back
                  region:
                    type: string
                    enum:
                    - printed_label
                    - name_block
                    - address_block
            municipality:
              type: array
              items:
                type: object
                additionalProperties: false
                required:
                - side
                - region
                properties:
                  side:
                    type: string
                    enum:
                    - front
                    - back
                  region:
                    type: string
                    enum:
                    - printed_label
                    - name_block
                    - address_block
            state:
              type: array
              items:
                type: object
                additionalProperties: false
                required:
                - side
                - region
                properties:
                  side:
                    type: string
                    enum:
                    - front
                    - back
                  region:
                    type: string
                    enum:
                    - printed_label
                    - name_block
                    - address_block
            postal_code:
              type: array
              items:
                type: object
                additionalProperties: false
                required:
                - side
                - region
                properties:
                  side:
                    type: string
                    enum:
                    - front
                    - back
                  region:
                    type: string
                    enum:
                    - printed_label
                    - name_block
                    - address_block
            mrz:
              type: array
              items:
                type: object
                additionalProperties: false
                required:
                - side
                - region
                properties:
                  side:
                    type: string
                    enum:
                    - front
                    - back
                  region:
                    type: string
                    const: mrz
            address_parts:
              "$ref": "#/components/schemas/AddressPartSources"
              description: Saved with the new address_parts object. Older cached extended readings
                may omit it.
          description: >-
            Regions reported by the model, without coordinates or confidence. Conflicting fields
            can be null while sources still list both observations.
        checks:
          "$ref": "#/components/schemas/ExtendedChecks"
        quality:
          type: object
          additionalProperties: false
          required:
          - front
          - back
          properties:
            front:
              anyOf:
              - type: 'null'
              - "$ref": "#/components/schemas/ImageQualityObservation"
            back:
              anyOf:
              - type: 'null'
              - "$ref": "#/components/schemas/ImageQualityObservation"
          description: The unsupplied side is null in single-side mode.
        warnings:
          type: array
          items:
            type: object
            additionalProperties: false
            required:
            - code
            properties:
              code:
                type: string
                description: >-
                  Includes address_parsing_unvalidated globally, and address_component_ambiguous
                  or address_source_conflict with an address_parts.KEY field. Handle future codes
                  gracefully.
              field:
                type: string
                enum:
                - full_name
                - curp
                - address
                - date_of_birth
                - validity
                - elector_key
                - cic
                - ocr
                - given_names
                - paternal_surname
                - maternal_surname
                - sex
                - section
                - registration_year
                - issue_year
                - street
                - neighborhood
                - municipality
                - state
                - postal_code
                - mrz
                - front
                - back
                - address_parts.type
                - address_parts.street
                - address_parts.number
                - address_parts.unit
                - address_parts.building
                - address_parts.block
                - address_parts.lot
                - address_parts.neighborhood
                - address_parts.locality
                - address_parts.municipality
                - address_parts.state
                - address_parts.zip
        expires_at:
          type: string
          format: date-time
      description: >-
        Opt-in extended profile. Its twenty fields and quality observations are not validated accuracy
        claims. Always review the result. The standard profile and legacy response shapes are unchanged.
    AddressParts:
      type: object
      additionalProperties: false
      required: &1
      - type
      - street
      - number
      - unit
      - building
      - block
      - lot
      - neighborhood
      - locality
      - municipality
      - state
      - zip
      properties:
        type:
          type:
          - string
          - 'null'
          description: Printed street type; accepted abbreviations remain literal.
        street:
          type:
          - string
          - 'null'
          description: Street name separated from supported labels. The original data.street remains
            the full line.
        number:
          type:
          - string
          - 'null'
          description: Explicit exterior number, preserved as text including leading zeros.
        unit:
          type:
          - string
          - 'null'
          description: Explicit interior or unit identifier, preserved as text.
        building:
          type:
          - string
          - 'null'
          description: Explicit building identifier.
        block:
          type:
          - string
          - 'null'
          description: Explicit block or manzana identifier.
        lot:
          type:
          - string
          - 'null'
          description: Explicit lot identifier.
        neighborhood:
          type:
          - string
          - 'null'
          description: Supported neighborhood or colonia text.
        locality:
          type:
          - string
          - 'null'
          description: Explicit locality; not automatically the municipality.
        municipality:
          type:
          - string
          - 'null'
          description: Supported municipality or alcaldia text.
        state:
          type:
          - string
          - 'null'
          description: Supported state text without expansion or geographic lookup.
        zip:
          type:
          - string
          - 'null'
          description: Supported postal code preserved as text, including leading zeros.
      description: >-
        Conservative deterministic parsing of the original OCR values, not another model extraction.
        All twelve keys are present when this object exists. Unsupported, absent, ambiguous or conflicting
        parts are null. Populated strings have exact source spans. No enrichment, authenticity, official-address
        or delivery validation is performed.
    AddressPartSource:
      type: object
      additionalProperties: false
      required:
      - method
      - field
      - start
      - end
      properties:
        method:
          type: string
          const: parsed
        field:
          type: string
          enum:
          - street
          - address
          - neighborhood
          - municipality
          - state
          - postal_code
          description: The original OCR field under data, never a nested address_parts field.
        start:
          type: integer
          minimum: 0
          description: Zero-based UTF-16 code-unit offset, inclusive.
        end:
          type: integer
          minimum: 1
          description: >-
            UTF-16 code-unit offset, exclusive and greater than start. data[field].slice(start, end)
            equals the corresponding part.
      description: >-
        An exact span in the original OCR string. It provides text provenance, not image coordinates,
        confidence or proof of correct transcription.
    AddressPartSources:
      type: object
      additionalProperties: false
      required: *1
      properties:
        type:
          anyOf:
          - type: 'null'
          - "$ref": "#/components/schemas/AddressPartSource"
        street:
          anyOf:
          - type: 'null'
          - "$ref": "#/components/schemas/AddressPartSource"
        number:
          anyOf:
          - type: 'null'
          - "$ref": "#/components/schemas/AddressPartSource"
        unit:
          anyOf:
          - type: 'null'
          - "$ref": "#/components/schemas/AddressPartSource"
        building:
          anyOf:
          - type: 'null'
          - "$ref": "#/components/schemas/AddressPartSource"
        block:
          anyOf:
          - type: 'null'
          - "$ref": "#/components/schemas/AddressPartSource"
        lot:
          anyOf:
          - type: 'null'
          - "$ref": "#/components/schemas/AddressPartSource"
        neighborhood:
          anyOf:
          - type: 'null'
          - "$ref": "#/components/schemas/AddressPartSource"
        locality:
          anyOf:
          - type: 'null'
          - "$ref": "#/components/schemas/AddressPartSource"
        municipality:
          anyOf:
          - type: 'null'
          - "$ref": "#/components/schemas/AddressPartSource"
        state:
          anyOf:
          - type: 'null'
          - "$ref": "#/components/schemas/AddressPartSource"
        zip:
          anyOf:
          - type: 'null'
          - "$ref": "#/components/schemas/AddressPartSource"
      description: One source per address part; null exactly when the corresponding part is null.
tags:
- name: API v3
  description: Primary custom-domain routes for the English v3 contract.
- name: v3
  description: Compatibility routes for the English v3 contract.
- name: Legacy v2
  description: Supported compact contract with Spanish data-field names and legacy error messages.
- name: Legacy v1
  description: Supported detailed contract with Spanish data-field names and legacy error messages.
