Prerequisites
- A Scrunch API key with Responses access (provision one here)
- A brand ID for the brand you want to load
- A cloud data warehouse (BigQuery, Snowflake, Redshift, Databricks, etc.)
How the Responses API works
The Responses API returns one record per AI response. Each record includes the full response text, citations, brand and competitor evaluations, and prompt metadata. Key characteristics:- 1:1 response model — each item represents a single, distinct AI response
- Denormalized — arrays like
tags,key_topics,competitors,citations, andshopping_resultsare embedded in each record - Reverse chronological — newest responses are returned first
- Supports date filtering and pagination — ideal for incremental ETL
platform, brand_sentiment, brand_position, source_type) are returned as lowercase strings. stage and key_topics are the exception — they are returned as display-cased names.
For the full response schema, see the Responses API overview.
Incremental loading strategy
Use date windows and pagination to pull new responses on a recurring schedule.1
Choose your sync window
Use
start_date and end_date (both YYYY-MM-DD, UTC) to define a date range.start_date is inclusive and end_date is exclusive. To load a single UTC day, set end_date to the following day — start_date=2025-06-01&end_date=2025-06-02 returns exactly June 1. Treating end_date as inclusive is the most common cause of duplicated or missing days in a daily job.For daily loads, pull the previous UTC day after midnight to ensure completeness.2
Paginate through all results
The API returns paginated results. Increment The response includes a
offset by limit until you have all records for the window.total count so you know when you’re done:limit defaults to 100, so always set it explicitly for bulk loads. The minimum is 1 and no maximum is enforced — values well above 1000 are honored — but 1000 keeps individual requests cheap to retry. Keep offset a multiple of limit.3
Deduplicate on id
Each response has a globally unique integer
id. Use it as a natural key and upsert into your warehouse to handle re-runs or overlapping date windows.Some fields like
brand_present, brand_sentiment, tags, key_topics, and stage may be re-evaluated if prompt metadata or brand configuration changes in Scrunch. Always upsert rather than append-only. response_text, citations, and created_at are immutable — they record exactly what was observed.Narrowing the window
If you are backfilling a large history or building per-segment marts, these filters are available alongside the date range and reduce the volume you have to page through:Schema design
Each API record includes arrays (tags, key_topics, competitors, citations, shopping_results) that should be normalized into separate tables to avoid row explosion.
Responses fact table
Store one row per response with scalar fields:stage is not a fixed enum. Values resolve from the brand’s own configured stages, so they vary per brand and can be renamed or extended. The default sets are intent (Advice, Awareness, Evaluation, Comparison, Other) and funnel (Awareness, Consideration, Conversion, Loyalty, Other), but treat the column as free text and drive any stage dimension table off the values you actually observe rather than a hardcoded list.
Optional scalar and semi-structured columns
These fields are present on every record but are not needed by every mart:query_fanout is null for most rows on most platforms. Store it as a raw JSON or STRUCT column rather than modelling it into its own table until you know you need it.Bridge tables
Unnest each array into its own table, keyed byresponse_id.
response_tags
response_key_topics
tags and key_topics are distinct fields and are not interchangeable. Tags are arbitrary labels a user attaches to a prompt; key topics are Scrunch’s topic classification. Both hang off the prompt rather than the response, so both can change on re-evaluation.
response_citations
response_shopping_results
Only populated for responses carrying product listings. Filter the load with
has_shopping_data=true if this is all you need.
Computing metrics
Once your data mart is loaded, you can aggregate responses into daily performance summaries. Group onDATE(created_at), prompt_id, prompt, platform to match the way Scrunch reports prompt-level performance by default.
The following examples use PostgreSQL syntax. Translate as needed for your warehouse.
Response count
Brand presence percentage
Brand sentiment score
Brand position score
Both score metrics are averaged only over responses that mention the entity. The
ELSE NULL is doing that work: sentiment and position are null when the brand is absent, and AVG skips nulls. Keep the ELSE NULL — replacing it with a numeric default silently mixes non-mentions into the score.Citation rate
Citation metrics are domain-based and independent of whether the brand was mentioned by name. Compute them from theresponse_citations bridge table, taking care to count responses rather than citation rows:
Putting it together
Competitor metrics
Sentiment and position translate directly, but presence does not. Becauseresponse_competitors only holds mentions, its own row count is the wrong denominator — you have to divide by the total response count for the period, which comes from the responses table:
LEFT JOIN this result onto a date spine crossed with your competitor dimension.
The brand equivalent does not have this problem: brand_present is a column on every response row, so COUNT(*) over responses is already the right denominator.
Metrics you cannot reproduce from this API
A few dashboard metrics depend on data the Responses API does not expose. Compute these with the Query API instead of approximating them:brand_avg_rank/competitor_avg_rank— first-occurrence mention rank is not a field on the response record. Note thatposition(top/middle/bottom) is a thirds-of-the-response bucket, not a rank, and is not a substitute for it.- Share of voice — normalized across the full tracked set, so it is only correct if your mart holds every tracked competitor for the period.
brand_citation_mention_rate— depends on crawled page content of the cited URLs, which is not part of the response payload.
Related
Responses API Overview
Full schema, filtering, and pagination details.
Responses Quickstart
Make your first API call in cURL, Python, or JavaScript.