Skip to Content
APIEndpointsDelete competitor

Delete competitor

Permanently removes a competitor and every measurement ever recorded against it. This is the most destructive call on the API. Read the warning below before using it.

Run it with ?dry_run=true first. That returns exactly what would be removed and removes nothing.

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

DELETE /v1/brands/{brand_id}/competitors/{competitor_id}

Authorization

HeaderTypeRequired
AuthorizationBearer asky_sk_…required
Idempotency-Keystringrequired

Path parameters

ParameterTypeRequiredDescription
brand_iduuidrequiredFrom List brands
competitor_iduuidrequiredFrom List competitors

Query parameters

ParameterTypeRequiredDescription
dry_runbooleanoptionalReport what would be deleted and delete nothing. Defaults to false

Request

# Always look first. curl --request DELETE \ --url 'https://api.askylabs.com/v1/brands/242546de-4cee-4a7d-952e-f6aa60c63ef8/competitors/c4a7e1b2-38d9-4f60-b5ac-2d90e7f14b83?dry_run=true' \ --header 'Authorization: Bearer <api-key>' \ --header 'Idempotency-Key: <unique-per-attempt>'

Response

{ "data": { "dry_run": true, "deleted": false, "competitor": { "id": "c4a7e1b2-38d9-4f60-b5ac-2d90e7f14b83", "name": "Semrush", "primary_url": "https://semrush.com", "domain": "semrush.com", "relation": "direct_competitor", "aliases": [], "is_active": true, "is_manual": true, "match_case_sensitive": false, "match_require_domain": false, "match_mode": "apex" }, "would_delete": { "executions": 19861, "prompt_analytics": 10734, "topic_analytics": 3445, "brand_analytics": 273, "domain_candidates": 0, "tag_assignments": 0, "total_rows": 34313 } }, "request_id": "req_5a1f0c8e37b14d92a6be" }

Response fields

FieldTypeDescription
data.dry_runbooleanrequired. Echoes what you asked for
data.deletedbooleanrequired. false on a dry run
data.competitorobjectrequired. The competitor, as Get competitor returns it. Captured before deletion
data.would_deleteobjectpresent on a dry run only
data.removedobjectpresent on a real delete only
…​.executionsintegerrequired. Per-execution mention records
…​.prompt_analyticsintegerrequired. Per-prompt rollups
…​.topic_analyticsintegerrequired. Per-topic rollups
…​.brand_analyticsintegerrequired. Per-brand rollups
…​.domain_candidatesintegerrequired. Discovered domains for this competitor
…​.tag_assignmentsintegerrequired. Tag links, the only cheap one to rebuild
…​.total_rowsintegerrequired. The sum, and the number worth reading
request_idstringrequired. Also returned as the x-request-id header

Errors

StatusCodeWhen
400invalid_requestdry_run is not a boolean, or an unknown query parameter was sent
401invalid_tokenThe key is missing, malformed, or does not exist
403insufficient_scopeThe key does not carry write:competitors
403plan_requiredThis workspace is not enabled for API writes
404not_foundThe brand or competitor does not exist, or this key is not allowed to reach it
429rate_limitedOver 60 requests per minute

Notes

This is not reversible and there is no soft delete. The competitor row and every cascading measurement are gone. There is no undo, no trash, and no export beforehand. On real data this is routinely tens of thousands of rows: a well-established competitor on an active brand carried 34,313 when we measured it.

It changes numbers you did not ask it to change. Share of voice is relative, so removing one competitor alters every remaining competitor’s historical share on that brand. Charts you have already looked at, screenshotted or reported will not match afterwards. This is the part people do not expect, and it is the main reason to prefer deactivating.

Deactivating is almost always what you want. PATCH with is_active: false (Update competitor) stops tracking the competitor from the next run onward and keeps every historical number intact and comparable. Use delete only when the competitor was genuinely a mistake, such as a duplicate or a typo, and its history is noise you want gone.

Idempotency-Key is required, including on dry runs. Reuse it when retrying an attempt and the original response is replayed rather than the delete running twice. See Idempotency.

Last updated on