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

# Add a text file or a picture of a document (a PDF once PDFs are read) for a widget's AI to answer from

> Gives the widget's AI a document made from a file. Send a `multipart/form-data` request with the file in the field
named `file` and, if you like, a `title`. The file is turned into text and then added exactly as
`addAiAnswersKnowledgeDocument` adds text: the same cleaning, the same limits, the same refusal of a copy of a
document the widget already has. The call returns once the document is ready to be used, which takes a few seconds
(a PDF is read first, so it takes longer).

**PDFs are not read yet.** For now a PDF is refused with 415, in a sentence that says what to do instead: paste the
text, upload it as a text file, or upload its pages as pictures. What this description says about a PDF is what will
hold from the day PDFs are read.

**Which files.**
- A **PDF** (not read yet, see above), up to 10 MB and 300 pages. Its text is read and its paragraphs are put back
  together. A PDF that is only pictures of pages (a scan) has no text to read: upload the pages as pictures instead.
  A PDF locked with a password is refused.
- A **text file**: `.txt`, `.text`, `.md`, `.markdown` or `.csv`, in UTF-8, UTF-16 or Windows-1252.
- A **picture of a document**: PNG, JPEG or WebP, up to 4 MB. The text in it is read with the same text recognition
  as the `ocr` adapter.
- Word and other office files are not read yet: save the file as a PDF and upload that.

What a file is comes from what is in it, not from its name or the type it is sent as. A file that is none of these is
refused with 415.

**The title.** Left out, the name of the file (without its extension) is the title. Visitors see the title as the
source of an answer, so send one that means something to them.

**The file is not kept.** Only its text, cut into passages, is kept, and `getAiAnswersKnowledge` never returns it.

**What leaves Widgetic.** As for text, the words of the document are sent to OpenAI to be embedded when it is added,
and the passages used for a question are sent to the AI model that writes the answer. A picture is also sent to the
text recognition service. A PDF is read on Widgetic's own servers and is not sent anywhere to be read. Say so in your
privacy policy.

**Treat every document as public.** An answer can quote or paraphrase anything a document says, to any visitor of
the widget. Do not add passwords, keys, personal data or anything that must stay private.

**Limits.** The widget's limits are those of `addAiAnswersKnowledgeDocument` (up to 20 documents, each up to 100000
characters of text, and up to 400000 characters in all; `getAiAnswersKnowledge` reports the current numbers), and
the file is at most 10 MB. Adding a document costs no credits. The same text cannot be added twice to one widget
(409).

The caller must be allowed to change the widget. An API key needs the `content:write` scope. Adds, from text or from
a file, share one limit of ten in ten minutes per person. A partner's customer in an editor session is one person
of its own: its adds are not counted with the partner's other customers'.




## OpenAPI

````yaml /openapi/widgetic-api-public.json post /compositions/{id}/adapters/ai-answers/knowledge/documents/file
openapi: 3.0.0
info:
  title: Widgetic API Gateway
  version: 1.0.0
  description: API documentation for the Widgetic API Gateway
  license:
    name: Widgetic Integration License
    url: https://docs.widgetic.com/resources/license
servers:
  - url: https://api.widgetic.com/v1
    description: Production server
    variables:
      env:
        default: production
        description: Environment
      apiUrl:
        default: https://api.widgetic.com
        description: API URL
      apiVersion:
        default: /v1
        description: API Version path prefix
security: []
tags: []
paths:
  /compositions/{id}/adapters/ai-answers/knowledge/documents/file:
    post:
      tags:
        - Compositions
      summary: >-
        Add a text file or a picture of a document (a PDF once PDFs are read)
        for a widget's AI to answer from
      description: >
        Gives the widget's AI a document made from a file. Send a
        `multipart/form-data` request with the file in the field

        named `file` and, if you like, a `title`. The file is turned into text
        and then added exactly as

        `addAiAnswersKnowledgeDocument` adds text: the same cleaning, the same
        limits, the same refusal of a copy of a

        document the widget already has. The call returns once the document is
        ready to be used, which takes a few seconds

        (a PDF is read first, so it takes longer).


        **PDFs are not read yet.** For now a PDF is refused with 415, in a
        sentence that says what to do instead: paste the

        text, upload it as a text file, or upload its pages as pictures. What
        this description says about a PDF is what will

        hold from the day PDFs are read.


        **Which files.**

        - A **PDF** (not read yet, see above), up to 10 MB and 300 pages. Its
        text is read and its paragraphs are put back
          together. A PDF that is only pictures of pages (a scan) has no text to read: upload the pages as pictures instead.
          A PDF locked with a password is refused.
        - A **text file**: `.txt`, `.text`, `.md`, `.markdown` or `.csv`, in
        UTF-8, UTF-16 or Windows-1252.

        - A **picture of a document**: PNG, JPEG or WebP, up to 4 MB. The text
        in it is read with the same text recognition
          as the `ocr` adapter.
        - Word and other office files are not read yet: save the file as a PDF
        and upload that.


        What a file is comes from what is in it, not from its name or the type
        it is sent as. A file that is none of these is

        refused with 415.


        **The title.** Left out, the name of the file (without its extension) is
        the title. Visitors see the title as the

        source of an answer, so send one that means something to them.


        **The file is not kept.** Only its text, cut into passages, is kept, and
        `getAiAnswersKnowledge` never returns it.


        **What leaves Widgetic.** As for text, the words of the document are
        sent to OpenAI to be embedded when it is added,

        and the passages used for a question are sent to the AI model that
        writes the answer. A picture is also sent to the

        text recognition service. A PDF is read on Widgetic's own servers and is
        not sent anywhere to be read. Say so in your

        privacy policy.


        **Treat every document as public.** An answer can quote or paraphrase
        anything a document says, to any visitor of

        the widget. Do not add passwords, keys, personal data or anything that
        must stay private.


        **Limits.** The widget's limits are those of
        `addAiAnswersKnowledgeDocument` (up to 20 documents, each up to 100000

        characters of text, and up to 400000 characters in all;
        `getAiAnswersKnowledge` reports the current numbers), and

        the file is at most 10 MB. Adding a document costs no credits. The same
        text cannot be added twice to one widget

        (409).


        The caller must be allowed to change the widget. An API key needs the
        `content:write` scope. Adds, from text or from

        a file, share one limit of ten in ten minutes per person. A partner's
        customer in an editor session is one person

        of its own: its adds are not counted with the partner's other
        customers'.
      operationId: addAiAnswersKnowledgeFile
      parameters:
        - in: path
          name: id
          required: true
          schema:
            type: string
            format: uuid
          description: The widget (composition) to add the document to
        - $ref: '#/components/parameters/ManagedUserScopeId'
        - $ref: '#/components/parameters/ManagedUserScopeExternalId'
      requestBody:
        required: true
        content:
          multipart/form-data:
            schema:
              type: object
              required:
                - file
              additionalProperties: false
              properties:
                file:
                  type: string
                  format: binary
                  description: >-
                    The file, which is a text file or a picture of a document (a
                    PDF is not read yet). One file only
                title:
                  type: string
                  maxLength: 120
                  description: >-
                    What the document is called, on one line. Visitors see it as
                    the source of an answer. Left out, the name of the file
                    stands in for it
                  example: Shipping and returns
      responses:
        '201':
          description: The document was added and is ready to be used
          content:
            application/json:
              schema:
                title: AiAnswersKnowledgeDocumentResponse
                type: object
                properties:
                  success:
                    type: boolean
                  data:
                    $ref: '#/components/schemas/AiAnswersKnowledgeDocument'
                  meta:
                    $ref: '#/components/schemas/ResponseMeta'
                required:
                  - success
                  - data
        '400':
          description: >-
            The widget id is not valid, no file was sent, more than one was, it
            was not in the field named `file`, the form could not be read, the
            form has a field other than `file` and `title`, or the title is too
            long (KNOWLEDGE_FILE_REQUIRED, KNOWLEDGE_TITLE_REQUIRED,
            KNOWLEDGE_TITLE_TOO_LONG, KNOWLEDGE_TEXT_REQUIRED)
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '401':
          description: The API key is missing or invalid
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '403':
          description: >-
            The widget belongs to another account, or the API key lacks the
            `content:write` scope
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '404':
          description: There is no such widget
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '409':
          description: >-
            The same text is already in this widget, or the widget already holds
            the most documents it can (KNOWLEDGE_DUPLICATE_DOCUMENT,
            KNOWLEDGE_LIMIT_DOCUMENTS)
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '413':
          description: >-
            The file is larger than 10 MB, a PDF has more than 300 pages, a
            picture is larger than 4 MB, or the text of the file is longer than
            a document may be or would take the widget past the most text it can
            hold in all (KNOWLEDGE_FILE_TOO_LARGE, KNOWLEDGE_TEXT_TOO_LONG,
            KNOWLEDGE_LIMIT_TOTAL_TEXT). Nothing was saved
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '415':
          description: >-
            The file is not a text file or a PNG, JPEG or WebP picture, or it is
            a PDF or a Word or other office file, which are not read yet
            (KNOWLEDGE_FILE_TYPE_UNSUPPORTED)
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '422':
          description: >-
            The file is of a kind that is read but this one cannot be: a PDF
            that is damaged, locked with a password or too slow to read, or a
            PDF or a picture with no text in it (KNOWLEDGE_FILE_UNREADABLE,
            KNOWLEDGE_FILE_NO_TEXT)
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '429':
          description: >-
            Too many documents added in a short time. Try again after the
            Retry-After seconds.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '502':
          description: >-
            The document could not be processed or saved
            (KNOWLEDGE_NOT_COMPLETED). Nothing was saved: try again
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '503':
          description: >-
            The knowledge base is not available right now, or the service is
            busy (KNOWLEDGE_UNAVAILABLE, KNOWLEDGE_BUSY). Nothing was saved
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
        - apiKeyAuth: []
      x-code-samples:
        - lang: TypeScript
          label: TypeScript SDK
          source: >
            import { openAsBlob } from 'node:fs';

            import { Configuration, CompositionsApi } from
            '@widgetic/api-sdk-ts';


            const compositionsApi = new CompositionsApi(new Configuration({
            apiKey: 'YOUR_API_KEY' }));


            const { data: document } = await
            compositionsApi.addAiAnswersKnowledgeFile({
              id: compositionId,
              file: await openAsBlob('shipping-and-returns.pdf'),
              title: 'Shipping and returns',
            });

            console.log(document.id, document.status);
components:
  parameters:
    ManagedUserScopeId:
      in: header
      name: X-Managed-User-Id
      required: false
      description: >-
        The id Widgetic gave the managed user (`POST /managed-users`). Makes
        this call for one of your managed users, so that a mistake in your own
        code cannot reach another customer's work. Send this header, or the
        other one, never both. Left out, the call works on your whole account,
        as it always has. With it, the call reaches only that user's
        compositions and workflows: a list shows only theirs, a composition or a
        workflow the call makes is filed under them, and one of another user, or
        one that does not exist, answers `404` (the same answer, so the call
        cannot be used to find out what another customer has). A managed user
        that is not yours answers `404` with `MANAGED_USER_NOT_FOUND`. An empty,
        repeated or malformed header is `400` with `MANAGED_USER_SCOPE_INVALID`;
        an empty header is never read as no header. A call that is about the
        whole account, such as the list of your managed users, is refused with
        `403` and `MANAGED_USER_SCOPE_ROUTE_NOT_AVAILABLE`: send it without the
        header. Only your API key can send it. The header is a limit the call
        asks for: whoever holds the key can leave it out, so for a credential
        that a customer's browser holds, use an editor session. An
        `Idempotency-Key` is kept apart for each managed user.
      schema:
        type: string
        format: uuid
        example: 3f2b8c1e-7a4d-4e0b-9c55-2d1a6b7e8f90
    ManagedUserScopeExternalId:
      in: header
      name: X-Managed-User-External-Id
      required: false
      description: >-
        Your own id for the managed user (its `externalId`), when you do not
        keep Widgetic's. Makes this call for one of your managed users, so that
        a mistake in your own code cannot reach another customer's work. Send
        this header, or the other one, never both. Left out, the call works on
        your whole account, as it always has. With it, the call reaches only
        that user's compositions and workflows: a list shows only theirs, a
        composition or a workflow the call makes is filed under them, and one of
        another user, or one that does not exist, answers `404` (the same
        answer, so the call cannot be used to find out what another customer
        has). A managed user that is not yours answers `404` with
        `MANAGED_USER_NOT_FOUND`. An empty, repeated or malformed header is
        `400` with `MANAGED_USER_SCOPE_INVALID`; an empty header is never read
        as no header. A call that is about the whole account, such as the list
        of your managed users, is refused with `403` and
        `MANAGED_USER_SCOPE_ROUTE_NOT_AVAILABLE`: send it without the header.
        Only your API key can send it. The header is a limit the call asks for:
        whoever holds the key can leave it out, so for a credential that a
        customer's browser holds, use an editor session. An `Idempotency-Key` is
        kept apart for each managed user.
      schema:
        type: string
        minLength: 1
        maxLength: 255
        example: customer-1042
  schemas:
    AiAnswersKnowledgeDocument:
      type: object
      description: >-
        One document in a widget's knowledge base: what the widget's AI answers
        visitors' questions from. Its text is not part of this: it is kept so
        the widget can find the passages that answer a question, and is never
        returned.
      required:
        - id
        - title
        - status
        - charCount
        - chunkCount
        - createdAt
        - readyAt
      properties:
        id:
          type: string
          format: uuid
          description: Use it to remove the document
        title:
          type: string
          maxLength: 120
          description: >-
            What the document is called. Visitors see it as the source of an
            answer, so write it for them
          example: Shipping and returns
        status:
          type: string
          enum:
            - processing
            - ready
          description: >-
            `ready` documents are used to answer questions. A `processing`
            document is not: it is being added, or an add was interrupted.
            Remove one that stays in this state and add it again
        charCount:
          type: integer
          description: How many characters of text the document holds, after it was cleaned
          example: 4210
        chunkCount:
          type: integer
          description: >-
            Into how many passages the text was cut. Zero until the document is
            ready
          example: 6
        createdAt:
          type: string
          format: date-time
        readyAt:
          type: string
          format: date-time
          nullable: true
          description: When the document became ready. Null while it is not
      example:
        id: 3fa85f64-5717-4562-b3fc-2c963f66afa6
        title: Shipping and returns
        status: Example status
        charCount: 4210
        chunkCount: 6
        createdAt: '2026-01-15T09:30:00.000Z'
        readyAt: '2026-01-15T09:30:00.000Z'
    ResponseMeta:
      type: object
      description: >-
        Extra information about the answer: where a page sits in a list, the
        cursor of the next page, or warnings about a call that succeeded with a
        caveat.
      additionalProperties: true
      properties:
        page:
          type: integer
          description: The page that was read, counting from 1.
          example: 1
        size:
          type: integer
          description: How many items one page holds.
          example: 20
        total:
          type: integer
          description: How many items the whole list has.
          example: 135
        limit:
          type: integer
          description: The same as `size`.
          example: 20
        offset:
          type: integer
          description: How many items come before this page.
          example: 0
        hasNextPage:
          type: boolean
          example: true
        hasPreviousPage:
          type: boolean
          example: false
        nextCursor:
          type: string
          nullable: true
          description: >-
            Pass this as `cursor` to read the next page of a list that is read
            by cursor. `null` on the last page.
        warnings:
          type: array
          items:
            type: string
          description: >-
            Things the call did not do, though it succeeded (for example a table
            that could not be created just now).
    ErrorResponse:
      type: object
      required:
        - success
        - message
        - error
      additionalProperties: true
      properties:
        success:
          type: boolean
          description: Always `false` on a failure.
          example: false
        message:
          type: string
          description: The same text as `error.message`, for a caller that reads one line.
        error:
          $ref: '#/components/schemas/ErrorDetail'
    ErrorDetail:
      type: object
      required:
        - code
        - message
        - timestamp
      properties:
        code:
          type: string
          description: Machine-readable error code.
          example: RESOURCE_NOT_FOUND
        message:
          type: string
          description: Human-readable explanation.
          example: Composition not found
        param:
          type: string
          description: The field that caused the error, when one did.
          example: name
        docUrl:
          type: string
          description: Where this error is explained.
        suggestedAction:
          type: string
          description: What to do about it.
        retryAfter:
          type: integer
          description: >-
            Seconds to wait before trying again (rate limits). The same number
            is in the `Retry-After` header.
          example: 60
        details:
          type: object
          additionalProperties: true
          description: >-
            More about the error: the fields that failed, a limit that was
            reached.
        correlationId:
          type: string
          description: Quote this when you ask support about the call.
          example: req_123e4567-e89b-12d3-a456-426614174000
        timestamp:
          type: string
          format: date-time
          example: '2026-10-15T10:00:00.000Z'
  securitySchemes:
    apiKeyAuth:
      type: http
      scheme: bearer
      bearerFormat: JWT

````

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