Skip to Content
APIEndpointsBulk operationsAdd tag to competitors

Bulk add tag to competitors

Applies one tag across up to 1000 competitors in a single call.

This is the inverse of Set competitor tags. That endpoint answers “what are this competitor’s tags” and replaces the whole set; this one answers “put this tag on these competitors” and touches nothing else. They are different operations and cannot share a URL — the other names a single competitor in its path.

Requires the write:tags scope, and the workspace must be enabled for API writes.

POST /v1/brands/{brand_id}/tags/{tag_id}/competitors

Authorization

HeaderTypeRequired
AuthorizationBearer asky_sk_…required
Idempotency-Keystringrequired

Path parameters

ParameterTypeRequiredDescription
brand_iduuidrequiredFrom List brands
tag_iduuidrequiredFrom List tags

Query parameters

None.

Body

application/json

FieldTypeRequiredDescription
competitor_idsuuid[], 1–1000requiredFrom List competitors. Duplicates are collapsed

All or nothing. Every id must name a competitor 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 --request POST \ --url 'https://api.askylabs.com/v1/brands/242546de-4cee-4a7d-952e-f6aa60c63ef8/tags/5524d66a-df1e-47e4-9dbc-802af39235ad/competitors' \ --header 'Authorization: Bearer <api-key>' \ --header 'Idempotency-Key: <unique-per-attempt>' \ --header 'Content-Type: application/json' \ --data '{"competitor_ids":["9f2c1d84-6b31-4a2e-9c77-1e5b0a3f8d42","3c8982b3-c287-4936-ba4a-346ad58a411c"]}'

Response

{ "data": { "tag_id": "5524d66a-df1e-47e4-9dbc-802af39235ad", "requested": 224, "applied": 224, "already_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.

FieldTypeDescription
data.tag_iduuidrequired
data.requestedintegerrequired. Ids after duplicates were collapsed
data.appliedintegerrequired. competitors actually changed
data.already_presentintegerrequired. Already carried the tag; left alone
request_idstringrequired

Errors

StatusCodeWhen
400invalid_requestcompetitor_ids missing, empty, over 1000, not uuids, or naming competitors outside this brand
401invalid_tokenThe key is missing, malformed, or does not exist
403insufficient_scopeThe key does not carry write:tags
404not_foundThe brand or the tag does not exist, or this key is not allowed to reach it
429rate_limitedOver 60 requests per minute

Notes

Safe to repeat. Applies is idempotent against the unique (tag_id, competitor_id) index, so a retry after a lost response changes nothing and reports applied: 0. That is also why the response separates applied from already_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.

Last updated on