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

# Ask

> Answer a question from the content of a workflow's documents, with citations

*Rate limit tier: **submission**, 60 requests/min. See [Rate limits](/api-reference-v3/introduction#rate-limits).*

Answers a question about what a workflow's documents **say**: contract terms, invoice details, anything that needs reading rather than a field lookup. Extraction answers "what is in this document". This endpoint answers "what do these documents say about X", across the workflow's current corpus.

Every answer carries the exact quotes it rests on. Each quote resolves to a page and a region in the source PDF, so you can show a customer where a number came from.

## Requires a knowledge base

The workflow needs a **knowledge node**. Without one, the endpoint returns `409 KNOWLEDGE_NOT_ENABLED`. Add the node in Studio, or include it when you create the workflow.

Adding the node makes subsequent completed runs eligible for ingestion. It does not backfill documents that completed earlier. A member starts **Index existing documents** or **Retry indexing** from the workflow's **Knowledge** tab when needed. A pack that already exists keeps serving while a later upload is re-indexed in the background, so there is no manual "update" action to trigger. These app actions are not public REST or MCP operations.

The corpus is **workflow-scoped, not version-scoped**. It keeps the current parsed content for each live file across runs and versions. It is not a version history.

## Errors

| Status | `error_code` | Meaning |
| - | - | - |
| `402` | `INSUFFICIENT_CREDIT` | The organization has no credits. The API refuses the question before it runs, and charges nothing. |
| `404` | `NOT_FOUND` | Unknown workflow, or one belonging to another organization. |
| `409` | `KNOWLEDGE_NOT_ENABLED` | The workflow has no Knowledge node. Do not retry: add the node first. |
| `409` | `KNOWLEDGE_NOT_READY` | No knowledge snapshot has ever been published for this workflow. Wait if indexing is in progress; otherwise index existing documents from the app's Knowledge tab. Once a snapshot exists, later ingestion never brings this error back — a stale pack keeps serving while it re-indexes. |
| `409` | `KNOWLEDGE_THREAD_MISMATCH` | The `thread_id` belongs to a different workflow. Use a new id or ask the workflow that owns it. |
| `409` | `KNOWLEDGE_UNSUPPORTED_SNAPSHOT_FORMAT` | The published snapshot is in a format this deployment no longer reads. Permanent until an operator republishes it. |
| `429` | `RATE_LIMITED` | The model is rate limited. Retry after the delay in `Retry-After`. |
| `502` | `INTERNAL_ERROR` | The model refused the request. Not worth retrying unchanged. |
| `503` | `INTERNAL_ERROR` | The model is temporarily unavailable. Retry. |
| `504` | `GATEWAY_TIMEOUT` | The ask exceeded the agent time limit. Retry with a narrower question. |

## Follow-up questions

Pass a `thread_id` you mint yourself, starting with `kb-`, to ask in the context of earlier questions in that thread. Omit it and each question stands alone. Reuse the same id to continue a conversation.

## Billing

The platform charges per question and meters the text the agent reads. A narrow question over a small corpus therefore costs a fraction of a broad sweep over a large one. A question the organization cannot pay for is refused up front.

<RequestExample>
  ```bash curl theme={null}
  curl -X POST 'https://api.anyformat.ai/v3/workflows/0686bb97-8c30-70f0-8000-97669e000eb8/knowledge/ask' \
    -H 'Authorization: Bearer YOUR_API_KEY' \
    -H 'Content-Type: application/json' \
    -d '{"question": "Which contracts renew before March and what notice do they need?"}'
  ```

  ```python Python (SDK) theme={null}
  from anyformat.sdk import Client

  client = Client(api_key="YOUR_API_KEY")
  answer = client.ask(
      "0686bb97-8c30-70f0-8000-97669e000eb8",
      "Which contracts renew before March and what notice do they need?",
  )

  print(answer)
  for citation in answer.citations:
      print(f"  {citation.path} p.{citation.page}: {citation.quote}")
  ```

  ```typescript TypeScript theme={null}
  const response = await fetch(
    'https://api.anyformat.ai/v3/workflows/0686bb97-8c30-70f0-8000-97669e000eb8/knowledge/ask',
    {
      method: 'POST',
      headers: {
        'Authorization': 'Bearer YOUR_API_KEY',
        'Content-Type': 'application/json',
      },
      body: JSON.stringify({
        question: 'Which contracts renew before March and what notice do they need?',
      }),
    },
  );

  if (!response.ok) {
    throw new Error(`API error: ${response.status}`);
  }

  const { answer, citations } = await response.json();
  console.log(answer);
  ```
</RequestExample>

<ResponseExample>
  ```json Response (200 OK) theme={null}
  {
    "answer": "Two contracts renew before March. Meridian MSA renews 2026-02-01 and needs ninety days' notice to terminate. Aldrete supply agreement renews 2026-02-14 with thirty days' notice.",
    "citations": [
      {
        "path": "2026-07/meridian-msa-2024.md",
        "quote": "Either Party may terminate upon ninety (90) days' notice.",
        "file_id": "0192f0c1-a2b3-4c5d-8000-abcdef012345",
        "block_id": "block-2",
        "page": 2,
        "bbox": { "x0": 0.08, "y0": 0.31, "x1": 0.92, "y1": 0.36 }
      }
    ],
    "path": [
      { "tool": "kb_grep", "args": { "pattern": "renewal" } },
      { "tool": "kb_read", "args": { "path": "2026-07/meridian-msa-2024.md" } }
    ],
    "steps_used": 2,
    "thread_id": null
  }
  ```

  ```json Response (409, no knowledge base) theme={null}
  {
    "error": "The knowledge base is not enabled.",
    "error_code": "KNOWLEDGE_NOT_ENABLED",
    "retryable": false,
    "request_id": "a1b2c3d4e5f67890abcdef1234567890"
  }
  ```

  ```json Response (402, out of credit) theme={null}
  {
    "error": "The organization has no extraction credit left.",
    "error_code": "INSUFFICIENT_CREDIT",
    "retryable": false,
    "request_id": "a1b2c3d4e5f67890abcdef1234567890"
  }
  ```
</ResponseExample>


## OpenAPI

````yaml POST /v3/workflows/{workflow_id}/knowledge/ask
openapi: 3.1.0
info:
  title: anyformat API
  description: >
    Document extraction and workflow automation API.


    AnyFormat lets you define extraction workflows that pull structured data
    from any document — PDFs, images, scanned files, or plain text. Upload a
    file, run it through a workflow, and get back structured fields with
    confidence scores and source evidence.


    ## Quick start


    See the [Quick start
    guide](https://docs.anyformat.ai/api-reference-v3/introduction) for a
    walkthrough.


    ## Authentication


    All endpoints (except `/health/`) require a Bearer token in the
    `Authorization` header:


    ```

    Authorization: Bearer <your-api-key>

    ```


    Get your API key from
    [app.anyformat.ai/api-key](https://app.anyformat.ai/api-key).


    ## Versioning


    Endpoints are versioned by path prefix (`/v3/`). Every response under

    a versioned prefix includes `X-API-Version`.
  version: 3.0.0
servers:
  - url: https://api.anyformat.ai
    description: API server
security: []
tags:
  - name: workflows
    description: >-
      Workflows define extraction templates — what fields to extract from
      documents. Create workflows, upload files, run extractions, and fetch
      results.
  - name: document-packets
    description: >-
      Document packets group uploaded documents for a workflow. Address a packet
      directly to (re-)run its workflow.
  - name: runs
    description: >-
      Extraction runs — the first-class result entity. Each run is a single
      execution of a workflow against a document packet; fetch its status and
      results flat by run id.
  - name: splits
    description: >-
      Splits — the sub-documents a splitter node carves out of a packet.
      Download any one of them as a PDF, built from the source documents on
      request and never stored.
  - name: parse
    description: >-
      Parse a single document with the platform's fast lite parse — a one-call
      shortcut over the workflow upload + run primitives, backed by your
      organization's system parse workflow.
  - name: health
    description: Health check endpoints to verify API availability.
paths:
  /v3/workflows/{workflow_id}/knowledge/ask:
    post:
      tags:
        - knowledge
      summary: Ask a question about a workflow's documents
      description: >-
        Answer a question from the content of this workflow's documents.


        The answer is grounded: every claim comes back with the exact quote it

        rests on, resolved to a page and a region in the source PDF, so you can

        show a customer where a number came from instead of asking them to trust

        it. `path` reports the route the agent took to get there.


        The workflow needs a knowledge node — that is what indexes its
        documents.

        Without one this returns 409.


        Billed per question against the organization's credits, on the text the

        agent actually reads. A question the organization cannot pay for is

        refused before it runs, not after.


        Pass a `thread_id` you mint yourself (starting with `kb-`) to ask a

        follow-up in context; omit it and each question stands alone.
      operationId: v3_ask_knowledge
      parameters:
        - name: workflow_id
          in: path
          required: true
          schema:
            type: string
            title: Workflow Id
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/AskRequestV3'
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AskResponseV3'
          headers:
            X-RateLimit-Limit:
              description: Requests allowed per window (60s).
              schema:
                type: integer
            X-RateLimit-Remaining:
              description: Requests remaining in the current window.
              schema:
                type: integer
            X-RateLimit-Reset:
              description: Seconds until the current window resets.
              schema:
                type: integer
        '400':
          description: >-
            Validation failed — the request body or query parameters are
            invalid.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorEnvelope'
              examples:
                VALIDATION_ERROR:
                  value:
                    error: The request failed validation.
                    detail: The request failed validation.
                    error_code: VALIDATION_ERROR
                    retryable: false
                    request_id: req_abc123
        '401':
          description: Authentication failed — missing, invalid, or expired API key.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorEnvelope'
              examples:
                AUTH_FAILED:
                  value:
                    error: Authentication failed.
                    detail: Authentication failed.
                    error_code: AUTH_FAILED
                    retryable: false
                    request_id: req_abc123
        '402':
          description: >-
            `PAYMENT_REQUIRED` — the organization has no credits. Refused before
            the question runs, so nothing is charged.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorEnvelope'
        '403':
          description: >-
            Access denied — the API key lacks access to this resource or the
            scope this call needs (`ACCESS_DENIED`,
            `INSUFFICIENT_API_KEY_SCOPE`).
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorEnvelope'
              examples:
                ACCESS_DENIED:
                  value:
                    error: You do not have access to this resource.
                    detail: You do not have access to this resource.
                    error_code: ACCESS_DENIED
                    retryable: false
                    request_id: req_abc123
        '404':
          description: >-
            Resource not found — the workflow, document packet, or run ID does
            not exist or is not visible to this API key.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorEnvelope'
              examples:
                NOT_FOUND:
                  value:
                    error: Resource not found.
                    detail: Resource not found.
                    error_code: NOT_FOUND
                    retryable: false
                    request_id: req_abc123
        '409':
          description: >-
            `KNOWLEDGE_NOT_ENABLED` — no knowledge node on the workflow,
            permanent until one is added. `KNOWLEDGE_NOT_READY` — the first
            index is still building, worth retrying. `KNOWLEDGE_THREAD_MISMATCH`
            — this `thread_id` belongs to a different workflow.
            `KNOWLEDGE_UNSUPPORTED_SNAPSHOT_FORMAT` — the published snapshot is
            in a format this deployment no longer reads, permanent until an
            operator republishes it.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorEnvelope'
        '429':
          description: >-
            Rate limited — retry after the `Retry-After` header. Default
            windows: 60 requests/minute for extraction submission, 600
            requests/minute for general endpoints.
          headers:
            Retry-After:
              description: Seconds until the next request is allowed.
              schema:
                type: integer
            X-RateLimit-Limit:
              description: Requests allowed per window (60s).
              schema:
                type: integer
            X-RateLimit-Remaining:
              description: Requests remaining in the current window.
              schema:
                type: integer
            X-RateLimit-Reset:
              description: Seconds until the current window resets.
              schema:
                type: integer
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorEnvelope'
              examples:
                RATE_LIMITED:
                  value:
                    error: Rate limit exceeded — retry after backoff.
                    detail: Rate limit exceeded — retry after backoff.
                    error_code: RATE_LIMITED
                    retryable: true
                    request_id: req_abc123
        '500':
          description: >-
            An internal error stopped the request — `retryable=true`. Retry with
            backoff.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorEnvelope'
              examples:
                INTERNAL_ERROR:
                  value:
                    error: An internal error stopped the request.
                    detail: An internal error stopped the request.
                    error_code: INTERNAL_ERROR
                    retryable: true
                    request_id: req_abc123
        '504':
          description: >-
            The ask exceeded the agent's own time ceiling. Retry with a narrower
            question.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorEnvelope'
      security:
        - ApiKeyAuth: []
components:
  schemas:
    AskRequestV3:
      properties:
        question:
          type: string
          minLength: 1
          title: Question
          description: A question about the content of this workflow's documents.
          examples:
            - Which contracts renew before March and what notice do they need?
        thread_id:
          anyOf:
            - type: string
              maxLength: 64
              pattern: ^kb-[A-Za-z0-9._-]+$
            - type: 'null'
          title: Thread Id
          description: >-
            Optional conversation id, minted by you, to ask a follow-up in
            context. Must start with `kb-`. Reuse it to continue; omit it for a
            fresh question.
          examples:
            - kb-renewals-q3
      type: object
      required:
        - question
      title: AskRequestV3
    AskResponseV3:
      properties:
        answer:
          type: string
          title: Answer
        citations:
          items:
            $ref: '#/components/schemas/AskCitationV3'
          type: array
          title: Citations
        path:
          items:
            $ref: '#/components/schemas/AskStepV3'
          type: array
          title: Path
          description: The route the agent took to the answer — auditable, not decorative.
        steps_used:
          type: integer
          title: Steps Used
        thread_id:
          anyOf:
            - type: string
            - type: 'null'
          title: Thread Id
          description: Present when the question was asked in a thread.
      type: object
      required:
        - answer
        - citations
        - path
        - steps_used
      title: AskResponseV3
    ErrorEnvelope:
      type: object
      title: ErrorEnvelope
      description: >-
        Uniform error response. `retryable=true` means the same request may
        succeed on retry (with backoff); `retryable=false` means the caller must
        change the request before retrying.
      required:
        - error
        - error_code
        - retryable
        - request_id
      properties:
        error:
          type: string
          description: Short human-readable summary.
        detail:
          description: >-
            Machine-readable detail, any JSON value. A string for most errors, a
            list of field errors for validation failures, and an object for a
            structured error such as `FILENAME_CONFLICT` (`detail.conflicts`).
        error_code:
          type: string
          description: Stable identifier for programmatic handling.
          examples:
            - VALIDATION_ERROR
            - AUTH_FAILED
            - NOT_FOUND
            - PRECONDITION_FAILED
            - RATE_LIMITED
            - INTERNAL_ERROR
            - GATEWAY_TIMEOUT
        retryable:
          type: boolean
          description: True when the caller should retry (with backoff for 429/412/5xx).
        request_id:
          type: string
          description: Correlates this response with server logs.
    AskCitationV3:
      properties:
        path:
          type: string
          title: Path
          description: Document path inside the workflow's corpus.
        quote:
          type: string
          title: Quote
          description: The exact span the answer rests on.
        file_id:
          anyOf:
            - type: string
            - type: 'null'
          title: File Id
          description: The source file, for downloads and links.
        block_id:
          anyOf:
            - type: string
            - type: 'null'
          title: Block Id
          description: Anchor within the document.
        page:
          anyOf:
            - type: integer
            - type: 'null'
          title: Page
          description: 1-based page in the source PDF.
        bbox:
          anyOf:
            - additionalProperties: true
              type: object
            - type: 'null'
          title: Bbox
          description: Region on that page, as `{x0, y0, x1, y1}` in relative coordinates.
      type: object
      required:
        - path
        - quote
        - file_id
        - block_id
        - page
        - bbox
      title: AskCitationV3
      description: Where an answer came from, resolved to a place in the source PDF.
    AskStepV3:
      properties:
        tool:
          type: string
          title: Tool
        args:
          additionalProperties: true
          type: object
          title: Args
      type: object
      required:
        - tool
        - args
      title: AskStepV3
      description: One navigation step the agent took, in order.
  securitySchemes:
    ApiKeyAuth:
      type: http
      description: >-
        API key issued from app.anyformat.ai/api-key. Send as `Authorization:
        Bearer <key>`.
      scheme: bearer

````

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