Update topic
Renames a topic, changes its description, or re-parents it. All three are reversible.
Moving a topic is parent_topic_id on this endpoint, not a separate action. Set it to null
to promote a subtopic to a root.
Requires the write:topics scope, and the workspace must be enabled for API writes. Topics are
their own scope rather than part of write:prompts because the blast radius is not comparable:
a topic sits above the prompts beneath it, so changing one reaches its whole subtree.
PATCH /v1/brands/{brand_id}/topics/{topic_id}Authorization
| Header | Type | Required |
|---|---|---|
Authorization | Bearer asky_sk_… | required |
Idempotency-Key | string | required |
Path parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
brand_id | uuid | required | From List brands |
topic_id | uuid | required | From List topics |
Query parameters
None.
Any parameter you pass returns 400 invalid_request naming the offending key, rather than being
ignored silently.
Body
application/json
| Field | Type | Required | Description |
|---|---|---|---|
name | string, 1–64 chars | optional | |
parent_topic_id | uuid | null | optional | null promotes the topic to a root. Its prompts move with it |
description | string | null | optional | null clears it |
Request
cURL
curl --request PATCH \
--url 'https://api.askylabs.com/v1/brands/242546de-4cee-4a7d-952e-f6aa60c63ef8/topics/4beb0694-7c2e-488b-84c1-613738e7eaf6' \
--header 'Authorization: Bearer <api-key>' \
--header 'Idempotency-Key: <unique-per-attempt>' \
--header 'Content-Type: application/json' \
--data '{"name":"AI visibility tracking"}'Response
200
{
"data": {
"topic": {
"id": "4beb0694-7c2e-488b-84c1-613738e7eaf6",
"name": "AI visibility tracking",
"description": null,
"parent_topic_id": null,
"is_subtopic": false
}
},
"request_id": "req_7d21b0af59c34e18b6ac"
}Response fields
| Field | Type | Description |
|---|---|---|
data.topic.id | uuid | required |
data.topic.name | string | required |
data.topic.description | string | null | required |
data.topic.parent_topic_id | uuid | null | required. null for a root topic |
data.topic.is_subtopic | boolean | required. Convenience for parent_topic_id !== null |
request_id | string | required. Also returned as the x-request-id header. Quote it when contacting support |
Errors
| Status | Code | When |
|---|---|---|
| 400 | invalid_request | A parameter is unknown or malformed. The message names it |
| 401 | invalid_token | The key is missing, malformed, or does not exist |
| 401 | token_expired | The key passed its expiry date |
| 401 | token_revoked | The key was revoked |
| 403 | insufficient_scope | The key does not carry the scope this endpoint needs |
| 403 | plan_required | This workspace is not enabled for API writes |
| 404 | not_found | The brand does not exist, or this key is not allowed to reach it. The two are deliberately indistinguishable |
| 409 | conflict | A sibling topic already has that name |
| 429 | rate_limited | Over 60 requests per minute. See the Retry-After header |
Notes
Send at least one field. An empty body returns 400 invalid_request rather than a
no-op success, so a client bug that drops the payload is visible instead of silent.
Omitting a field leaves it alone; sending null clears it. That distinction is why this
is a PATCH and why there is no PUT on this API: a PUT that cleared everything you did not
mention would be a data-loss bug wearing the right verb.
Prompts and subtopics move with the topic. Nothing is detached and nothing is deleted.
A topic that has subtopics cannot be moved under another topic, because its children would land on a third level. Promote or move the subtopics first. Promoting a subtopic to a root is always allowed.
Idempotency-Key is required. Send a unique value per attempt and reuse it when retrying
that attempt: a retry replays the original response instead of executing again, which is what
stops a lost response from becoming a duplicate. See Idempotency.