It is most commonly used by:
- Agencies onboarding dozens or hundreds of clients
- Enterprise teams automating persona and keyword setup
- Internal tools (brand creation, batch updates, auditing)
What you can configure
Brands
- Name, alternative names
- Website + alternative websites
- Competitors
- Personas
- Key topics
Prompts
- Text
- Stage
- Tags
- Personas
- Platforms
Example: Create a brand
Case-sensitive name matching
By default, Scrunch matches brand and competitor names against AI responses case-insensitively, so"spirit airlines", "Spirit Airlines", and "SPIRIT AIRLINES" all count as mentions. For names that are common words, acronyms, or stylized in a specific case (for example, NeXT or LUSH), enable case-sensitive matching to avoid false positives.
Set case_sensitive: true on a brand or competitor to require exact-case matches for name and alternative_names. The flag defaults to false and is available on:
POST /brands— on the brand body and on each entry incompetitors[]PATCH /brands/{brand_id}— on the brand and on each competitor in the replacement listPOST /brands/{brand_id}/competitorsandPUT /brands/{brand_id}/competitors/{competitor_id}GETresponses for brands and competitors return the current value
Changing
case_sensitive on an existing brand triggers a re-evaluation of historical responses against the new matching rule.Domain uniqueness across brand and competitors
Each domain can only be classified one way within a brand — either as the brand’s own or as one specific competitor’s. This keeps citation owner classification (brand / competitor / other) deterministic.
Scrunch normalizes every configured URL by stripping the scheme, www., query, fragment, and trailing slash, and lowercasing it. The brand’s primary website is compared by domain only, while alternative_websites and competitor websites keep their path — so example.com/a and example.com/b on two different owners do not conflict. If a write would assign the same normalized domain to two different owners (for example, the brand’s website and a competitor’s websites, or two competitors), the request is rejected with HTTP 409 and a detail describing where the domain is already used. The check applies to:
POST /brandsandPATCH /brands/{brand_id}(brandwebsite,alternative_websites, and the replacementcompetitors[])POST /brands/{brand_id}/competitorsandPUT /brands/{brand_id}/competitors/{competitor_id}
Asynchronous website validation
After a write commits, Scrunch checks each new or changed website URL in the background. The checks confirm that the hostname resolves to a public address and that the page responds over HTTP. These checks are advisory. They never delay, reject, or roll back a structurally valid save, so your API response is unaffected. Background checks run for URLs submitted through:POST /brandsandPATCH /brands/{brand_id}(brandwebsite,alternative_websites, and competitorwebsitesin the replacement list)POST /brands/{brand_id}/competitorsandPUT /brands/{brand_id}/competitors/{competitor_id}(websites)
401, 403, or 429) do not create a warning. Sites often return these codes to automated clients while remaining reachable in a browser, so they do not indicate that the URL is invalid. If a run contains both blocked-access results and other failures, the notification reports only the other failures.
URL-validation warnings are independent of brand-performance notification preferences and cannot be disabled by those settings.
Alternative names limit
Each brand and competitor accepts up to 100 entries inalternative_names. Submitting more returns a 422 Unprocessable Entity with the message:
alternative_names, including:
POST /v1/brandsandPATCH /v1/brands/{brand_id}(brand body and each competitor)POST /v1/brands/{brand_id}/competitorsandPUT /v1/brands/{brand_id}/competitors/{competitor_id}
Excluded names
Useexcluded_names to list phrases that should never count as a mention of a brand or competitor, even when the phrase contains a configured name as a word. This lets a brand named Caliber match Caliber Collision while ignoring unrelated entities like Caliber Car Wash or Caliber Fitness.
Scrunch blanks every word-boundary occurrence of each excluded phrase before searching the response for this entity’s names. Position and other span-based metrics are unaffected because masked spans are replaced with equal-length whitespace. Historical responses are re-evaluated when excluded_names changes, so metrics update without a manual backfill.
excluded_names is a list of strings and is available on:
POST /v1/brands— on the brand body and on each entry incompetitors[]PATCH /v1/brands/{brand_id}— on the brand and on each competitor in the replacement listPOST /v1/brands/{brand_id}/competitorsandPUT /v1/brands/{brand_id}/competitors/{competitor_id}GETresponses for brands and competitors return the current value
excluded_names. Submitting more returns a 422 Unprocessable Entity with:
name or any of its alternative_names, since either would remove every mention of the entity. Remove the alternative name instead of excluding it. The check runs after Scrunch normalizes punctuation, so Caliber. and Caliber are treated as the same phrase.
Example: Add a prompt
Tag name limit
Each entry in a prompt’stags array is limited to 64 characters. Submitting a longer tag name to POST /{brand_id}/prompts returns a 400 Bad Request with a structured detail object:
Duplicate prompt text
POST /{brand_id}/prompts checks the new text against the brand’s existing prompts. The outcome depends on the existing prompt’s status:
-
Active duplicate — returns
400 Bad Requestwith the messagePrompt already exists. -
Paused duplicate — returns
400 Bad Requestwith a structureddetailobject identifying the paused prompt, so you can resume it instead of creating a copy: - Archived duplicate — reactivates the archived prompt instead of returning an error.
Listing prompts
GET /{brand_id}/prompts returns active prompts by default. Pass the status query parameter to include paused or archived prompts:
Any other value returns a
422 Unprocessable Entity rather than an empty list.
branded—trueif the prompt mentions the brandfavorite—trueif marked as a favorite in the dashboardstatus—active,paused, orarchived
platforms and variants reflect the prompt’s active variants. Pausing never changes them, so they show what a resume would collect again.
GET /{brand_id}/prompts/{prompt_id} returns archived prompts as well, so check the status field if you only want active ones.
Pausing and resuming prompts
PATCH /{brand_id}/prompts/{prompt_id} moves a prompt between active and paused. It requires the configure scope, and status is the only field the body accepts.
GET /{brand_id}/prompts?status=paused.
Resuming restores the exact deployment the prompt had when it was paused. Scrunch re-checks the prompt pool first, so a resume can return 429 with a quota_exceeded error when the organization no longer has room for the prompt’s variants.
Both transitions are idempotent: a prompt already in the requested status returns 200 with the prompt, unchanged. archived is not accepted as a target status; archive a prompt with DELETE /{brand_id}/prompts/{prompt_id} instead.
A transition the prompt’s current state does not allow returns 409 with a detail.type naming the reason:
A
503 with detail.type of pause_failed or resume_failed means the transition did not complete. Retry the request.
Archiving a persona pauses its prompts
Archiving a persona pauses its active custom prompts instead of archiving them. Collection and billing stop, but the prompts’ collected history stays visible on the Responses and Query APIs. The paused prompts appear understatus=paused in the prompt listing.
This applies to every path that archives a persona:
DELETE /brands/{brand_id}/personas/{persona_id}PATCH /brands/{brand_id}when thepersonasreplace-list omits an existing persona
Reusing an archived persona name
When youPATCH /brands/{brand_id} with personas, the list represents the full desired state: existing personas not included are archived.
If you later submit a persona without an id and the name matches a previously archived persona on the same brand, Scrunch reactivates the archived record instead of failing on the unique-name constraint. Its status returns to active and the description is replaced with the value you provide.
Budget Traveler was previously archived on this brand, the call reactivates that persona and updates its description. To update an existing active persona instead, include its id.
Persona limits when creating a brand
POST /brands accepts an optional personas array. Each plan caps how many personas you can attach to a single brand. If the array is longer than your plan allows, the request is rejected before the brand is created — no partial brand is saved.
When the limit is exceeded, the API returns 429 Too Many Requests with a quota_exceeded error:
personas array to limit entries or fewer and retry the request. To find your plan’s limit, inspect the limit field in the error response or contact your account team.
Notes
To update prompt text, delete the old prompt and create a new one. Only tags and platforms can be updated in-place.
See all configuration endpoints
Explore the API reference →