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

# Extract text from a PDF or Word document

> Returns the text a compliance check would run on, with word and page counts and the
limits that apply to your plan. Use it to preview or trim a document before checking
it, or to build your own text check. **Not billed.** Extraction is also performed
implicitly when you send a `document` part to `POST /compliance/check`.

Limits: 30 MB per file, 100 pages, 400,000 characters, 30 seconds of extraction, one
document per request, and a per-plan word cap returned as `limits.maxWords`. Scanned
PDFs with no text layer are rejected. A `Content-Length` header is required.




## OpenAPI

````yaml /openapi/zebratruth-v1.yaml post /compliance/documents/extract
openapi: 3.1.0
info:
  title: ZebraTruth Compliance API
  version: 1.0.0
  description: >
    AI-powered compliance checking for advertising content. Check text and
    images against

    jurisdiction laws, platform policies, and rights clearance requirements.
    Results include

    embeddable annotations mapped to content locations (text spans, video
    timestamps, image regions).
  contact:
    name: ZebraTruth Support
    email: support@zebratruth.ai
    url: https://developers.zebratruth.ai
  license:
    name: MIT
    url: https://opensource.org/licenses/MIT
servers:
  - url: https://api.zebratruth.ai/v1
    description: Production
security:
  - bearerAuth: []
tags:
  - name: Video Compliance
    description: >
      **Primary endpoint.** Async compliance analysis for video ads. 3-step
      flow:

      get an upload URL, upload the video bytes, submit for analysis. Poll or

      receive an HMAC-signed webhook with the report. Returns timestamped

      findings citing stable evidence IDs (`audio_NNN`, `frame_NNN`, `ocr_NNN`,

      `signal_NNN`). 3-180 second videos. mp4 / webm /

      quicktime. Built for ad agencies and creators.
  - name: Authentication
    description: Validate API keys and check account status
  - name: Compliance
    description: >-
      Run compliance checks on text + image content (sync). For video, use the
      Video Compliance endpoints above.
  - name: Agents
    description: Discover and invoke individual compliance agents
  - name: Jobs
    description: Poll async job status and view execution traces
  - name: Reports
    description: Retrieve and replay compliance reports
  - name: Observability
    description: Request logs and webhook delivery status
  - name: Billing
    description: Subscriptions, plan changes, and credit balance
  - name: Documents
    description: Extract text from PDF and Word documents before or as part of a check
  - name: Check History
    description: List and retrieve past compliance checks for the workspace
  - name: Provenance
    description: Inspect and sign Content Credentials (C2PA) on images and video
  - name: Corpus
    description: >-
      Review queue for proposed changes to the governed legal corpus (dashboard
      session)
  - name: Webhooks
    description: Saved webhook endpoints (dashboard session) and delivery logs
paths:
  /compliance/documents/extract:
    post:
      tags:
        - Documents
      summary: Extract text from a PDF or Word document
      description: >
        Returns the text a compliance check would run on, with word and page
        counts and the

        limits that apply to your plan. Use it to preview or trim a document
        before checking

        it, or to build your own text check. **Not billed.** Extraction is also
        performed

        implicitly when you send a `document` part to `POST /compliance/check`.


        Limits: 30 MB per file, 100 pages, 400,000 characters, 30 seconds of
        extraction, one

        document per request, and a per-plan word cap returned as
        `limits.maxWords`. Scanned

        PDFs with no text layer are rejected. A `Content-Length` header is
        required.
      operationId: extractDocument
      requestBody:
        required: true
        content:
          multipart/form-data:
            schema:
              $ref: '#/components/schemas/DocumentExtractRequest'
      responses:
        '200':
          description: Extracted text
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/DocumentExtractResponse'
        '400':
          description: >-
            `data.code`: `expected_multipart`, `content_length_required`,
            `invalid_content_length`, `empty_multipart`, `document_required`,
            `document_count_exceeded`, `document_malformed`.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/CodedError'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/ForbiddenCoded'
        '413':
          $ref: '#/components/responses/PayloadTooLarge'
        '415':
          $ref: '#/components/responses/UnsupportedMediaType'
        '422':
          $ref: '#/components/responses/UnprocessableDocument'
components:
  schemas:
    DocumentExtractRequest:
      type: object
      required:
        - document
      properties:
        document:
          type: string
          format: binary
          description: >
            One PDF (`application/pdf`, `.pdf`) or Word file

            (`application/vnd.openxmlformats-officedocument.wordprocessingml.document`,
            `.docx`).

            The bytes are sniffed; the declared type and the filename extension
            must agree with

            what the bytes are. Legacy `.doc` is refused.
    DocumentExtractResponse:
      type: object
      required:
        - format
        - wordCount
        - charCount
        - text
        - limits
      properties:
        format:
          type: string
          enum:
            - pdf
            - word_doc
        pageCount:
          type: integer
          description: Present for PDF only.
        wordCount:
          type: integer
          description: >-
            Billable words. A check on this text is priced by `ceil(wordCount /
            500)` blocks.
        charCount:
          type: integer
        text:
          type: string
          description: The extracted text, line breaks preserved.
        limits:
          type: object
          description: The limits that applied to this workspace.
          properties:
            maxWords:
              type: integer
              description: Words per check allowed on the current plan.
            maxPages:
              type: integer
              example: 100
            maxUploadBytes:
              type: integer
              example: 31457280
        _meta:
          type: object
          description: Present only for test-mode keys.
          properties:
            testMode:
              type: boolean
    CodedError:
      type: object
      description: >
        Standard error envelope. `data.code` is the stable discriminator to
        branch on;

        `statusMessage` is the human-readable reason. Unless a response
        documents extra

        named fields, `data` is reduced to `{ code }` before it is sent.
      required:
        - statusCode
        - message
      properties:
        error:
          type: boolean
          example: true
        url:
          type: string
          format: uri
        statusCode:
          type: integer
        statusMessage:
          type: string
        message:
          type: string
        data:
          type: object
          required:
            - code
          properties:
            code:
              type: string
              example: review_scope_not_enabled
          additionalProperties: true
  responses:
    Unauthorized:
      description: |
        Invalid, missing, or expired API key. Standard error envelope —
        read `message` for the human-readable reason.
      content:
        application/json:
          schema:
            type: object
            description: Standard error envelope.
            required:
              - statusCode
              - message
            properties:
              error:
                type: boolean
                example: true
              url:
                type: string
                format: uri
                example: https://api.zebratruth.ai/v1/whoami
              statusCode:
                type: integer
                example: 401
              statusMessage:
                type: string
                example: Invalid API key
              message:
                type: string
                description: Canonical human-readable reason — pattern-match on this field.
                example: Invalid API key
    ForbiddenCoded:
      description: >
        The credential is valid but may not perform this action. `data.code` is
        one of

        `permission_not_granted`, `principal_forbidden_control_plane` (an API
        key called a

        dashboard-only action), `membership_not_active`, `entitlement_required`,

        `workspace_provisioning`, `workspace_deletion_scheduled`.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/CodedError'
    PayloadTooLarge:
      description: >
        The upload exceeds a limit. `data.code` is one of `document_too_large`,

        `document_too_many_pages`, `document_too_much_text`,
        `text_exceeds_tier_limit`,

        `payload_too_large` (provenance; also carries `limitBytes`),
        `video_upload_too_large`.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/CodedError'
    UnsupportedMediaType:
      description: >
        The file type is not accepted. `data.code` is one of
        `document_format_unsupported`

        (legacy `.doc`, unknown signature, or a filename that does not match the
        bytes),

        `document_encrypted`, `unknown_content_type`,
        `video_signing_unavailable`,

        `unsupported_container`.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/CodedError'
    UnprocessableDocument:
      description: |
        The document was accepted but could not be used. `data.code` is one of
        `document_no_extractable_text` (for example a scanned PDF) or
        `document_extraction_timeout`.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/CodedError'
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      description: |
        API key starting with `zt_live_` (production) or `zt_test_` (sandbox).
        Get your key at https://developers.zebratruth.ai

````

This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.