---
title: "Taxonomies API reference"
canonical_url: https://zentrik.ai/docs/api/taxonomies
markdown_url: https://zentrik.ai/docs/api/taxonomies.md
last_reviewed: 2026-09-03
---

# Taxonomies API reference

Taxonomies are workspace-owned classification lenses for insights, ideas, and opportunities. Use these endpoints to read the current lens, validate proposed groups, iterate on drafts, preview AI assignments, publish reviewed changes, and refresh classifications with explicit guards.

- Human reference: https://zentrik.ai/docs/api/taxonomies
- Complete Markdown index: https://zentrik.ai/docs/api/index.md
- Base URL: `https://zentrik.ai/api`
- Authentication: `Authorization: Bearer YOUR_API_KEY`
- Shared pagination and rate limits: https://zentrik.ai/docs/api/index.md#shared-conventions

## GET /external/v1/taxonomies — List taxonomies

Operation ID: `list-taxonomies`

List taxonomy schemas in the current workspace, including active and draft version ids.

Required API key scopes: `taxonomies:read`

### Example request

```curl
curl -X GET https://zentrik.ai/api/external/v1/taxonomies \
  -H 'Authorization: Bearer YOUR_API_KEY'
```

### Responses

| Status | Meaning | Description | Schema |
| --- | --- | --- | --- |
| 200 | Success | Taxonomies were retrieved. | Array<Taxonomy> |

### Example response

```json
[
  {
    "id": "taxonomy-uuid",
    "name": "Customer decision lens",
    "status": "DRAFT",
    "activeVersionId": null,
    "draftVersionId": "taxonomy-version-uuid",
    "createdAt": "2026-07-05T10:00:00Z",
    "updatedAt": "2026-07-05T10:00:00Z",
    "usage": {
      "inUse": false
    }
  }
]
```

---

## GET /external/v1/taxonomies/current — Get active taxonomy

Operation ID: `get-current-taxonomy`

Read the active published taxonomy used for workspace classification. Returns null when nothing is published.

Required API key scopes: `taxonomies:read`

### Example request

```curl
curl -X GET https://zentrik.ai/api/external/v1/taxonomies/current \
  -H 'Authorization: Bearer YOUR_API_KEY'
```

### Responses

| Status | Meaning | Description | Schema |
| --- | --- | --- | --- |
| 200 | Success | The current taxonomy was returned, or null if none is published. | — |

### Example response

```json
{
  "taxonomySchemaId": "taxonomy-uuid",
  "taxonomyVersionId": "taxonomy-version-uuid",
  "groups": [
    {
      "id": "group-uuid",
      "key": "strategic_motion",
      "label": "Strategic motion",
      "description": "Product action implied by the evidence.",
      "displayOrder": 0,
      "selectionMode": "SINGLE",
      "appliesTo": [
        "INSIGHT"
      ],
      "aiManagedTargets": [
        "INSIGHT"
      ],
      "valueType": "LIST",
      "required": false,
      "options": [
        {
          "id": "option-uuid",
          "valueKey": "build",
          "label": "Build",
          "displayOrder": 0
        }
      ]
    }
  ]
}
```

---

## GET /external/v1/taxonomies/:id — Get one taxonomy

Operation ID: `get-taxonomy`

Read one taxonomy with active, draft, and historical versions.

Required API key scopes: `taxonomies:read`

### Parameters

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `id` | uuid | Yes | The taxonomy schema UUID. |

### Example request

```curl
curl -X GET https://zentrik.ai/api/external/v1/taxonomies/taxonomy-uuid \
  -H 'Authorization: Bearer YOUR_API_KEY'
```

### Responses

| Status | Meaning | Description | Schema |
| --- | --- | --- | --- |
| 200 | Success | The taxonomy was returned. | Taxonomy |
| 404 | Not Found | No taxonomy found with the provided id. | — |

### Example response

```json
{
  "id": "taxonomy-uuid",
  "name": "Customer decision lens",
  "status": "DRAFT",
  "activeVersionId": null,
  "createdAt": "2026-07-05T10:00:00Z",
  "updatedAt": "2026-07-05T10:00:00Z",
  "activeVersion": null,
  "draftVersion": {
    "id": "taxonomy-version-uuid",
    "versionNumber": 1,
    "status": "DRAFT",
    "revision": "revision-hash",
    "publishedAt": null,
    "createdAt": "2026-07-05T10:00:00Z",
    "updatedAt": "2026-07-05T10:00:00Z",
    "groups": [
      {
        "id": "group-uuid",
        "key": "strategic_motion",
        "label": "Strategic motion",
        "description": "Product action implied by the evidence.",
        "llmDescription": "Which product action should the team consider because of this evidence?",
        "selectionMode": "SINGLE",
        "appliesTo": [
          "INSIGHT"
        ],
        "aiManagedTargets": [
          "INSIGHT"
        ],
        "valueType": "LIST",
        "required": false,
        "displayOrder": 0,
        "options": [
          {
            "id": "option-uuid",
            "valueKey": "build",
            "label": "Build",
            "llmDescription": "Use when the evidence points to building or improving native product capability.",
            "parentValueKey": null,
            "displayOrder": 0
          }
        ]
      }
    ]
  },
  "versions": [],
  "usage": {
    "inUse": false
  }
}
```

---

## POST /external/v1/taxonomies/validate — Validate taxonomy design

Operation ID: `validate-taxonomy`

Validate proposed groups before writing. This is the safest first step for generated or migrated taxonomy specs.

Required API key scopes: `taxonomies:read`

### JSON request body

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `groups` | TaxonomyGroup[] | Yes | Full taxonomy group definitions. Group keys and option value keys should be stable snake_case identifiers; STRING groups still need an empty options array. |

### Example request

```json
{
  "groups": [
    {
      "id": "group-uuid",
      "key": "strategic_motion",
      "label": "Strategic motion",
      "description": "Product action implied by the evidence.",
      "llmDescription": "Which product action should the team consider because of this evidence?",
      "selectionMode": "SINGLE",
      "appliesTo": [
        "INSIGHT"
      ],
      "aiManagedTargets": [
        "INSIGHT"
      ],
      "valueType": "LIST",
      "required": false,
      "displayOrder": 0,
      "options": [
        {
          "id": "option-uuid",
          "valueKey": "build",
          "label": "Build",
          "llmDescription": "Use when the evidence points to building or improving native product capability.",
          "parentValueKey": null,
          "displayOrder": 0
        }
      ]
    }
  ]
}
```

### Responses

| Status | Meaning | Description | Schema |
| --- | --- | --- | --- |
| 200 | Success | Validation returned lint results without writing. | — |

### Example response

```json
{
  "hasBlockingErrors": false,
  "errors": [],
  "warnings": []
}
```

---

## POST /external/v1/taxonomies — Create a taxonomy draft

Operation ID: `create-taxonomy`

Create a taxonomy schema with an editable draft. Supply groups directly or clone an existing taxonomy.

Required API key scopes: `taxonomies:write`

### JSON request body

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `name` | string | Yes | Human-readable taxonomy name. |
| `cloneFromTaxonomyId` | uuid | No | Existing taxonomy to clone into the new draft. |
| `groups` | TaxonomyGroup[] | No | Initial draft groups. |

### Example request

```json
{
  "name": "Customer decision lens",
  "groups": [
    {
      "id": "group-uuid",
      "key": "strategic_motion",
      "label": "Strategic motion",
      "description": "Product action implied by the evidence.",
      "llmDescription": "Which product action should the team consider because of this evidence?",
      "selectionMode": "SINGLE",
      "appliesTo": [
        "INSIGHT"
      ],
      "aiManagedTargets": [
        "INSIGHT"
      ],
      "valueType": "LIST",
      "required": false,
      "displayOrder": 0,
      "options": [
        {
          "id": "option-uuid",
          "valueKey": "build",
          "label": "Build",
          "llmDescription": "Use when the evidence points to building or improving native product capability.",
          "parentValueKey": null,
          "displayOrder": 0
        }
      ]
    }
  ]
}
```

### Responses

| Status | Meaning | Description | Schema |
| --- | --- | --- | --- |
| 201 | Created | The taxonomy draft was created. | Taxonomy |

### Example response

```json
{
  "id": "taxonomy-uuid",
  "name": "Customer decision lens",
  "status": "DRAFT",
  "activeVersionId": null,
  "createdAt": "2026-07-05T10:00:00Z",
  "updatedAt": "2026-07-05T10:00:00Z",
  "activeVersion": null,
  "draftVersion": {
    "id": "taxonomy-version-uuid",
    "versionNumber": 1,
    "status": "DRAFT",
    "revision": "revision-hash",
    "publishedAt": null,
    "createdAt": "2026-07-05T10:00:00Z",
    "updatedAt": "2026-07-05T10:00:00Z",
    "groups": [
      {
        "id": "group-uuid",
        "key": "strategic_motion",
        "label": "Strategic motion",
        "description": "Product action implied by the evidence.",
        "llmDescription": "Which product action should the team consider because of this evidence?",
        "selectionMode": "SINGLE",
        "appliesTo": [
          "INSIGHT"
        ],
        "aiManagedTargets": [
          "INSIGHT"
        ],
        "valueType": "LIST",
        "required": false,
        "displayOrder": 0,
        "options": [
          {
            "id": "option-uuid",
            "valueKey": "build",
            "label": "Build",
            "llmDescription": "Use when the evidence points to building or improving native product capability.",
            "parentValueKey": null,
            "displayOrder": 0
          }
        ]
      }
    ]
  },
  "versions": [],
  "usage": {
    "inUse": false
  }
}
```

---

## PATCH /external/v1/taxonomies/:id/draft — Update taxonomy draft

Operation ID: `update-taxonomy-draft`

Replace the full draft name and/or groups. Prefer group and option endpoints for small iterative edits.

Required API key scopes: `taxonomies:write`

### Parameters

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `id` | uuid | Yes | The taxonomy schema UUID. |

### JSON request body

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `name` | string | No | Updated taxonomy name. |
| `groups` | TaxonomyGroup[] | No | Full replacement group list. |
| `expectedDraftRevision` | string | No | Current draft revision from readback. Use it for stale-write protection. |
| `dryRun` | boolean | No | When true, returns lint and diff without changing the draft. |

### Example request

```json
{
  "groups": [
    {
      "id": "group-uuid",
      "key": "strategic_motion",
      "label": "Strategic motion",
      "description": "Product action implied by the evidence.",
      "llmDescription": "Which product action should the team consider because of this evidence?",
      "selectionMode": "SINGLE",
      "appliesTo": [
        "INSIGHT"
      ],
      "aiManagedTargets": [
        "INSIGHT"
      ],
      "valueType": "LIST",
      "required": false,
      "displayOrder": 0,
      "options": [
        {
          "id": "option-uuid",
          "valueKey": "build",
          "label": "Build",
          "llmDescription": "Use when the evidence points to building or improving native product capability.",
          "parentValueKey": null,
          "displayOrder": 0
        }
      ]
    }
  ],
  "dryRun": true,
  "expectedDraftRevision": "revision-before"
}
```

### Responses

| Status | Meaning | Description | Schema |
| --- | --- | --- | --- |
| 200 | Success | Draft mutation result, lint, diff, and taxonomy readback were returned. | — |

### Example response

```json
{
  "dryRun": true,
  "baseDraftRevision": "revision-before",
  "draftRevision": "revision-after",
  "lint": {
    "hasBlockingErrors": false,
    "errors": [],
    "warnings": []
  },
  "diff": {
    "addedGroupKeys": [
      "strategic_motion"
    ],
    "removedGroupKeys": []
  },
  "taxonomy": {
    "id": "taxonomy-uuid",
    "name": "Customer decision lens",
    "status": "DRAFT",
    "activeVersionId": null,
    "createdAt": "2026-07-05T10:00:00Z",
    "updatedAt": "2026-07-05T10:00:00Z",
    "activeVersion": null,
    "draftVersion": {
      "id": "taxonomy-version-uuid",
      "versionNumber": 1,
      "status": "DRAFT",
      "revision": "revision-hash",
      "publishedAt": null,
      "createdAt": "2026-07-05T10:00:00Z",
      "updatedAt": "2026-07-05T10:00:00Z",
      "groups": [
        {
          "id": "group-uuid",
          "key": "strategic_motion",
          "label": "Strategic motion",
          "description": "Product action implied by the evidence.",
          "llmDescription": "Which product action should the team consider because of this evidence?",
          "selectionMode": "SINGLE",
          "appliesTo": [
            "INSIGHT"
          ],
          "aiManagedTargets": [
            "INSIGHT"
          ],
          "valueType": "LIST",
          "required": false,
          "displayOrder": 0,
          "options": [
            {
              "id": "option-uuid",
              "valueKey": "build",
              "label": "Build",
              "llmDescription": "Use when the evidence points to building or improving native product capability.",
              "parentValueKey": null,
              "displayOrder": 0
            }
          ]
        }
      ]
    },
    "versions": [],
    "usage": {
      "inUse": false
    }
  }
}
```

---

## PUT /external/v1/taxonomies/:id/draft/groups/:groupKey — Create or replace a draft group

Operation ID: `upsert-taxonomy-group`

Create or replace one draft group by key. Use dryRun first when iterating from an agent.

Required API key scopes: `taxonomies:write`

### Parameters

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `id` | uuid | Yes | The taxonomy schema UUID. |
| `groupKey` | string | Yes | Stable group key. |

### JSON request body

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `label` | string | No | Human-readable group label. |
| `description` | string | No | Optional human-facing description. |
| `llmDescription` | string | No | Decision question and evidence boundary the model uses for assignment. |
| `selectionMode` | enum | No | SINGLE or MULTI. |
| `appliesTo` | enum[] | No | Entity types where the field is available: INSIGHT, IDEA, OPPORTUNITY. |
| `aiManagedTargets` | enum[] | No | Entity types where AI should suggest values. |
| `valueType` | enum | No | LIST or STRING. |
| `required` | boolean | No | Whether the field should always have a value. |
| `options` | TaxonomyOption[] | No | Allowed values for LIST groups. |
| `expectedDraftRevision` | string | No | Current draft revision from readback. Use it for stale-write protection. |
| `dryRun` | boolean | No | When true, returns lint and diff without changing the draft. |

### Example request

```json
{
  "id": "group-uuid",
  "key": "strategic_motion",
  "label": "Strategic motion",
  "description": "Product action implied by the evidence.",
  "llmDescription": "Which product action should the team consider because of this evidence?",
  "selectionMode": "SINGLE",
  "appliesTo": [
    "INSIGHT"
  ],
  "aiManagedTargets": [
    "INSIGHT"
  ],
  "valueType": "LIST",
  "required": false,
  "displayOrder": 0,
  "options": [
    {
      "id": "option-uuid",
      "valueKey": "build",
      "label": "Build",
      "llmDescription": "Use when the evidence points to building or improving native product capability.",
      "parentValueKey": null,
      "displayOrder": 0
    }
  ],
  "dryRun": true
}
```

### Responses

| Status | Meaning | Description | Schema |
| --- | --- | --- | --- |
| 200 | Success | Group mutation result was returned. | — |

### Example response

```json
{
  "dryRun": true,
  "baseDraftRevision": "revision-before",
  "draftRevision": "revision-after",
  "lint": {
    "hasBlockingErrors": false,
    "errors": [],
    "warnings": []
  },
  "diff": {
    "addedGroupKeys": [
      "strategic_motion"
    ],
    "removedGroupKeys": []
  },
  "taxonomy": {
    "id": "taxonomy-uuid",
    "name": "Customer decision lens",
    "status": "DRAFT",
    "activeVersionId": null,
    "createdAt": "2026-07-05T10:00:00Z",
    "updatedAt": "2026-07-05T10:00:00Z",
    "activeVersion": null,
    "draftVersion": {
      "id": "taxonomy-version-uuid",
      "versionNumber": 1,
      "status": "DRAFT",
      "revision": "revision-hash",
      "publishedAt": null,
      "createdAt": "2026-07-05T10:00:00Z",
      "updatedAt": "2026-07-05T10:00:00Z",
      "groups": [
        {
          "id": "group-uuid",
          "key": "strategic_motion",
          "label": "Strategic motion",
          "description": "Product action implied by the evidence.",
          "llmDescription": "Which product action should the team consider because of this evidence?",
          "selectionMode": "SINGLE",
          "appliesTo": [
            "INSIGHT"
          ],
          "aiManagedTargets": [
            "INSIGHT"
          ],
          "valueType": "LIST",
          "required": false,
          "displayOrder": 0,
          "options": [
            {
              "id": "option-uuid",
              "valueKey": "build",
              "label": "Build",
              "llmDescription": "Use when the evidence points to building or improving native product capability.",
              "parentValueKey": null,
              "displayOrder": 0
            }
          ]
        }
      ]
    },
    "versions": [],
    "usage": {
      "inUse": false
    }
  }
}
```

---

## PATCH /external/v1/taxonomies/:id/draft/groups/:groupKey — Update a draft group

Operation ID: `patch-taxonomy-group`

Patch one draft group without replacing unrelated fields.

Required API key scopes: `taxonomies:write`

### Parameters

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `id` | uuid | Yes | The taxonomy schema UUID. |
| `groupKey` | string | Yes | Stable group key. |

### JSON request body

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `label` | string | No | Human-readable group label. |
| `description` | string | No | Optional human-facing description. |
| `llmDescription` | string | No | Decision question and evidence boundary the model uses for assignment. |
| `selectionMode` | enum | No | SINGLE or MULTI. |
| `appliesTo` | enum[] | No | Entity types where the field is available: INSIGHT, IDEA, OPPORTUNITY. |
| `aiManagedTargets` | enum[] | No | Entity types where AI should suggest values. |
| `valueType` | enum | No | LIST or STRING. |
| `required` | boolean | No | Whether the field should always have a value. |
| `options` | TaxonomyOption[] | No | Allowed values for LIST groups. |
| `expectedDraftRevision` | string | No | Current draft revision from readback. Use it for stale-write protection. |
| `dryRun` | boolean | No | When true, returns lint and diff without changing the draft. |

### Example request

```json
{
  "label": "Strategic motion",
  "dryRun": true
}
```

### Responses

| Status | Meaning | Description | Schema |
| --- | --- | --- | --- |
| 200 | Success | Group patch result was returned. | — |

### Example response

```json
{
  "dryRun": true,
  "baseDraftRevision": "revision-before",
  "draftRevision": "revision-after",
  "lint": {
    "hasBlockingErrors": false,
    "errors": [],
    "warnings": []
  },
  "diff": {
    "addedGroupKeys": [
      "strategic_motion"
    ],
    "removedGroupKeys": []
  },
  "taxonomy": {
    "id": "taxonomy-uuid",
    "name": "Customer decision lens",
    "status": "DRAFT",
    "activeVersionId": null,
    "createdAt": "2026-07-05T10:00:00Z",
    "updatedAt": "2026-07-05T10:00:00Z",
    "activeVersion": null,
    "draftVersion": {
      "id": "taxonomy-version-uuid",
      "versionNumber": 1,
      "status": "DRAFT",
      "revision": "revision-hash",
      "publishedAt": null,
      "createdAt": "2026-07-05T10:00:00Z",
      "updatedAt": "2026-07-05T10:00:00Z",
      "groups": [
        {
          "id": "group-uuid",
          "key": "strategic_motion",
          "label": "Strategic motion",
          "description": "Product action implied by the evidence.",
          "llmDescription": "Which product action should the team consider because of this evidence?",
          "selectionMode": "SINGLE",
          "appliesTo": [
            "INSIGHT"
          ],
          "aiManagedTargets": [
            "INSIGHT"
          ],
          "valueType": "LIST",
          "required": false,
          "displayOrder": 0,
          "options": [
            {
              "id": "option-uuid",
              "valueKey": "build",
              "label": "Build",
              "llmDescription": "Use when the evidence points to building or improving native product capability.",
              "parentValueKey": null,
              "displayOrder": 0
            }
          ]
        }
      ]
    },
    "versions": [],
    "usage": {
      "inUse": false
    }
  }
}
```

---

## DELETE /external/v1/taxonomies/:id/draft/groups/:groupKey — Delete a draft group

Operation ID: `delete-taxonomy-group`

Delete one draft group by key. Use dryRun and impact preview before removing classifications that may be in use.

Required API key scopes: `taxonomies:write`

### Parameters

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `id` | uuid | Yes | The taxonomy schema UUID. |
| `groupKey` | string | Yes | Stable group key. |
| `dryRun` | boolean | No | Return diff without deleting. |
| `expectedDraftRevision` | string | No | Current draft revision. |

### Example request

```curl
curl -X DELETE 'https://zentrik.ai/api/external/v1/taxonomies/taxonomy-uuid/draft/groups/strategic_motion?dryRun=true' \
  -H 'Authorization: Bearer YOUR_API_KEY'
```

### Responses

| Status | Meaning | Description | Schema |
| --- | --- | --- | --- |
| 200 | Success | Delete diff or mutation result was returned. | — |

### Example response

```json
{
  "dryRun": true,
  "baseDraftRevision": "revision-before",
  "draftRevision": "revision-after",
  "lint": {
    "hasBlockingErrors": false,
    "errors": [],
    "warnings": []
  },
  "diff": {
    "addedGroupKeys": [
      "strategic_motion"
    ],
    "removedGroupKeys": []
  },
  "taxonomy": {
    "id": "taxonomy-uuid",
    "name": "Customer decision lens",
    "status": "DRAFT",
    "activeVersionId": null,
    "createdAt": "2026-07-05T10:00:00Z",
    "updatedAt": "2026-07-05T10:00:00Z",
    "activeVersion": null,
    "draftVersion": {
      "id": "taxonomy-version-uuid",
      "versionNumber": 1,
      "status": "DRAFT",
      "revision": "revision-hash",
      "publishedAt": null,
      "createdAt": "2026-07-05T10:00:00Z",
      "updatedAt": "2026-07-05T10:00:00Z",
      "groups": [
        {
          "id": "group-uuid",
          "key": "strategic_motion",
          "label": "Strategic motion",
          "description": "Product action implied by the evidence.",
          "llmDescription": "Which product action should the team consider because of this evidence?",
          "selectionMode": "SINGLE",
          "appliesTo": [
            "INSIGHT"
          ],
          "aiManagedTargets": [
            "INSIGHT"
          ],
          "valueType": "LIST",
          "required": false,
          "displayOrder": 0,
          "options": [
            {
              "id": "option-uuid",
              "valueKey": "build",
              "label": "Build",
              "llmDescription": "Use when the evidence points to building or improving native product capability.",
              "parentValueKey": null,
              "displayOrder": 0
            }
          ]
        }
      ]
    },
    "versions": [],
    "usage": {
      "inUse": false
    }
  }
}
```

---

## PUT /external/v1/taxonomies/:id/draft/groups/:groupKey/options/:valueKey — Create or replace a draft option

Operation ID: `upsert-taxonomy-option`

Create or replace one option in a draft LIST group.

Required API key scopes: `taxonomies:write`

### Parameters

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `id` | uuid | Yes | The taxonomy schema UUID. |
| `groupKey` | string | Yes | Stable group key. |
| `valueKey` | string | Yes | Stable option key. |

### JSON request body

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `label` | string | No | Human-readable option label. |
| `llmDescription` | string | No | Boundary for when this option should be selected. |
| `parentValueKey` | string | No | Optional parent option key in the same group. |
| `displayOrder` | number | No | Sort order within the group. |
| `expectedDraftRevision` | string | No | Current draft revision from readback. Use it for stale-write protection. |
| `dryRun` | boolean | No | When true, returns lint and diff without changing the draft. |

### Example request

```json
{
  "id": "option-uuid",
  "valueKey": "build",
  "label": "Build",
  "llmDescription": "Use when the evidence points to building or improving native product capability.",
  "parentValueKey": null,
  "displayOrder": 0,
  "dryRun": true
}
```

### Responses

| Status | Meaning | Description | Schema |
| --- | --- | --- | --- |
| 200 | Success | Option mutation result was returned. | — |

### Example response

```json
{
  "dryRun": true,
  "baseDraftRevision": "revision-before",
  "draftRevision": "revision-after",
  "lint": {
    "hasBlockingErrors": false,
    "errors": [],
    "warnings": []
  },
  "diff": {
    "addedGroupKeys": [
      "strategic_motion"
    ],
    "removedGroupKeys": []
  },
  "taxonomy": {
    "id": "taxonomy-uuid",
    "name": "Customer decision lens",
    "status": "DRAFT",
    "activeVersionId": null,
    "createdAt": "2026-07-05T10:00:00Z",
    "updatedAt": "2026-07-05T10:00:00Z",
    "activeVersion": null,
    "draftVersion": {
      "id": "taxonomy-version-uuid",
      "versionNumber": 1,
      "status": "DRAFT",
      "revision": "revision-hash",
      "publishedAt": null,
      "createdAt": "2026-07-05T10:00:00Z",
      "updatedAt": "2026-07-05T10:00:00Z",
      "groups": [
        {
          "id": "group-uuid",
          "key": "strategic_motion",
          "label": "Strategic motion",
          "description": "Product action implied by the evidence.",
          "llmDescription": "Which product action should the team consider because of this evidence?",
          "selectionMode": "SINGLE",
          "appliesTo": [
            "INSIGHT"
          ],
          "aiManagedTargets": [
            "INSIGHT"
          ],
          "valueType": "LIST",
          "required": false,
          "displayOrder": 0,
          "options": [
            {
              "id": "option-uuid",
              "valueKey": "build",
              "label": "Build",
              "llmDescription": "Use when the evidence points to building or improving native product capability.",
              "parentValueKey": null,
              "displayOrder": 0
            }
          ]
        }
      ]
    },
    "versions": [],
    "usage": {
      "inUse": false
    }
  }
}
```

---

## PATCH /external/v1/taxonomies/:id/draft/groups/:groupKey/options/:valueKey — Update a draft option

Operation ID: `patch-taxonomy-option`

Patch one option without replacing unrelated fields.

Required API key scopes: `taxonomies:write`

### Parameters

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `id` | uuid | Yes | The taxonomy schema UUID. |
| `groupKey` | string | Yes | Stable group key. |
| `valueKey` | string | Yes | Stable option key. |

### JSON request body

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `label` | string | No | Human-readable option label. |
| `llmDescription` | string | No | Boundary for when this option should be selected. |
| `parentValueKey` | string | No | Optional parent option key in the same group. |
| `displayOrder` | number | No | Sort order within the group. |
| `expectedDraftRevision` | string | No | Current draft revision from readback. Use it for stale-write protection. |
| `dryRun` | boolean | No | When true, returns lint and diff without changing the draft. |

### Example request

```json
{
  "label": "Build",
  "dryRun": true
}
```

### Responses

| Status | Meaning | Description | Schema |
| --- | --- | --- | --- |
| 200 | Success | Option patch result was returned. | — |

### Example response

```json
{
  "dryRun": true,
  "baseDraftRevision": "revision-before",
  "draftRevision": "revision-after",
  "lint": {
    "hasBlockingErrors": false,
    "errors": [],
    "warnings": []
  },
  "diff": {
    "addedGroupKeys": [
      "strategic_motion"
    ],
    "removedGroupKeys": []
  },
  "taxonomy": {
    "id": "taxonomy-uuid",
    "name": "Customer decision lens",
    "status": "DRAFT",
    "activeVersionId": null,
    "createdAt": "2026-07-05T10:00:00Z",
    "updatedAt": "2026-07-05T10:00:00Z",
    "activeVersion": null,
    "draftVersion": {
      "id": "taxonomy-version-uuid",
      "versionNumber": 1,
      "status": "DRAFT",
      "revision": "revision-hash",
      "publishedAt": null,
      "createdAt": "2026-07-05T10:00:00Z",
      "updatedAt": "2026-07-05T10:00:00Z",
      "groups": [
        {
          "id": "group-uuid",
          "key": "strategic_motion",
          "label": "Strategic motion",
          "description": "Product action implied by the evidence.",
          "llmDescription": "Which product action should the team consider because of this evidence?",
          "selectionMode": "SINGLE",
          "appliesTo": [
            "INSIGHT"
          ],
          "aiManagedTargets": [
            "INSIGHT"
          ],
          "valueType": "LIST",
          "required": false,
          "displayOrder": 0,
          "options": [
            {
              "id": "option-uuid",
              "valueKey": "build",
              "label": "Build",
              "llmDescription": "Use when the evidence points to building or improving native product capability.",
              "parentValueKey": null,
              "displayOrder": 0
            }
          ]
        }
      ]
    },
    "versions": [],
    "usage": {
      "inUse": false
    }
  }
}
```

---

## DELETE /external/v1/taxonomies/:id/draft/groups/:groupKey/options/:valueKey — Delete a draft option

Operation ID: `delete-taxonomy-option`

Delete one option from a draft group. Use dryRun first to inspect the diff.

Required API key scopes: `taxonomies:write`

### Parameters

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `id` | uuid | Yes | The taxonomy schema UUID. |
| `groupKey` | string | Yes | Stable group key. |
| `valueKey` | string | Yes | Stable option key. |
| `dryRun` | boolean | No | Return diff without deleting. |

### Example request

```curl
curl -X DELETE 'https://zentrik.ai/api/external/v1/taxonomies/taxonomy-uuid/draft/groups/strategic_motion/options/build?dryRun=true' \
  -H 'Authorization: Bearer YOUR_API_KEY'
```

### Responses

| Status | Meaning | Description | Schema |
| --- | --- | --- | --- |
| 200 | Success | Delete diff or mutation result was returned. | — |

### Example response

```json
{
  "dryRun": true,
  "baseDraftRevision": "revision-before",
  "draftRevision": "revision-after",
  "lint": {
    "hasBlockingErrors": false,
    "errors": [],
    "warnings": []
  },
  "diff": {
    "addedGroupKeys": [
      "strategic_motion"
    ],
    "removedGroupKeys": []
  },
  "taxonomy": {
    "id": "taxonomy-uuid",
    "name": "Customer decision lens",
    "status": "DRAFT",
    "activeVersionId": null,
    "createdAt": "2026-07-05T10:00:00Z",
    "updatedAt": "2026-07-05T10:00:00Z",
    "activeVersion": null,
    "draftVersion": {
      "id": "taxonomy-version-uuid",
      "versionNumber": 1,
      "status": "DRAFT",
      "revision": "revision-hash",
      "publishedAt": null,
      "createdAt": "2026-07-05T10:00:00Z",
      "updatedAt": "2026-07-05T10:00:00Z",
      "groups": [
        {
          "id": "group-uuid",
          "key": "strategic_motion",
          "label": "Strategic motion",
          "description": "Product action implied by the evidence.",
          "llmDescription": "Which product action should the team consider because of this evidence?",
          "selectionMode": "SINGLE",
          "appliesTo": [
            "INSIGHT"
          ],
          "aiManagedTargets": [
            "INSIGHT"
          ],
          "valueType": "LIST",
          "required": false,
          "displayOrder": 0,
          "options": [
            {
              "id": "option-uuid",
              "valueKey": "build",
              "label": "Build",
              "llmDescription": "Use when the evidence points to building or improving native product capability.",
              "parentValueKey": null,
              "displayOrder": 0
            }
          ]
        }
      ]
    },
    "versions": [],
    "usage": {
      "inUse": false
    }
  }
}
```

---

## POST /external/v1/taxonomies/:id/preview — Preview AI assignments

Operation ID: `preview-taxonomy`

Run a non-persisted AI assignment preview against selected entities or a sample. Use this before publish.

Required API key scopes: `taxonomies:read`

### Parameters

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `id` | uuid | Yes | The taxonomy schema UUID. |

### JSON request body

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `entityType` | enum | No | INSIGHT, IDEA, or OPPORTUNITY. Defaults to INSIGHT. |
| `entityIds` | uuid[] | No | Specific entity ids to preview. |
| `insightIds` | uuid[] | No | Legacy insight id list for insight previews. |
| `sampleSize` | number | No | Number of representative entities to sample. |

### Example request

```json
{
  "entityType": "INSIGHT",
  "sampleSize": 5
}
```

### Responses

| Status | Meaning | Description | Schema |
| --- | --- | --- | --- |
| 200 | Success | Preview assignments and diagnostics were returned. | — |

### Example response

```json
{
  "taxonomyId": "taxonomy-uuid",
  "sampleSize": 5,
  "results": [],
  "previewReport": {
    "sampleSize": 5,
    "groups": []
  }
}
```

---

## POST /external/v1/taxonomies/:id/impact-preview — Preview publish impact

Operation ID: `impact-preview-taxonomy`

Inspect publish impact, including changed groups, removed options, and affected classifications.

Required API key scopes: `taxonomies:read`

### Parameters

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `id` | uuid | Yes | The taxonomy schema UUID. |

### Example request

```curl
curl -X POST https://zentrik.ai/api/external/v1/taxonomies/taxonomy-uuid/impact-preview \
  -H 'Authorization: Bearer YOUR_API_KEY'
```

### Responses

| Status | Meaning | Description | Schema |
| --- | --- | --- | --- |
| 200 | Success | Impact preview was returned. | — |

### Example response

```json
{
  "taxonomyId": "taxonomy-uuid",
  "totalInsights": 42,
  "impactedInsights": 0,
  "changedGroups": [
    "strategic_motion"
  ],
  "removedOptions": [],
  "changedOptions": [],
  "hasDraft": true
}
```

---

## POST /external/v1/taxonomies/:id/publish — Publish taxonomy

Operation ID: `publish-taxonomy`

Publish the current draft as the active taxonomy. This requires explicit confirmation and a draft revision guard.

Required API key scopes: `taxonomies:publish`

### Parameters

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `id` | uuid | Yes | The taxonomy schema UUID. |

### JSON request body

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `confirmation` | string | Yes | Must be PUBLISH_TAXONOMY. |
| `expectedDraftVersionId` | uuid | No | Draft version id from readback. |
| `expectedDraftRevision` | string | No | Draft revision from readback. |
| `skipPreviewJustification` | string | No | Operator justification when intentionally bypassing preview. |

### Example request

```json
{
  "confirmation": "PUBLISH_TAXONOMY",
  "expectedDraftRevision": "revision-after"
}
```

### Responses

| Status | Meaning | Description | Schema |
| --- | --- | --- | --- |
| 200 | Published | The taxonomy was published. | Taxonomy |

### Example response

```json
{
  "id": "taxonomy-uuid",
  "name": "Customer decision lens",
  "status": "PUBLISHED",
  "activeVersionId": "taxonomy-version-uuid",
  "createdAt": "2026-07-05T10:00:00Z",
  "updatedAt": "2026-07-05T10:00:00Z",
  "activeVersion": {
    "id": "taxonomy-version-uuid",
    "versionNumber": 1,
    "status": "DRAFT",
    "revision": "revision-hash",
    "publishedAt": null,
    "createdAt": "2026-07-05T10:00:00Z",
    "updatedAt": "2026-07-05T10:00:00Z",
    "groups": [
      {
        "id": "group-uuid",
        "key": "strategic_motion",
        "label": "Strategic motion",
        "description": "Product action implied by the evidence.",
        "llmDescription": "Which product action should the team consider because of this evidence?",
        "selectionMode": "SINGLE",
        "appliesTo": [
          "INSIGHT"
        ],
        "aiManagedTargets": [
          "INSIGHT"
        ],
        "valueType": "LIST",
        "required": false,
        "displayOrder": 0,
        "options": [
          {
            "id": "option-uuid",
            "valueKey": "build",
            "label": "Build",
            "llmDescription": "Use when the evidence points to building or improving native product capability.",
            "parentValueKey": null,
            "displayOrder": 0
          }
        ]
      }
    ]
  },
  "draftVersion": {
    "id": "taxonomy-version-uuid",
    "versionNumber": 1,
    "status": "DRAFT",
    "revision": "revision-hash",
    "publishedAt": null,
    "createdAt": "2026-07-05T10:00:00Z",
    "updatedAt": "2026-07-05T10:00:00Z",
    "groups": [
      {
        "id": "group-uuid",
        "key": "strategic_motion",
        "label": "Strategic motion",
        "description": "Product action implied by the evidence.",
        "llmDescription": "Which product action should the team consider because of this evidence?",
        "selectionMode": "SINGLE",
        "appliesTo": [
          "INSIGHT"
        ],
        "aiManagedTargets": [
          "INSIGHT"
        ],
        "valueType": "LIST",
        "required": false,
        "displayOrder": 0,
        "options": [
          {
            "id": "option-uuid",
            "valueKey": "build",
            "label": "Build",
            "llmDescription": "Use when the evidence points to building or improving native product capability.",
            "parentValueKey": null,
            "displayOrder": 0
          }
        ]
      }
    ]
  },
  "versions": [],
  "usage": {
    "inUse": false
  }
}
```

---

## POST /external/v1/taxonomies/:id/reclassify — Start classification run

Operation ID: `reclassify-taxonomy`

Start a targeted or full classification run. Targeted runs can use entityIds; full runs require explicit confirmation.

Required API key scopes: `classification-runs:write`

### Parameters

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `id` | uuid | Yes | The taxonomy schema UUID. |

### JSON request body

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `mode` | enum | No | TARGETED, ENTITY_IDS, INSIGHT_IDS, or FULL. |
| `entityType` | enum | No | INSIGHT, IDEA, or OPPORTUNITY. |
| `entityIds` | uuid[] | No | Specific entity ids for targeted runs. |
| `insightIds` | uuid[] | No | Legacy insight id list. |
| `confirmation` | string | No | FULL runs require RECLASSIFY_TAXONOMY_FULL. |
| `expectedTaxonomyVersionId` | uuid | No | Published taxonomy version id for full-run guard. |

### Example request

```json
{
  "mode": "TARGETED",
  "entityType": "INSIGHT",
  "entityIds": [
    "insight-uuid"
  ]
}
```

### Responses

| Status | Meaning | Description | Schema |
| --- | --- | --- | --- |
| 201 | Queued | The classification run was queued. | ClassificationRun |

### Example response

```json
{
  "id": "classification-run-uuid",
  "taxonomySchemaId": "taxonomy-uuid",
  "taxonomyVersionId": "taxonomy-version-uuid",
  "mode": "TARGETED",
  "entityType": "INSIGHT",
  "status": "PENDING",
  "totalItems": 5,
  "processedItems": 0,
  "autoAppliedItems": 0,
  "needsReviewItems": 0,
  "failedItems": 0,
  "requestedById": null,
  "metadata": null,
  "failedReason": null,
  "startedAt": null,
  "completedAt": null,
  "createdAt": "2026-07-05T10:00:00Z",
  "updatedAt": "2026-07-05T10:00:00Z"
}
```

---

## GET /external/v1/classification-runs/:runId — Get classification run

Operation ID: `get-classification-run`

Poll a classification run until it completes or fails.

Required API key scopes: `classification-runs:read`

### Parameters

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `runId` | uuid | Yes | The classification run UUID. |

### Example request

```curl
curl -X GET https://zentrik.ai/api/external/v1/classification-runs/classification-run-uuid \
  -H 'Authorization: Bearer YOUR_API_KEY'
```

### Responses

| Status | Meaning | Description | Schema |
| --- | --- | --- | --- |
| 200 | Success | The run state was returned. | ClassificationRun |

### Example response

```json
{
  "id": "classification-run-uuid",
  "taxonomySchemaId": "taxonomy-uuid",
  "taxonomyVersionId": "taxonomy-version-uuid",
  "mode": "TARGETED",
  "entityType": "INSIGHT",
  "status": "PENDING",
  "totalItems": 5,
  "processedItems": 0,
  "autoAppliedItems": 0,
  "needsReviewItems": 0,
  "failedItems": 0,
  "requestedById": null,
  "metadata": null,
  "failedReason": null,
  "startedAt": null,
  "completedAt": null,
  "createdAt": "2026-07-05T10:00:00Z",
  "updatedAt": "2026-07-05T10:00:00Z"
}
```

---

## GET /external/v1/classification-queue — List classification queue

Operation ID: `list-classification-queue`

List classification review work for the workspace.

Required API key scopes: `classification-queue:read`

### Parameters

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `limit` | number | No | Maximum number of queue items to return. |
| `offset` | number | No | Number of queue items to skip. |
| `productId` | uuid | No | Filter by product. |
| `reviewStatuses` | string | No | Comma-separated review statuses. |

### Example request

```curl
curl -X GET 'https://zentrik.ai/api/external/v1/classification-queue?limit=20' \
  -H 'Authorization: Bearer YOUR_API_KEY'
```

### Responses

| Status | Meaning | Description | Schema |
| --- | --- | --- | --- |
| 200 | Success | Classification queue items were returned. | — |

### Example response

```json
{
  "items": [],
  "total": 0,
  "limit": 20,
  "offset": 0
}
```
