Manage competitors and the exact aliases that count as a mention, plus the suggestions drawn from real answers.
An entity is your brand or a competitor, together with the aliases, domains, exclusions and context terms that decide what counts as a mention of it, and the domains and YouTube channels whose pages and videos count as its citations.
Paths on this page are relative to https://shruwd.io/api/v1.
| Method | Path | Scope | Role |
|---|---|---|---|
GET | /brands/{brandId}/entities | read | viewer |
POST | /brands/{brandId}/entities | write | editor |
PUT | /entities/{entityId} | write | editor |
DELETE | /entities/{entityId} | write | editor |
Matching is exact
Every alias is matched as an exact string on word boundaries. The API does not accept patterns or regular expressions, and there is no fuzzy matching anywhere.
An alias that starts with a capital letter does not match where the answer writes it all in
lowercase ("a narrow arc" is not Arc), except inside code, where names are lowercase.
caseSensitive is stricter: the whole alias must match exactly as written.
A near-match that quietly counts the wrong brand corrupts every metric downstream and is close to impossible to detect later. The cost is that you supply the spellings.
Add a competitor
curl -X POST "https://shruwd.io/api/v1/brands/northwind/entities" \
-H "Authorization: Bearer $SHRUWD_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "Planwell",
"aliases": [{ "alias": "Planwell", "kind": "name", "caseSensitive": false }],
"domains": ["planwell.io"]
}'
| Field | Required | Notes |
|---|---|---|
name | Yes | The canonical name |
aliases | No | Defaults to one alias equal to name. Up to 50 |
domains | No | Reduced to registrable domains. Up to 20 |
channels | No | YouTube channels, as https://www.youtube.com/@name or @name. Up to 5 |
exclusions | No | Phrases that must not count as a mention. Up to 50 |
contextTerms | No | Required for short or common-word names — see below. Up to 50 |
Competitors only. isSelf is not accepted; the self entity arrives with the brand. A
brand tracks up to 100 companies, its own included; past that, 409 entity_limit.
Short and common-word names
A name or alias of six characters or fewer, or one on the common-word list, is refused
with 422 context_terms_required until you supply contextTerms; details.spelling says
which. The entity is then stored
with requires_context set, and its domains are added to the terms.
This is not a nicety to route around. Without context terms, "Arc" counts every ordinary use of the word as a competitor mention, and every share-of-voice number for the brand becomes wrong in a way nobody notices.
Your brand's own entity has the same rule: creating a brand with such a
name needs contextTerms too. An entity whose name needs them and has none reads back with
needsContextTerms: true; add them with PUT.
YouTube channels
Answers cite videos as well as pages, and a video's address says only youtube.com. Name a
company's channel and a cited video from it counts as that company's citation: for your
brand, in your own citation rate and as "Cited your video" on an answer. Give the channel's
address as YouTube shows it, https://www.youtube.com/@name, or the @name handle alone.
A /channel/UC… address is accepted too, but it matches only videos whose channel YouTube
reports the same way, and today that is the handle.
It counts from the answers measured after you name it. Answers already measured keep the credit they had, as they do when you add a domain.
Errors
| Code | Status | |
|---|---|---|
context_terms_required | 422 | The name needs context terms. The reason is in the body |
domain_taken | 409 | Another entity of this brand already owns that domain |
channel_taken | 409 | Another entity of this brand already has that YouTube channel |
invalid_alias · invalid_domain · invalid_channel · invalid_name | 422 | Bad input |
Replace an entity
PUT takes the desired state — the full set of aliases, domains, exclusions and
context terms you want.
curl -X PUT "https://shruwd.io/api/v1/entities/$entityId" \
-H "Authorization: Bearer $SHRUWD_API_KEY" \
-H "Content-Type: application/json" \
-d '{"name":"Planwell","aliases":[{"alias":"Planwell","kind":"name"},{"alias":"Plan Well","kind":"name"}],"domains":["planwell.io"],"channels":["https://www.youtube.com/@planwell"]}'
The server diffs against what exists: rows you dropped are closed as of now, new ones are inserted, unchanged ones are left alone. Nothing is ever edited in place, because a measurement taken yesterday must still resolve against yesterday's aliases.
YouTube channels are the one exception: leave channels out and they stay as they are;
send [] to remove them.
Remove an entity
curl -X DELETE "https://shruwd.io/api/v1/entities/$entityId" \
-H "Authorization: Bearer $SHRUWD_API_KEY"
Closes the entity as of now. It stops counting from the next cycle; past measurements keep it, and share of voice is recomputed against the remaining set.
The self entity is 409 self_entity — archive the brand instead.
Suggestions
Shruwd lists names that appeared in your answers but are not tracked.
| Method | Path | Scope |
|---|---|---|
GET | /brands/{brandId}/suggestions?state= | read |
POST | /suggestions/{suggestionId}/accept | write |
POST | /suggestions/{suggestionId}/dismiss | write |
Each carries the share of a prompt cluster's answers that named it, and a domain hint where the answers linked one.
Accept creates the competitor through the same path as POST …/entities — the same
exact-alias rule, the same context_terms_required check. Pass name, aliases,
domains, exclusions or contextTerms to override the draft; the domain hint is used
unless you give domains.
Dismiss quiets it for 90 days.
A suggestion that has already been decided is 409 suggestion_decided.
Next steps
- Measurement — reading mention rate and share of voice
- Competitors — the same thing in the dashboard

