# Entities API 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. 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. 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 ```bash curl -X POST "https://shruwd.io/api/v1/brands/waitlister/entities" \ -H "Authorization: Bearer $SHRUWD_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "name": "LaunchList", "aliases": [{ "alias": "LaunchList", "kind": "name", "caseSensitive": false }], "domains": ["getlaunchlist.com"] }' ``` | Field | Required | Notes | |---|---|---| | `name` | Yes | The canonical name | | `aliases` | No | Defaults to one alias equal to `name` | | `domains` | No | Reduced to registrable domains | | `exclusions` | No | Phrases that must not count as a mention | | `contextTerms` | No | Required for short or common-word names — see below | Competitors only. `isSelf` is not accepted; the self entity arrives with the brand. ### Short and common-word names A name of six characters or fewer, or one on the common-word list, is refused with `422 context_terms_required` until you supply `contextTerms`. The entity is then stored with `requires_context` set. > **Warning** > > 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](https://shruwd.io/docs/api/brands.md) 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`. ### 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 | | `invalid_alias` · `invalid_domain` · `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. ```bash curl -X PUT "https://shruwd.io/api/v1/entities/$entityId" \ -H "Authorization: Bearer $SHRUWD_API_KEY" \ -H "Content-Type: application/json" \ -d '{"name":"LaunchList","aliases":[{"alias":"LaunchList","kind":"name"},{"alias":"Launch List","kind":"name"}],"domains":["getlaunchlist.com"]}' ``` 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. ## Remove an entity ```bash 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](https://shruwd.io/docs/api/measurement.md) — reading mention rate and share of voice - [Competitors](https://shruwd.io/docs/tracking/competitors.md) — the same thing in the dashboard