Bulk remove tag from prompts
Removes one tag across up to 1000 prompts in a single call.
This is the inverse of Set prompt tags. That endpoint answers “what are this prompt’s tags” and replaces the whole set; this one answers “put this tag on these prompts” and touches nothing else. They are different operations and cannot share a URL — the other names a single prompt in its path.
Requires the write:tags scope, and the workspace must be enabled for API writes.
DELETE /v1/brands/{brand_id}/tags/{tag_id}/promptsAuthorization
| 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 |
tag_id | uuid | required | From List tags |
Query parameters
None.
Body
application/json
| Field | Type | Required | Description |
|---|---|---|---|
prompt_ids | uuid[], 1–1000 | required | From List prompts. Duplicates are collapsed |
All or nothing. Every id must name a prompt on this brand. If any does not, nothing is written and the error names the offenders (up to 20, with a count of the rest) so one round trip is enough to fix the list.
Request
cURL
curl --request DELETE \
--url 'https://api.askylabs.com/v1/brands/242546de-4cee-4a7d-952e-f6aa60c63ef8/tags/5524d66a-df1e-47e4-9dbc-802af39235ad/prompts' \
--header 'Authorization: Bearer <api-key>' \
--header 'Idempotency-Key: <unique-per-attempt>' \
--header 'Content-Type: application/json' \
--data '{"prompt_ids":["9f2c1d84-6b31-4a2e-9c77-1e5b0a3f8d42","3c8982b3-c287-4936-ba4a-346ad58a411c"]}'Response
200
{
"data": {
"tag_id": "5524d66a-df1e-47e4-9dbc-802af39235ad",
"requested": 224,
"removed": 224,
"not_present": 0
},
"request_id": "req_7d21b0af59c34e18b6ac"
}Response fields
Counts rather than objects. A bulk response echoing a thousand entities would be stored whole in the idempotency record on every attempt, so read the entities back if you need them.
| Field | Type | Description |
|---|---|---|
data.tag_id | uuid | required |
data.requested | integer | required. Ids after duplicates were collapsed |
data.removed | integer | required. prompts actually changed |
data.not_present | integer | required. Did not carry the tag; nothing to do |
request_id | string | required |
Errors
| Status | Code | When |
|---|---|---|
| 400 | invalid_request | prompt_ids missing, empty, over 1000, not uuids, or naming prompts outside this brand |
| 401 | invalid_token | The key is missing, malformed, or does not exist |
| 403 | insufficient_scope | The key does not carry write:tags |
| 404 | not_found | The brand or the tag does not exist, or this key is not allowed to reach it |
| 429 | rate_limited | Over 60 requests per minute |
Notes
Safe to repeat. Removes is idempotent against the unique (tag_id, prompt_id) index, so a retry
after a lost response changes nothing and reports removed: 0. That is also why the response
separates removed from not_present — you can tell a no-op from a failure.
Ids outside this brand are a 400, not a 404. The resource in the path is the tag; the ids
are payload, and payload that fails validation is a bad request. The path itself still returns a
bare 404 for anything you may not reach, so the tenancy boundary is unchanged.
Above 1000, page it yourself. The cap is deliberately conservative and will be reviewed against real traffic. Asynchronous submission for larger sets is not built yet.
Idempotency-Key is required. See Idempotency.