openapi: 3.1.0
info:
  title: Cogneris Document AI API
  version: '2026-04-30'
  summary: Extract structured data from documents at production scale.
  description: |
    The Cogneris Document AI API turns unstructured documents — PDFs, images, scans —
    into structured JSON in seconds. The same endpoint handles 40+ document types:
    payslips, W-2s, 1040 tax returns, bank statements, invoices, IDs, contracts,
    and more.

    ## Key concepts

    - **Document** — what you upload. Cogneris accepts PDF, PNG, JPEG, TIFF, and
      multi-page TIFF up to 100MB. Documents are encrypted at rest with per-tenant
      keys (CMEK on Enterprise).
    - **Extraction** — what you get back. A structured representation of the
      document with field-level confidence scores, source-page references, and a
      link to the audit record.
    - **Audit record** — every extraction produces an immutable audit trail
      capturing the model version, prompt hash, response, and post-processor
      decisions. Available via the audit endpoint and exportable as JSON-Lines.

    ## Authentication

    All requests require an API key passed in the `Authorization` header as
    `Bearer YOUR_API_KEY`. Generate keys from the dashboard at https://cogneris.ai/app.

    Each key is scoped to a tenant; keys cannot cross tenant boundaries.

    ## Rate limits

    Default rate limit is 60 sync requests/min and 600 async requests/min per
    tenant. Enterprise customers receive higher limits negotiated per contract.
    `Retry-After` is set on 429 responses.

    ## Versioning

    The API is versioned via the date in the `info.version` field above. Breaking
    changes get a new dated version; non-breaking additions ship inline. Pin a
    version with the `cogneris-Version: YYYY-MM-DD` request header.

    ## Errors

    Errors follow [RFC 7807](https://datatracker.ietf.org/doc/html/rfc7807) Problem
    Details, with an additional `request_id` field that you can include in
    support tickets for fast triage.
  contact:
    name: Cogneris Engineering
    url: https://cogneris.ai/contact.html
    email: support@cogneris.ai
  termsOfService: https://cogneris.ai/terms.html
  license:
    name: Commercial
    url: https://cogneris.ai/terms.html

servers:
  - url: https://api.cogneris.ai/v1
    description: Production

tags:
  - name: Documents
    description: Upload documents and trigger extraction.
  - name: Extractions
    description: Retrieve and manage extraction results.
  - name: Webhooks
    description: Configure async-callback endpoints.
  - name: Audit
    description: Retrieve audit records for compliance and reproducibility.

security:
  - bearerAuth: []

paths:
  /documents:
    post:
      tags: [Documents]
      summary: Extract synchronously
      description: |
        Upload a document and receive structured extraction in the same response.
        Best for documents under 10 pages where you can wait 1-5 seconds for the
        result. For larger documents or higher throughput, use the async endpoint.
      operationId: extractDocumentSync
      requestBody:
        required: true
        content:
          multipart/form-data:
            schema:
              type: object
              required: [file, schema]
              properties:
                file:
                  type: string
                  format: binary
                  description: The document file. PDF, PNG, JPEG, TIFF supported up to 100MB.
                schema:
                  type: string
                  description: |
                    Schema identifier (e.g. `w2_2025`, `1040_2024`, `bank_statement`,
                    `invoice`, `passport`, `kyc_id`). See the dashboard for the full list.
                  example: w2_2025
                tenant_workflow:
                  type: string
                  description: Optional workflow ID to apply tenant-specific validators and routing.
                  example: wf_payroll_lending_v2
      responses:
        '200':
          description: Extraction successful.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Extraction'
              example:
                extraction_id: ext_01H8YN3P9ZTVKMRAEH56X29Q4D
                document_id: doc_01H8YN3P5ZTVKMRAEH56X29Q3K
                schema: w2_2025
                fields:
                  employee_name:
                    value: Jordan T. Hall
                    confidence: 0.999
                    source_page: 1
                  ssn:
                    value: '***-**-1234'
                    confidence: 0.998
                    source_page: 1
                  wages_box_1:
                    value: 124580.00
                    confidence: 0.997
                    source_page: 1
                  federal_tax_withheld:
                    value: 22420.00
                    confidence: 0.997
                    source_page: 1
                processing_ms: 1840
                audit_record_url: /v1/audit/req_01H8YN3P9ZTVKMRAEH56X29Q4D
                created_at: '2026-04-30T14:32:18Z'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '413':
          $ref: '#/components/responses/PayloadTooLarge'
        '429':
          $ref: '#/components/responses/RateLimited'
        '500':
          $ref: '#/components/responses/InternalError'

  /documents/async:
    post:
      tags: [Documents]
      summary: Extract asynchronously
      description: |
        Upload a document and receive an extraction ID immediately. Use this for
        high-volume processing or for documents over 10 pages. The result is
        delivered to a configured webhook (see `/webhooks`) or polled via the
        `GET /extractions/{id}` endpoint.
      operationId: extractDocumentAsync
      requestBody:
        required: true
        content:
          multipart/form-data:
            schema:
              type: object
              required: [file, schema]
              properties:
                file:
                  type: string
                  format: binary
                schema:
                  type: string
                  example: claim_package
                tenant_workflow:
                  type: string
                webhook_id:
                  type: string
                  description: Optional webhook to call when extraction completes. Overrides default tenant webhook.
                  example: wh_01H8YJ4P9ZTVKMRAEH56X29Q3K
                metadata:
                  type: object
                  description: Free-form key/value metadata returned with the extraction.
                  additionalProperties:
                    type: string
                  example:
                    customer_id: cus_01H8...
                    application_id: app_01H8...
      responses:
        '202':
          description: Document accepted; extraction in progress.
          content:
            application/json:
              schema:
                type: object
                properties:
                  extraction_id:
                    type: string
                  document_id:
                    type: string
                  status:
                    type: string
                    enum: [queued, processing]
                  estimated_completion_ms:
                    type: integer
                example:
                  extraction_id: ext_01H8YN3P9ZTVKMRAEH56X29Q4D
                  document_id: doc_01H8YN3P5ZTVKMRAEH56X29Q3K
                  status: queued
                  estimated_completion_ms: 8000

  /documents/{document_id}:
    parameters:
      - $ref: '#/components/parameters/DocumentId'
    get:
      tags: [Documents]
      summary: Get document metadata
      description: Returns the document's metadata and the latest extraction status. Document content is not returned through this endpoint for privacy reasons.
      operationId: getDocument
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Document'
        '404':
          $ref: '#/components/responses/NotFound'

  /extractions/{extraction_id}:
    parameters:
      - $ref: '#/components/parameters/ExtractionId'
    get:
      tags: [Extractions]
      summary: Get an extraction
      description: |
        Retrieve an extraction by ID. Use this to poll async extractions, or to
        re-fetch a sync extraction's result later (until your retention window
        expires).
      operationId: getExtraction
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Extraction'
        '404':
          $ref: '#/components/responses/NotFound'

  /extractions/{extraction_id}/validate:
    parameters:
      - $ref: '#/components/parameters/ExtractionId'
    post:
      tags: [Extractions]
      summary: Re-validate an extraction
      description: |
        Re-run the validator chain against an existing extraction. Useful when a
        validation rule has been updated since the extraction was performed, or
        when reviewing a flagged extraction in a human-in-the-loop workflow.
      operationId: validateExtraction
      requestBody:
        required: false
        content:
          application/json:
            schema:
              type: object
              properties:
                validators:
                  type: array
                  items:
                    type: string
                  description: Optional list of validator IDs to run. Defaults to the workflow's full validator chain.
                  example: [arithmetic_check, mrz_checksum, balance_reconciliation]
      responses:
        '200':
          description: Validation re-run; updated extraction returned.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Extraction'

  /webhooks:
    post:
      tags: [Webhooks]
      summary: Create a webhook
      description: |
        Register a callback URL for async extraction completion. Cogneris signs
        every webhook with HMAC-SHA256; verify the `cogneris-Signature` header
        before trusting the payload.
      operationId: createWebhook
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [url, events]
              properties:
                url:
                  type: string
                  format: uri
                  example: https://api.acme.com/webhooks/Cogneris
                events:
                  type: array
                  items:
                    type: string
                    enum: [extraction.completed, extraction.failed, validation.flagged]
                  example: [extraction.completed, validation.flagged]
                description:
                  type: string
                  example: Production extraction callbacks
      responses:
        '201':
          description: Webhook created.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Webhook'

  /audit/{request_id}:
    parameters:
      - name: request_id
        in: path
        required: true
        schema:
          type: string
          example: req_01H8YN3P9ZTVKMRAEH56X29Q4D
    get:
      tags: [Audit]
      summary: Get an audit record
      description: |
        Returns the immutable audit record for a request — model version, prompt
        hash, response, post-processor decisions, validator results, and any
        human-review decisions. Used for reproducibility, customer support, and
        regulatory audit (SOX, GDPR Art. 30, HIPAA).

        Audit records are retained per the customer's contract — default 7 years
        for Enterprise tenants.
      operationId: getAuditRecord
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AuditRecord'
        '404':
          $ref: '#/components/responses/NotFound'

components:
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      bearerFormat: API key
      description: |
        API keys are issued from the dashboard. Pass as `Authorization: Bearer YOUR_API_KEY`.
        Keys are tenant-scoped; never share keys across tenants.

  parameters:
    DocumentId:
      name: document_id
      in: path
      required: true
      schema:
        type: string
        pattern: '^doc_[A-Z0-9]{26}$'
        example: doc_01H8YN3P5ZTVKMRAEH56X29Q3K
    ExtractionId:
      name: extraction_id
      in: path
      required: true
      schema:
        type: string
        pattern: '^ext_[A-Z0-9]{26}$'
        example: ext_01H8YN3P9ZTVKMRAEH56X29Q4D

  schemas:
    Document:
      type: object
      properties:
        document_id:
          type: string
          example: doc_01H8YN3P5ZTVKMRAEH56X29Q3K
        original_filename:
          type: string
          example: jordan-hall-w2-2025.pdf
        page_count:
          type: integer
          example: 2
        bytes:
          type: integer
          example: 184320
        sha256:
          type: string
          example: 9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08
        created_at:
          type: string
          format: date-time
        latest_extraction_id:
          type: string
        latest_status:
          type: string
          enum: [queued, processing, completed, failed]

    Extraction:
      type: object
      properties:
        extraction_id:
          type: string
        document_id:
          type: string
        schema:
          type: string
          description: The extraction schema applied (e.g. `w2_2025`).
        fields:
          type: object
          description: Map of field-name → field-value. Each value is a `Field` object.
          additionalProperties:
            $ref: '#/components/schemas/Field'
        validators_run:
          type: array
          items:
            type: object
            properties:
              validator_id:
                type: string
              passed:
                type: boolean
              message:
                type: string
        decision:
          type: string
          enum: [auto_approved, auto_rejected, human_review_required]
        processing_ms:
          type: integer
        audit_record_url:
          type: string
          format: uri-reference
        created_at:
          type: string
          format: date-time

    Field:
      type: object
      description: A single extracted field with metadata.
      properties:
        value:
          oneOf:
            - type: string
            - type: number
            - type: boolean
            - type: 'null'
          description: The extracted value. Type depends on the schema (numbers for monetary fields, strings for names, etc.)
        confidence:
          type: number
          minimum: 0
          maximum: 1
          description: Confidence score 0-1. Below 0.85 triggers human review by default.
          example: 0.997
        source_page:
          type: integer
          description: 1-indexed page number where the value was found.
          example: 1
        bounding_box:
          type: array
          items:
            type: number
          minItems: 4
          maxItems: 4
          description: '[x_min, y_min, x_max, y_max] in normalized 0-1 coordinates.'
          example: [0.12, 0.34, 0.42, 0.38]

    Webhook:
      type: object
      properties:
        webhook_id:
          type: string
          example: wh_01H8YJ4P9ZTVKMRAEH56X29Q3K
        url:
          type: string
          format: uri
        events:
          type: array
          items:
            type: string
        signing_secret:
          type: string
          description: HMAC-SHA256 signing secret. Returned only on creation; cannot be retrieved later.
        created_at:
          type: string
          format: date-time

    AuditRecord:
      type: object
      properties:
        request_id:
          type: string
        tenant_id:
          type: string
        document_hash:
          type: string
        schema_version:
          type: string
        pipeline_version:
          type: string
        steps:
          type: array
          items:
            type: object
            properties:
              step:
                type: string
                enum: [planner, extractor, validator, post_processor]
              model:
                type: string
                example: claude-3-5-sonnet-2026-04
              prompt_hash:
                type: string
              params:
                type: object
              tokens_in:
                type: integer
              tokens_out:
                type: integer
              started_at:
                type: string
                format: date-time
              completed_at:
                type: string
                format: date-time
        final_extraction_hash:
          type: string
        decision:
          type: string
        completed_at:
          type: string
          format: date-time

    ErrorResponse:
      type: object
      description: RFC 7807 Problem Details.
      properties:
        type:
          type: string
          format: uri-reference
          example: https://cogneris.ai/errors/invalid-schema
        title:
          type: string
          example: Invalid schema identifier
        status:
          type: integer
          example: 400
        detail:
          type: string
          example: Schema 'w2_2099' is not a recognized extraction schema. See the dashboard for the current list.
        request_id:
          type: string
          description: Include this in support tickets for fast triage.
          example: req_01H8YN3P9ZTVKMRAEH56X29Q4D

  responses:
    BadRequest:
      description: Invalid request — missing fields, malformed schema, unsupported file type.
      content:
        application/problem+json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
    Unauthorized:
      description: Missing or invalid API key.
      content:
        application/problem+json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
    NotFound:
      description: Resource not found, or not visible from this tenant.
      content:
        application/problem+json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
    PayloadTooLarge:
      description: File exceeds the 100MB sync limit. Use the async endpoint for larger files.
      content:
        application/problem+json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
    RateLimited:
      description: Rate limit exceeded. The `Retry-After` response header indicates when to retry.
      headers:
        Retry-After:
          schema:
            type: integer
            description: Seconds until the limit resets.
      content:
        application/problem+json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
    InternalError:
      description: Internal server error. Include the request_id in support tickets.
      content:
        application/problem+json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
