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

# Prompt Config Versions

> Save, publish and load whole versions of an agent's prompt configuration.

# Prompt Config Versions

An agent's prompt is assembled from **sections** — the system prompt, then each enabled tool's guidance. Versioning is at the level of the **whole configuration**, not the section:

| Concept | What it is | Who reads it |
| - | - | - |
| **Draft** | The working copy of every section, as the prompt editor shows it | The editor and the draft preview |
| **Config version** | An immutable capture of every customised section, numbered `vX.Y` | The version rail; Load; Publish |
| **Live** | The one config version visitors hear | Every chat channel |

**A section absent from a config version means "platform default".** A platform improvement to a default therefore reaches every agent that has not overridden that section.

Saving never changes what visitors hear. Publishing does, and it moves the whole configuration at once — there is no per-section publish.

<Note>
  All API requests require a valid JWT token in the `Authorization: Bearer <token>` header. The API Gateway decodes the JWT and forwards auth context (`user-id`, `organization-id`, `user-email`, `x-platform-role`, `x-org-role`) as headers to downstream services.
</Note>

Reads (`GET`) require **`read`** on the agent. Save and Publish require **`update`**. An agent outside the caller's organization answers `404`. Save and Publish each write an audit row under the agent's organization.

***

## Save a config version

<ParamField method="POST" path="/api/bots/:id/prompt-config-versions" />

Writes every given section to the draft **and** captures config `vX.Y` from the agent's whole customised set, in one transaction. Does **not** publish.

<ParamField body="sections" type="object[]" required>
  The sections to write, usually the ones edited since the last save. May be empty: a save after "Reset to default", or after a draft change made elsewhere, records the draft as it stands. Each section appears at most once.

  <Expandable title="section">
    <ParamField body="promptType" type="string" required>
      The prompt type, e.g. `system`, `guardrail`, `custom_tool_instructions`.
    </ParamField>

    <ParamField body="instanceRef" type="string | null">
      Required for an instanced type (one section per custom tool): the custom tool id, which must be enabled on this agent. Ignored for any other type.
    </ParamField>

    <ParamField body="mode" type="'fixed' | 'generated'" required>
      `fixed` sends `content` as written; `generated` sends `prompt` to a model first.
    </ParamField>

    <ParamField body="content" type="string | null">
      The section text for `fixed` mode. `null` content **and** `null` prompt means "no override": the section returns to the platform default.
    </ParamField>

    <ParamField body="prompt" type="string | null">
      The generation instruction for `generated` mode.
    </ParamField>
  </Expandable>
</ParamField>

<ParamField body="bumpType" type="'major' | 'minor'" default="minor">
  `minor` → `vM.(m+1)`, `major` → `v(M+1).0`, counted from the newest version. An agent's first version is `v1.0` whichever is chosen.
</ParamField>

<ParamField body="label" type="string">
  Optional Version Comment, up to 5,000 characters. Shown in the version history.
</ParamField>

Concurrent saves of one agent are serialised: two saves at once get two consecutive versions.

<ResponseExample>
  ```json 201 theme={null}
  {
    "version": { "id": "6f1c…", "versionMajor": 2, "versionMinor": 4, "sectionCount": 3 },
    "published": false
  }
  ```
</ResponseExample>

| Status | `error` | When |
| - | - | - |
| 400 | `UNKNOWN_PROMPT_TYPE` | A `promptType` that does not exist |
| 400 | `INSTANCED_TYPE_NOT_ADDRESSED` | An instanced type with no `instanceRef` |
| 400 | `INSTANCE_NOT_FOUND` | An `instanceRef` that is not an enabled custom tool of this agent |
| 400 | `INVALID_VARIABLE_NAMESPACE` | A `{{namespace.var}}` the section's type does not allow |
| 400 | `DUPLICATE_SECTION` | The same section twice in one save |
| 404 | — | No such agent |

***

## Publish a config version

<ParamField method="PUT" path="/api/bots/:id/prompt-live" />

Makes one of this agent's config versions what visitors hear. Moves the live pointer and changes nothing else.

<ParamField body="versionId" type="string">
  The config version to publish. **Clients should always send the id of the version they are showing**, so a version saved in another tab in between is never the one that goes live. When omitted, the newest version is published.
</ParamField>

<ResponseExample>
  ```json 200 theme={null}
  {
    "live": { "id": "6f1c…", "versionMajor": 2, "versionMinor": 4 },
    "previous": { "id": "93ab…", "versionMajor": 2, "versionMinor": 2 }
  }
  ```
</ResponseExample>

A `versionId` that belongs to another agent answers `404` and publishes nothing.

***

## List config versions

<ParamField method="GET" path="/api/bots/:id/prompt-config-versions" />

<ParamField query="limit" type="number" default="50">
  Newest-first page size, at most 200.
</ParamField>

<ResponseExample>
  ```json 200 theme={null}
  {
    "versions": [
      {
        "id": "6f1c…",
        "versionMajor": 2,
        "versionMinor": 4,
        "label": "Tightened the refusal wording",
        "createdAt": "2026-10-08T10:12:00.000Z",
        "createdBy": "c0ffee…",
        "authorName": "Sidd",
        "isLive": false,
        "isNewest": true
      }
    ],
    "live": {
      "id": "93ab…",
      "versionMajor": 2,
      "versionMinor": 2,
      "publishedAt": "2026-10-07T16:00:00.000Z",
      "publishedBy": "c0ffee…",
      "publishedByName": "Sidd"
    }
  }
  ```
</ResponseExample>

`live` is reported separately because the live version can be older than the page returned. It is `null` for an agent that has never published. `createdBy` and `publishedBy` are `null` for the `v1.0` every existing agent received when config versioning shipped, and for an author whose account has been deleted.

***

## Get one config version

<ParamField method="GET" path="/api/bots/:id/prompt-config-versions/:versionId" />

Returns the version and its `items` — one per customised section (`promptType`, `instanceRef`, `mode`, `content`, `prompt`). This is what the editor's **View** reads. It writes nothing: the editor shows the version read-only. **Restore as draft** then sends these items back through `POST /api/bots/:id/prompt-config-versions` as a new version (it does not publish).

***

## Related endpoints

* `GET /api/bots/:id/prompt-sections` — the editor's section model. Each section carries its draft text and `isUnpublished` (the draft differs from what the live version serves for it); the response also carries `draftDiffersFromNewest`.
* `POST /api/bots/:id/prompt-sections/:type/reset` — drop one section's draft override. A draft change: nothing live moves until the next Save and Publish.
* `PUT /api/bots/:id/prompt-configs/:type` — legacy single-section **draft** write. It records no version and publishes nothing.


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