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

# Bulk generate knowledge

> Queue generate-and-save jobs for multiple source IDs in one request.

Use this route when you want Fini to generate knowledge directly from ingested source records at scale. This is the main self-serve route for source-backed knowledge creation and refresh.

<Info>
  This route only supports `origin: "sources"`. It reads from the stored source content for each `documentId`, and `isDraft` defaults to `true`.
</Info>

## Headers

<ParamField header="Authorization" type="string" required>
  Bearer token containing your Fini workspace API key. Format: `Bearer fini_...` The key needs `write` scope.
</ParamField>

<ParamField header="Content-Type" type="string" required>
  `application/json`
</ParamField>

## Body parameters

<ParamField body="documentIds" type="array" required>
  Source IDs to generate from.
</ParamField>

<ParamField body="origin" type="string" required>
  Must be `sources` on the bulk route.
</ParamField>

<ParamField body="restrictedOps" type="array">
  Optional operation restrictions passed through to the generation pipeline. Use this to limit what Fini is allowed to do when it decides how to apply each source.
</ParamField>

<ParamField body="instructions" type="string">
  Additional generation instructions.
</ParamField>

<ParamField body="botId" type="string">
  Optional agent ID to scope the generated content to.
</ParamField>

<ParamField body="isDraft" type="boolean" default={true}>
  Whether the generated results should remain drafts.
</ParamField>

## `restrictedOps` values

Use `restrictedOps` to limit the operation choices available to the knowledge-generation pipeline for every source in the batch.

| Value                   | Meaning                                                                                                                                        |
| ----------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------- |
| `ADD_ARTICLE_TO_FOLDER` | Allow Fini to create a new article in an existing folder.                                                                                      |
| `UPDATE_ARTICLE`        | Allow Fini to update an existing article that the pipeline selects as the best match.                                                          |
| `DO_NOTHING`            | Allow Fini to decide that no knowledge change should be applied. When `isDraft` is `true`, this still creates a reviewable draft/no-op record. |

## Response

<ResponseField name="jobs" type="array">
  One queued job per input source.

  <Expandable title="job object">
    <ResponseField name="jobs[].documentId" type="string">
      Input source ID.
    </ResponseField>

    <ResponseField name="jobs[].backgroundJobId" type="string">
      Queued background job ID for that source.
    </ResponseField>
  </Expandable>
</ResponseField>

<RequestExample>
  ```bash cURL theme={null}
  curl --request POST \
    --url 'https://api-prod.usefini.com/v2/knowledge/public/bulk' \
    --header 'Authorization: Bearer fini_your_api_key' \
    --header 'Content-Type: application/json' \
    --data '{
      "documentIds": [
        "5d9f67a8-d853-4af4-b7ce-23ebba1245e5",
        "35b4838a-4136-4f6c-a530-8f17cb47566d"
      ],
      "origin": "sources",
      "isDraft": true
    }'
  ```

  ```python Python theme={null}
  import requests

  response = requests.post(
      "https://api-prod.usefini.com/v2/knowledge/public/bulk",
      headers={
          "Authorization": "Bearer fini_your_api_key",
          "Content-Type": "application/json",
      },
      json={
          "documentIds": [
              "5d9f67a8-d853-4af4-b7ce-23ebba1245e5",
              "35b4838a-4136-4f6c-a530-8f17cb47566d",
          ],
          "origin": "sources",
          "isDraft": True,
      },
  )
  jobs = response.json()
  ```

  ```javascript Node.js theme={null}
  const response = await fetch("https://api-prod.usefini.com/v2/knowledge/public/bulk", {
    method: "POST",
    headers: {
      Authorization: "Bearer fini_your_api_key",
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      documentIds: [
        "5d9f67a8-d853-4af4-b7ce-23ebba1245e5",
        "35b4838a-4136-4f6c-a530-8f17cb47566d",
      ],
      origin: "sources",
      isDraft: true,
    }),
  });
  const jobs = await response.json();
  ```
</RequestExample>

<ResponseExample>
  ```json 200 OK theme={null}
  {
    "jobs": [
      {
        "documentId": "5d9f67a8-d853-4af4-b7ce-23ebba1245e5",
        "backgroundJobId": "4cfcf2cc-7a06-4de2-b460-5b991fe6236a"
      },
      {
        "documentId": "35b4838a-4136-4f6c-a530-8f17cb47566d",
        "backgroundJobId": "1b18f1d5-f5cc-4fc2-8d5b-38d4a7c5f28b"
      }
    ]
  }
  ```
</ResponseExample>

## Refresh existing knowledge from changed sources

If existing sources already back knowledge in Fini and the upstream content changes, the refresh sequence is:

<Steps>
  <Step title="Refresh the existing source IDs">
    Call [Refresh sources](/en/api-reference/refresh-sources) with the source IDs you already have.
  </Step>

  <Step title="Poll until the source refresh finishes">
    Use [List sources](/en/api-reference/list-sources) or [Get source](/en/api-reference/get-source) until `linkedJobStatus` moves to `COMPLETED`.
  </Step>

  <Step title="Filter to the sources that actually changed">
    Call [List sources](/en/api-reference/list-sources) with `changed=true`. If you only want web content, also pass `source=web`. Keep the source records that already have a `linkedKnowledgeId`.
  </Step>

  <Step title="Bulk generate and save knowledge for those changed source IDs">
    Call this route with the changed `documentIds`. Use `isDraft: true` if you want to review the updates first. Use `isDraft: false` only if you want the updated knowledge saved live immediately.
  </Step>

  <Step title="Poll job status, then review if drafts were created">
    Call [Check knowledge jobs](/en/api-reference/check-knowledge-jobs) with the returned job IDs until the jobs finish. If you created drafts, review and publish them before expecting live answers to change.
  </Step>
</Steps>

<Info>
  After a successful source-backed save, Fini syncs the source's linked knowledge reference and clears the `changed` flag on that source record.
</Info>

## Errors

<AccordionGroup>
  <Accordion title="400 Bad Request" icon="circle-exclamation">
    The request body is malformed, `documentIds` is missing or empty, or `origin` is not `sources`.
  </Accordion>

  <Accordion title="401 Unauthorized" icon="lock">
    The API key is missing, malformed, revoked, or invalid.
  </Accordion>

  <Accordion title="403 Forbidden" icon="shield-halved">
    The API key does not include the `write` scope.
  </Accordion>

  <Accordion title="500 Internal Server Error" icon="triangle-exclamation">
    Fini failed while queueing or processing one or more generation jobs. Retry once, then inspect the job IDs with [Check knowledge jobs](/en/api-reference/check-knowledge-jobs).
  </Accordion>
</AccordionGroup>
