Skip to Content
APIEndpointsCreate topic

Create topic

Creates a topic. Pass parent_topic_id to create a subtopic instead — there is no separate subtopic endpoint, because a subtopic is just a topic with a parent.

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.

POST /v1/brands/{brand_id}/topics

Authorization

HeaderTypeRequired
AuthorizationBearer asky_sk_…required
Idempotency-Keystringrequired

Path parameters

ParameterTypeRequiredDescription
brand_iduuidrequiredFrom List brands

Query parameters

None.

Any parameter you pass returns 400 invalid_request naming the offending key, rather than being ignored silently.

Body

application/json

FieldTypeRequiredDescription
namestring, 1–64 charsrequiredMust be unique among its siblings. Leading and trailing whitespace is trimmed
parent_topic_iduuidoptionalOmit for a root topic. Must be a root topic in the same brand
descriptionstring, up to 500 charsoptional

Request

curl --request POST \ --url 'https://api.askylabs.com/v1/brands/242546de-4cee-4a7d-952e-f6aa60c63ef8/topics' \ --header 'Authorization: Bearer <api-key>' \ --header 'Idempotency-Key: <unique-per-attempt>' \ --header 'Content-Type: application/json' \ --data '{"name":"Answer engine optimisation","parent_topic_id":"4beb0694-7c2e-488b-84c1-613738e7eaf6"}'

Response

{ "data": { "topic": { "id": "5524d66a-df1e-47e4-9dbc-802af39235ad", "name": "Answer engine optimisation", "description": null, "parent_topic_id": "4beb0694-7c2e-488b-84c1-613738e7eaf6", "is_subtopic": true } }, "request_id": "req_7d21b0af59c34e18b6ac" }

Response fields

FieldTypeDescription
data.topic.iduuidrequired
data.topic.namestringrequired
data.topic.descriptionstring | nullrequired
data.topic.parent_topic_iduuid | nullrequired. null for a root topic
data.topic.is_subtopicbooleanrequired. Convenience for parent_topic_id !== null
request_idstringrequired. Also returned as the x-request-id header. Quote it when contacting support

Errors

StatusCodeWhen
400invalid_requestA parameter is unknown or malformed. The message names it
401invalid_tokenThe key is missing, malformed, or does not exist
401token_expiredThe key passed its expiry date
401token_revokedThe key was revoked
403insufficient_scopeThe key does not carry the scope this endpoint needs
403plan_requiredThis workspace is not enabled for API writes
404not_foundThe brand does not exist, or this key is not allowed to reach it. The two are deliberately indistinguishable
409conflictA sibling topic already has that name
429rate_limitedOver 60 requests per minute. See the Retry-After header

Notes

Names are unique per parent. Two subtopics of different parents may share a name; two siblings may not. A collision returns 409 conflict and changes nothing.

The tree is two levels deep. parent_topic_id must name a root topic, so you cannot create a sub-subtopic. The database schema would permit deeper nesting, but the app renders roots and their subtopics and nothing else, so a third level would be data no one could see or edit. Passing a subtopic returns 400 invalid_request saying so.

The new topic is returned in full, in the same shape List topics uses, so you can put it straight into a cache without a follow-up read.

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.

Last updated on