API: LLMPulse
Build dashboards, ETL pipelines and automations with a clean, well-typed API.
LLM Pulse is an AI visibility analytics platform that monitors how your brand appears in AI-generated responses from ChatGPT, Perplexity, Gemini, and other LLMs. The API gives you programmatic access to all your visibility data, including brand mentions, citation sources, sentiment analysis, and share of voice metrics. Use it to build custom dashboards, automate reports, or integrate AI visibility tracking into your existing tools.
Authentication
Use a Bearer token from your API Key.
Authorization: Bearer YOUR_API_KEY
Base URL
Use this base URL for all endpoints below. Examples already include the full path.
https://api.llmpulse.ai/api/v1
Using an AI agent? Read the llms.txt
We serve a machine-readable version of these docs so coding agents (Claude Code, Cursor, ChatGPT, etc.) can find the right endpoint without parsing this page.
/api-docs/llms.txt : short index, generated from the live route table.
/api-docs/llms-full.txt : full reference (every endpoint, every parameter).
100% UI-to-API parity, found a gap? We''ll close it
We aim for 100% UI-to-API parity, anything you can see in the LLM Pulse dashboard should be reachable through the API. If you find a gap, report it and we commit to implementing it, typically within hours to a few days.
Quick start
The logical flow is: list resources → (optionally) fetch dimensions → query metrics. The first call to /dimensions/projects already validates your API key.
- List your projects:
GET /dimensions/projects - (Optional) Fetch project dimensions (competitors, models, locales, tags)
- Request metrics under
/metrics/*
Official CLI & SDKs
Use the native CLI from a terminal or add a typed SDK to your application. Both cover all 71 documented REST operations and work with the same API keys and base URL shown in this reference.
Rust CLI
A native Rust client for macOS, Linux, and Windows with named profiles plus JSON, table, and CSV output. Use it for quick checks, shell scripts, scheduled exports, and CI jobs.
SDKs for 12 languages
Official generated clients for TypeScript, Python, Go, Java, Kotlin, C#, PHP, Ruby, Rust, Swift, Dart, and R. Each client stays aligned with the published OpenAPI document.
API Playground
API Playground
curl -X GET "https://api.llmpulse.ai/api/v1/ping" -H "Authorization: Bearer YOUR_API_KEY"
Response will appear here...
Sign up to get your API key and start testing
Get API KeyAuthentication
Send your key in the Authorization header as a Bearer token. Rotate/revoke under Settings → API Keys.
Missing or malformed headers return 401 ERR_MISSING_AUTH. Unknown keys return 401 ERR_INVALID_API_KEY. Revoked keys return 403 ERR_REVOKED_API_KEY.
Each call runs in the context of the API key’s user. Projects must belong to that user; otherwise 404 ERR_PROJECT_NOT_FOUND.
Versioning & Rate limits
Current version: v1. Future breaking changes will bump the path (e.g. /api/v2).
Rate limiting: 300 requests per minute per API key. Contact us for higher quotas.
Metrics endpoints support conditional GET (ETag/Last-Modified); see Cache & Conditional GET.
Dimensions endpoints
GET/dimensions/projects
Lists the authenticated user’s projects (this is also an auth check).
GET/dimensions/competitors
Lists competitors for the project.
GET/dimensions/collections
Lists collections (Tags) belonging to the project.
GET/dimensions/tags
Alias for /dimensions/collections. Returns the same payload, but named as tags for consistency with the UI.
GET/dimensions/models
Lists models present in daily metrics for the project.
GET/dimensions/locales
Lists countries and languages present in daily metrics for the project.
GET/dimensions/sentiments
(Optional) Lists available sentiment buckets and their metric names.
project_idrequired
GET/dimensions/prompts
Lists prompts in a project.
project_idrequiredcollection_idpromptprompt IDcountry_codelanguage_codefromtopageper_page≤100
GET/dimensions/prompt_executions
Lists prompt executions in a project.
project_idrequiredmodelcollection_idpromptprompt IDcountry_codelanguage_codefromtopageper_pagemention_filtercitation_filtercompetitorsthe two-axis matrix described underGET /answers
GET/dimensions/sources
Lists non-rejected sources produced by prompt executions.
project_idrequiredmodelcollection_idpromptprompt IDcountry_codelanguage_codefromtopageper_pagesource_typemention_filtercompetitors
Here mention_filter applies to the brands named in the crawled content of each cited page, not in the AI answer, mirroring the Citations page.
GET/dimensions/mentions
Lists mentions created by your project.
project_idrequiredcollection_idpromptprompt IDfromtopageper_page
GET/dimensions/citations
Lists citations created by your project.
project_idrequiredcollection_idpromptprompt IDfromtopageper_page
GET/dimensions/competitor_mentions
Lists competitor mentions detected in your executions.
project_idrequiredcompetitorsCSV idspromptprompt IDfromtopageper_page
GET/dimensions/competitor_citations
Lists competitor citations detected in your executions.
project_idrequiredcompetitorsCSV idspromptprompt IDfromtopageper_page
GET/dimensions/all_mentions
Unified endpoint combining brand and competitor mentions. Each record includes an actor_type field (project or competitor).
project_idrequiredcompetitorsCSV idsmodelcollection_idpromptprompt IDcountry_codelanguage_codefromtopageper_page
GET/dimensions/all_citations
Unified endpoint combining brand and competitor citations. Each record includes an actor_type field (project or competitor).
project_idrequiredcompetitorsCSV idsmodelcollection_idpromptprompt IDcountry_codelanguage_codefromtopageper_page
GET/dimensions/projects/:id
Get detailed information about a project: matching names, industry, business model, prompt counts per brand focus, and data_coverage (the models, countries and languages that actually have data), so one call replaces separate models/locales lookups.
GET/dimensions/competitors/:id
Get detailed information about a competitor including matching names and app store IDs.
Agent Analytics
Surfaces AI bot crawler traffic hitting your origin server (GPTBot, PerplexityBot, ClaudeBot, OAI-SearchBot, Google-Extended, and ~25 other AI bots) from Cloudflare or CSV uploads. Available on Scale and above.
GET/metrics/agent_traffic
Aggregated AI bot traffic for a project, grouped by bot or by company, with daily/weekly/monthly granularity.
project_idrequiredrangefromtobotcompanygroup_bybot|companygranularityday|week|month
GET/dimensions/agent_bots
Static catalog of AI bots that Agent Analytics can identify. Use it to render filter UIs that mirror our internal classification (slug, display name, company, category, Cloudflare verified-bot mapping). Requires Scale or above; the MCP tool list_agent_bots is available on every plan.
project_idrequired
Search Console
Google Search Console performance data (impressions, clicks, CTR, average position) for projects with a connected GSC property. Growth plan or above required. ctr is a 0..1 fraction and position is the impression-weighted average, matching the Search Console API. Projects without a connected property return ERR_SEARCH_CONSOLE_NOT_CONNECTED (404).
GET/search_console/summary
Property-wide headline totals for the range, with an optional country or device breakdown aggregated over the same range.
project_idrequiredrangefromtodimensioncountry|device
GET/search_console/timeseries
Property-wide series bucketed by day, week or month.
project_idrequiredrangefromtogranularityday|week|month
GET/search_console/queries
Top search queries for the range, ranked and paginated. Knowingly undercounts anonymized queries, so they do not sum exactly to the summary totals (same as the GSC UI).
project_idrequiredrangefromtosortimpressions|clicks|ctr|positionpageper_page
GET/search_console/pages
Top landing pages for the range, ranked and paginated. Same shape as the queries endpoint, with each row key being a page URL.
project_idrequiredrangefromtosortimpressions|clicks|ctr|positionpageper_page
Citation Intelligence
Cited-page intelligence, grouped URL/domain/host views, page-cache metadata, mention evidence inside cited pages, occurrence lists, and sanitized cached content.
GET/citation_intelligence/groups
Grouped citation intelligence by url, domain, or host with per-model breakdown, citation rate, and average citation position (ignores position = 0 rows).
project_idrequiredviewurl|domain|hostpageper_pageordergroup_key,total_responses,total_citations,citation_rate,avg_citation_position,first_seen_at,last_seen_atdirectionmodelcollection_idcountry_codelanguage_codepromptfromtoquerysource_typeowned|competitor|third_party|social_media|own_domain|ugc|backgroundsentimentnegativecontent_gapmentioned|gap
Invalid enum values return ERR_INVALID_PARAM.
GET/citation_intelligence/mentions_by_domain
For the responses where each given source domain is cited, the share of those responses that mention your brand vs each competitor. Brand and competitors are normalized to sum to 100% per domain, mirroring the Share of Voice mention definition. Pass several domains to analyze the whole matrix in one call.
project_idrequireddomainsrequired array, e.g.domains[]=example.com, max 50modelcollection_idcollection_idscountry_codelanguage_codepromptfromto
Empty domains returns ERR_INVALID_PARAM. Each row has responses_citing, total_mentions, and an actors array (brand and competitors with mentions and share).
GET/citation_intelligence/urls/:url_sha256
URL-level detail for one cited page: totals, citation rate, avg citation position, source-type counts, per-model counts, distinct URL variants, page-cache metadata, and page mention evidence with snippets and actor labels.
- Params:
project_id(required),:url_sha256(64 hex chars in URL), same optional filters as/citation_intelligence/groups.ERR_NOT_FOUNDonly when the URL was never cited by the project; filters that empty the result still return200with zero stats.
GET/citation_intelligence/urls/:url_sha256/occurrences
Paginated occurrences of a cited URL across prompt executions, with response excerpt, prompt text, model, executed_at, citation_position and source_type per row.
- Params:
project_id(required),:url_sha256(64 hex chars),page,per_page, same optional filters as/citation_intelligence/groups.
GET/citation_intelligence/urls/:url_sha256/content
Sanitized cached page content for a cited URL: page-cache metadata, mention evidence and snippets, full plain text, and rendered HTML (scripts and unsafe markup removed).
project_idrequired:url_sha25664 hex chars
AI Model Insights
Aggregate parts of the in-app AI Model Insights report. All three endpoints filter by executed_at (not created_at) and share a standard actor shape: { type, id, competitor_id, name, domain } with bare (scheme-less) domains.
GET/reports/ai_model_insights/summary
Per-model mention counts and shares, citation counts and shares, brand net sentiment with raw positive/negative counts, weighted visibility totals and shares, plus actor matrices for each.
project_idrequiredrangedefault 28fromtogranularityday|week|monthcollection_idcountry_codelanguage_codeprompt_typebrand_kindusenon_brandto match the in-app AI Model Insights Overview tab and for fair brand-vs-competitor comparisonscompetitorsCSV of competitor IDs; unknown IDs →ERR_INVALID_PARAM
GET/reports/ai_model_insights/position_distribution
Position-distribution comparison used in the AI Model Insights report: one or two brand series with bucketed totals (Position 1, Position 2-3, Position 4-7, Position 8+) and chart-ready time series per bucket.
project_idrequiredrangefromtogranularitycollection_idcountry_codelanguage_codeprompt_typebrand_kindusenon_brandfor a fair head-to-head, the in-app defaultmodelrestrict to one modelbrand1brand2competitor IDs for the comparison brands; omitbrand1to compare the project brand
GET/reports/ai_model_insights/ai_overview_results
Aggregate Google AI Overview result-availability data: total AI Overview responses, responses with results (no_result = false), result rate, chart-ready trend data, and a paginated by-prompt result-rate table.
project_idrequiredrangefromtofilters byexecuted_atcollection_idcountry_codelanguage_codeprompt_typebrand_kindgranularitypageper_page
Recommendations
Read-only API for the same recommendation runs that power the in-app Recommendations experience.
GET/recommendations
Lists recommendation runs for a project with type/status filters.
project_idrequiredrecommendation_typeai_visibility|social_community|brand_building|sentiment_reputationstatuspending|processing|completed|failedpageper_page
Invalid enum values return ERR_INVALID_PARAM.
GET/recommendations/:id
One recommendation run with its items and report data: items array with title, priority, action steps, metadata, source references, plus item counts grouped by active, completed, archived.
project_idrequired:idin URLitem_statusactive|completed|archivedresolve_source_refsdefaulttrue
POST/recommendations
Launch a new generation (same engine as the in-app Recommendations page). Runs async (1-3 minutes); poll GET /recommendations/:id until status is completed. Consumes the project weekly recommendation-item budget (ERR_LIMIT_REACHED when exhausted, or when a run of the same type is already pending). sentiment_reputation requires Scale or above. Requires a writable API key.
project_idrequiredrecommendation_typeai_visibilitydefault |social_community|brand_building|sentiment_reputation
Answers (AI Responses)
Access the actual AI-generated responses with full content, mentions, citations, and sentiment analysis.
GET/answers
List AI responses with their content. Returns paginated results with truncated response text (max 10,000 chars). Pass query for case-insensitive full-text search inside response texts: total becomes the exact count of matching responses, and each item returns snippet and match_count instead of the full response.
project_idrequiredmodelcollection_idpromptprompt IDcountry_codelanguage_codefromtopageper_pagequeryfull-text searchmention_filtercitation_filtercompetitors
The last three are the two-axis matrix from the Responses page: mention_filter takes mentions_you, not_mentions_you, mentions_competitor, not_mentions_competitor, you_and_competitor, competitor_not_you, you_not_competitor or no_brands (no tracked brand appears at all); citation_filter takes the same cells against cited domains (cites_you, not_cites_you, cites_competitor, not_cites_competitor, you_and_competitor, competitor_not_you, you_not_competitor, cites_no_brands). Both combine, and competitors (CSV of IDs) narrows the competitor side to those rivals. Unknown presets return ERR_INVALID_PARAM.
GET/answers/:id
Get a single AI response with full details including mentions, citations, sentiments, and sources.
project_idrequiredidanswer ID in URL
Detailed Sentiments
Access detailed sentiment analysis with comments, topics, and scores. This is different from /dimensions/sentiments which only returns sentiment categories.
GET/sentiments
List detailed sentiment records with full analysis context.
project_idrequiredmodelcompetitor_idbrand_onlyanalysisvery_positive/positive/neutral/negative/very_negativecollection_idpromptprompt IDcountry_codelanguage_codefromtopageper_page
Prompts (Bulk Create + Delete)
Add prompts to a project in bulk via the API. Validates against account prompt limits and deduplicates automatically.
POST/prompts
Create up to 100 prompts per request. Existing prompts (same text + locale) are skipped.
project_idrequiredpromptsarray, required, max 100country_coderequiredlanguage_coderequired
DELETE/prompts/:id
Delete a prompt. Irreversible; the prompt disappears immediately, frees a prompt slot, and its history (executions, mentions, citations, sentiment) is purged by a background job. Requires a writable API key.
project_idrequired:idin URL
Returns ERR_NOT_FOUND for prompts outside the project.
GEO Writer
Create and manage AI-powered GEO Writer tasks via the API. Tasks are processed asynchronously and results can be polled.
POST/intelligence_tasks
Create a GEO Writer task. Two modes: prompt-based (provide prompt_id) or agentic (provide custom_topic and/or user_instructions).
project_idrequiredtask_typerequired: brief, create, update, pr_insights, customprompt_idcustom_topicuser_instructionsoutput_language_codeexisting_contentexisting_content_url
GET/intelligence_tasks
List GEO Writer tasks for a project with optional filtering.
project_idrequiredtask_typestatuspageper_page
GET/intelligence_tasks/:id
Get full task details including result data when completed. Accepts numeric ID or public_id.
project_idrequired:idtask ID or public_id in URL
Agent Write Endpoints
These endpoints accept POST/PATCH/PUT/DELETE and require an API key with the read_write scope. A token with the read scope receives 403 ERR_INSUFFICIENT_SCOPE. Writes share a tighter rate limit (60/min/key) in addition to the global 300/min/key budget.
POST/projects
Create a complete project in one call (fast mode): project, prompts (queued for execution + categorization), competitors, weekly email subscription. Idempotent when external_identifier is provided. The project always belongs to the account owner.
- Body (JSON):
website_url(required public HTTP(S) URL with a DNS hostname or public IP address; credentials, private and special IP addresses, localhost and internal hostnames are rejected),name(required),main_country(required),main_language(required),brand_name,description,industry(array),matching_names(array),prompts(array, max 100),competitors(array of {domain, brand_name, matching_names}),owned_media(object, Growth+),use_subdomain,weekly_email_subscribed,external_identifier(embed-enabled accounts only; idempotency key, [a-z0-9_-]{1,64}),execute_prompts_immediately(default true).
Project Drafts wizard
Multi-step project wizard with AI suggestions: POST /project_drafts starts a draft (returns suggested name/description/industry for the URL), PATCH submits each step (details, prompts, competitors, owned_media) with strict forward gating and returns suggestions for the next step, POST /project_drafts/:id/finalize creates the real project. Drafts expire after 24h.
- The initial
website_urlmust be a public HTTP(S) URL with a DNS hostname or public IP address. Credentials, private and special IP addresses, localhost and internal hostnames are rejected. Steps:details(name required),prompts(max 100, quota-validated),competitors(plan-capped),owned_media(optional, Growth+). Suggestions per step withsuggest=falseopt-out; cold URLs can take up to ~2 minutes, set client timeout to 180s. Finalize is idempotent and re-validates every gate.
POST/competitors
Add a competitor (brand_name + domain) to a project. Honours the per-plan max competitors cap.
project_idrequiredbrand_namerequireddomainrequired, URL is normalisedmatching_namesoptional array
PATCH/DELETE /competitors/:id
Update a competitor (brand_name, matching_names, color; the domain is immutable after creation) or delete it. Name changes re-run mention/citation matching in the background (processing: true for a few minutes, edits blocked meanwhile). Deleting is irreversible and purges the competitor data in the background.
project_idrequiredbrand_namematching_namesfull replacement arraycolorhex
DELETE: project_id + :id in URL.
POST/collections
Create a tag (Collection) in a project. Optionally attach existing prompts in the same call. Tag name is case-insensitive unique per project.
project_idrequirednamerequireddescriptionoptionalprompt_idsoptional array, must belong to the project
PATCH/DELETE /collections/:id
Rename a tag or change its description, or delete it. Deleting a tag keeps the prompts inside it; only the grouping disappears. Prompt membership is managed via POST /prompts/assign_tags.
- PATCH body:
project_id(required),nameand/ordescription. DELETE:project_id+:idin URL.
POST/prompts/assign_tags
Idempotent bulk attachment of tags to existing prompts. Tags can be resolved by id or name.
project_idrequiredprompt_idsrequired arraytag_idsone-oftag_namesone-ofcreate_missingoptional bool, auto-create unknown tag names
POST/annotations
Mark a date in the project timeseries with a title + description. Available on every plan.
project_idrequiredtitlerequiredannotation_dateoptional ISO YYYY-MM-DD; default todaydescriptionoptionalcoloroptional hexannotation_category_idoptional, must belong to the project
GET /annotations + PATCH/DELETE /annotations/:id
List, update, and delete annotations on every plan. GET returns manual, automatic, GEO test, and platform annotations newest first. The origin field distinguishes them, and editable says whether the requesting user may modify a row. PATCH and DELETE only work on manual annotations belonging to your own user (403 otherwise).
- GET query:
project_id(required),from/to(YYYY-MM-DD),annotation_category_id,page,per_page. PATCH body: any oftitle,description,annotation_date,color,annotation_category_id. DELETE:project_id+:idin URL.
POST/technical_geo_reports
Launch the full technical GEO analysis bundle (crawlability, schema, content readiness, discoverability, site structure, robots.txt, llms.txt, AI visibility) for a URL + country. Each report runs as a background job.
project_idrequiredurlrequiredcountry_codeoptional, defaults to the project country
Webhooks
Receive a signed HTTP POST every time something happens in a project, with no polling. Webhooks power the LLM Pulse connectors for Zapier, Make and n8n, and work with any custom backend. Available on the Scale plan and above. Each delivery is a JSON envelope: { "event", "occurred_at", "project_id", "subscription_id", "data" }.
- Event types:
mention.created,competitor_mention.created,citation.created,prompt_execution.completed,sentiment.negative_detected(negative or very negative brand sentiment),recommendation.completed,intelligence_task.completed. - Security: every delivery carries
X-LLMPulse-Event,X-LLMPulse-Delivery(unique id) andX-LLMPulse-Signature(sha256=<hex>, HMAC-SHA256 of the raw body computed with the subscription secret). Verify the signature to authenticate deliveries. - Delivery: a 2xx response acknowledges the event; anything else is retried 5 times with exponential backoff. Subscriptions auto-disable after 20 consecutive failed deliveries.
POST/webhooks
Create a subscription. Idempotent: re-posting the same project + event + URL returns the existing subscription. The signing secret (whsec_...) is only returned by this endpoint, store it to verify delivery signatures. Requires a read_write scope key.
project_idrequiredevent_typerequired, see event list abovetarget_urlrequired, public HTTPS URL; private IPs, localhost and internal hostnames are rejected
Max 100 active subscriptions per account.
GET/webhooks
List active subscriptions for the account. Items match the create response without the secret.
project_idoptional filterpageper_pagemax 100
DELETE/webhooks/:id
Delete a subscription. The target URL stops receiving events immediately. Requires a read_write scope key.
:idsubscription id
Returns ERR_NOT_FOUND for subscriptions that do not belong to the account.
GET/webhooks/sample/:event_type
Up to 3 example event payloads for the event type, built from the project''s most recent real data (or a static sample when the project has no data yet). Used by integration editors such as the Zapier sample loader. Also available as the MCP tool get_webhook_sample.
:event_typepathproject_idrequired
Filters & Common params
project_idrequired for all project-scoped endpoints.metricsormetric: CSV ofmentions, citations, responses, mention_rate (or visibility), citation_rate, ai_visibility_score, avg_position, avg_mention_position, sentiment_very_positive, sentiment_positive, sentiment_neutral, sentiment_negative, sentiment_very_negative, net_sentimentgranularity:day|week|month(weeks start Monday)- Time window: either
range(days) orfrom&to(ISO8601). If you sendto,fromis required. Defaults withfrom/to: missingfrom= 30 days ago (start of day); missingto= now (end of day). - Filters:
model,collection_id(tag id),prompt(prompt ID),country_code,language_code,competitors(CSV IDs) include_project(defaulttrue): setfalseto exclude your project (return only competitors).
Output Formats for BI Tools
Read endpoints return nested JSON by default, which is convenient for code but unreadable for business intelligence tools. Pass the optional output parameter to get the same data as a rectangular table that Tableau, Excel, Google Sheets or a warehouse loader can consume directly.
outputomitted (default): the nested JSON documented for each endpoint. Unchanged, so existing integrations are unaffected.output=flat: the same metadata pluscolumns(ordered column names),rows(one flat object per row) androw_count.output=csv: the same rows astext/csv, withcolumnsas the header row.
Supported on /metrics/timeseries, /metrics/summary, /metrics/sov, /metrics/prompt_summary, /metrics/top_sources, the /search_console/* series and the list-returning /dimensions/* endpoints. Endpoints whose payload is not a single table (/metrics/agent_traffic, /metrics/ai_traffic, /search_console/summary, /dimensions/models, /dimensions/locales) reject output instead of ignoring it.
/metrics/sov also accepts view=over_time (default), view=current or view=breakdown: its payload holds several different shapes and a table can only hold one at a time.
Columns by endpoint
| Endpoint | Columns |
|---|---|
/metrics/timeseries
|
date, actor_type, actor_id, actor_name, actor_domain, metric, value
|
/metrics/summary
|
actor_type, actor_id, actor_name, actor_domain, metric, aggregation, total, min, max, last
|
/metrics/sov
|
date, actor_type, actor_id, actor_name, actor_domain, share
|
/metrics/sov?view=current
|
actor_type, actor_id, actor_name, actor_domain, share
|
/metrics/sov?view=breakdown
|
rank, actor_type, actor_id, actor_name, actor_domain, share, others
|
/metrics/prompt_summary, /metrics/top_sources, /search_console/*, /dimensions/*
|
The keys of the endpoint's own data rows |
Example
GET /api/v1/metrics/timeseries?project_id=1&range=30&metrics=mentions&output=csv
date,actor_type,actor_id,actor_name,actor_domain,metric,value
2025-01-01,project,1,My Brand,mybrand.com,mentions,10
2025-01-01,competitor,2,Competitor A,competitor.com,mentions,5
Notes:
- Errors are always returned as JSON, never as CSV, so a failure is never mistaken for data.
- Percentages stay on the raw 0-100 scale, exactly as in the JSON response.
- Text cells that begin with an equals, plus, minus or at sign are escaped so spreadsheets do not execute them as formulas.
- Paginated endpoints also return their paging metadata in the
X-Total-Count,X-PageandX-Per-Pageresponse headers, which a CSV body cannot carry. - Flat output is capped at 200,000 rows. Above that, narrow the date range, request fewer metrics, or use
granularity=week. - Endpoints without a flat projection reject
outputwithERR_INVALID_PARAMinstead of ignoring it.
Metrics: Semantics & aggregation
These semantics are aligned 1:1 with the Overview UI.
- mentions: daily sums of
mentions_count. Forweek/monthwe compute the PERIOD TOTAL (Mon-Sun for weeks) and repeat that same total for every day in the period. If a period’s total is 0, we “carry” the last non-zero period total (sticky). - citations: response-level count that includes visible citations and background source references. Each actor counts at most once per response. Uses the same period-total and sticky-carry behavior as mentions.
- responses: total number of prompt executions (API calls to LLMs). Uses project-level execution count regardless of actor. •
day: daily sum. •week/month: period total (no sticky carry, days with 0 executions show 0). - Mention Rate
mention_rate(also accepted asvisibility): percentage per actor, using the project-level executions as denominator under the same filters (mentions_count/prompt_executions_count× 100). •day: compute the daily ratio. •week/month: compute the ratio-of-sums for the period (Σ mentions / Σ executions) and repeat that value for every day in the period. If the period's denominator is 0, carry forward the last non-null value. - citation_rate: percentage of responses that include a visible or background citation for the actor (
citations_count/prompt_executions_count× 100). •day: daily ratio. •week/month: ratio-of-period-sums with sticky carry, same as visibility. - AI Visibility Score
ai_visibility_score: position-weighted visibility metric that accounts for mention prominence. Uses reciprocal position weighting (position 1 = 100%, position 2 = 50%, position 3 = 33%, etc.). Higher scores indicate both more mentions AND better positioning. •day: compute daily weighted score / executions. •week/month: ratio-of-period-sums with sticky carry, same as visibility. - avg_position: average visible citation position. Background citations have no visible position and are excluded. •
day: daily average excluding nulls. •week/month: average within the period (ignoring nulls) and then propagate (carry) the last known value to days without data, matching the Overview chart smoothing. - avg_mention_position: average position of the brand when mentioned in AI responses (position 1 = first mentioned, position 2 = second, etc.). Lower is better. •
day: daily average excluding nulls. •week/month: average within the period with sticky carry. - Sentiment metrics
sentiment_very_positive,sentiment_positive,sentiment_neutral,sentiment_negative,sentiment_very_negative: for each actor and day, percentage of sentiments in that bucket over all sentiments for that actor. •day: daily ratio (bucket_count / total_sentiments * 100). Days with no sentiments returnnull. •week/month: we compute a ratio-of-period-sums (Σ bucket / Σ total * 100) and repeat that percentage for every day in the period. If the period’s denominator is 0, we carry forward the last non-null value (sticky), matching the Overview smoothing. - Net Sentiment Score
net_sentiment: para cada actor y día, calculamos un score en [-100, 100]: ( (very_positive + positive) − (negative + very_negative) ) / total_sentiments × 100. •day: usamos los porcentajes diarios de cada bucket (las métricassentiment_*) y calculamosnet = (pos+very_pos) − (neg+very_neg). •week/month: el score hereda las mismas semánticas de agregación/smoothing que los buckets de sentiment, porque se calcula a partir de esas series.
In /metrics/summary, total is a sum for count metrics and an average for avg_position, avg_mention_position, and net_sentiment.
GET /metrics/timeseries
Returns time series for one or more metrics, grouped by actor (your project + selected competitors). Weekly/monthly values follow the period semantics above. Optional prompt_type (search intent) and brand_kind filters scope every metric to a prompt category.
GET /metrics/summary
Aggregates per actor and metric (total/min/max/last). Ideal for KPI tiles.
GET /metrics/prompt_summary
Returns paginated per-prompt aggregated metrics (responses, mentions, citations, mention_rate, citation_rate, avg_mention_position, avg_position). Supports breakdown=model to add the AI model dimension to each row, returning per-prompt per-model metrics. Params: sort (responses, mentions, citations, mention_rate or visibility, citation_rate, avg_mention_position, avg_position), sort_dir (asc/desc), breakdown (model), page, per_page (max 100).
GET /metrics/sov
Share of Voice based on mentions, aligned with Overview.
- over_time: for each date,
SOV = (actor_mentions / sum_all_mentions) × 100. If the daily sum is 0, the last value is carried forward (sticky). - current: uses the latest date with non-zero total; if none, it uses totals over the whole range.
- breakdown: top 4 actors + an aggregated Others row (and a detailed
otherslist).
GET /metrics/top_sources
Ranks source domains by number of responses and average mention rate (% of executions that surfaced that domain).
- The dataset includes non-rejected sources linked to prompt executions within the window and current filters.
total_responses: number of unique prompt executions that produced at least one source on that domain.avg_mention_rate(also returned asavg_visibility):(count of source rows for the domain / total executions) × 100.- Sorting:
sort=total_responses(default),sort=avg_mention_rate, orsort=avg_visibility. - Pagination:
page(>=1),per_page(default 20, max 100). - Filter by domain:
query(case-insensitiveLIKE), e.g.query=github.
GET /metrics/ai_traffic
Returns the AI-referred traffic measured from a project's connected web analytics provider (Google Analytics 4, Adobe Analytics, PostHog, Plausible or Piano): per-day users, sessions and conversions grouped by AI source (ChatGPT, Perplexity, Gemini, Claude and others), with totals and a conversion rate. Requires the Scale plan or above and a connected provider; projects without one return ERR_AI_TRAFFIC_NOT_CONNECTED (404).
project_idrequiredrangefromtogranularityday|week|monthsourcerestrict to one AI source
Cache & Conditional GET
Metrics endpoints (timeseries, summary, sov, top_sources) support conditional GET. We compute an ETag from the project version and a hash of your query params, and use the project’s updated_at as Last-Modified.
Send If-None-Match or If-Modified-Since to receive 304 Not Modified when nothing changed.
Errors
Errors are consistent and machine-parsable:
| Code | HTTP | Meaning |
|---|---|---|
| ERR_MISSING_AUTH | 401 | Missing or malformed Authorization header |
| ERR_INVALID_API_KEY | 401 | Token not recognized |
| ERR_REVOKED_API_KEY | 403 | Key revoked |
| ERR_PROJECT_NOT_FOUND | 404 | project_id not accessible by this user |
| ERR_NOT_FOUND | 404 | Resource not found |
| ERR_INVALID_PARAM | 422 | Validation failed (see message) |
| ERR_LIMIT_REACHED | 422 | Account prompt limit reached |
| ERR_QUOTA_EXCEEDED | 422 | Monthly GEO Writer task quota exceeded |
Error body shape:
Typical 422 cases:
invalid metrics: onlymentions, citations, responses, mention_rate (or visibility), citation_rate, ai_visibility_score, avg_position, avg_mention_position, sentiment_very_positive, sentiment_positive, sentiment_neutral, sentiment_negative, sentiment_very_negative, net_sentimentare allowed.invalid granularity: must beday|week|month.from/to must be ISO8601, orfrom is required with to.range is requiredwhen neitherfromnortoare sent.unknown competitor ids: ...: IDs not found under the project.
Client snippets
Examples in multiple languages are shown in the code panel on the right.
Postman: Download & Environment
Use this curated Postman collection to explore the API quickly and securely. It mirrors the examples and metric semantics described above (period totals with sticky carry, ratio-of-period-sums for visibility, and propagation for avg_position), so you can validate responses and prototype integrations in minutes.
Download the collection
Download LLMPulse API v1 Postman Collection
Import the file in Postman (File → Import), then select or create the environment shown below. The collection uses variables, so you won’t need to edit each request manually.
Environment (placeholders, keep your IDs private)
Create a new Environment in Postman with the following variables. Use placeholders instead of real IDs or keys in any public context (docs, screenshots, etc.):
How it’s used:
- The collection reads
{{base_url}}and injectsAuthorization: Bearer {{api_key}}automatically. - Set
{{project_id}}to a project you own;{{competitors}}is CSV (e.g.1,2,3). - You can override per request (e.g. send
from/toinstead ofrange) and add filters likemodel,collection_id,country_code,language_code. - Keep your API key in your private environment only; do not paste it into shared documents.
MCP (AI Integration)
MCP (Model Context Protocol) allows AI assistants like ChatGPT, Claude and Gemini to access your LLM Pulse data directly. Available on every plan via OAuth, no API key required. Ask questions in natural language and let the AI fetch and analyze your visibility data.
What is MCP?
MCP is an open protocol that lets AI assistants connect to external data sources. Instead of copying data or making API calls manually, you can simply ask your AI assistant questions like "What's my visibility trend this month?" and it will fetch the data automatically.
Endpoint
Configuration
Recommended for every plan: paste the MCP URL into your AI client. The client handles OAuth automatically, no token to copy. API-key auth (Bearer header) is available on the Scale plan and above for headless integrations.
Struggling to connect?
MCP and OAuth support is still uneven across AI clients, so connections sometimes fail to establish. On the Scale plan and above, the easiest fallback is to give your AI assistant a Bearer API key plus a link to these API docs. It can then query every endpoint directly over plain HTTP, with no MCP client setup at all.
Available Tools
These tools are available to your AI assistant.
Live list rendered from Mcp::LlmPulseServer::TOOLS (74 tools registered). The MCP server filters tools/list per user plan.
| Tool | Description | Plan |
|---|---|---|
| list_projects | List all projects accessible to the authenticated user. Returns project id and name. | All |
| list_competitors | List all competitors for a specific project. Returns competitor id, name, domain, and matching_names (the aliases used for mention matching). With include_project_brand=true a synthetic first row represents the tracked brand itself: its id is the PROJECT id (not a competitor id, so do not pass it to get_competitor_details) and it carries actor_type=project / is_own=true. | All |
| list_collections | List all collections (tags) for a specific project. Returns collection id and name. Collections and tags are the SAME underlying object: this returns identical data to list_tags. | All |
| list_tags | List all tags for a specific project. Tags and collections are the SAME underlying object in LLM Pulse: this returns identical data to list_collections, and create_collection / assign_prompt_tags(create_missing) write to the same set. | All |
| list_models | List all AI models that have data for a specific project. Returns model identifiers (e.g., chatgpt, perplexity, gemini, ai_mode, ai_overview). Note: get_project_details data_coverage already includes this, so a separate call is rarely needed. | All |
| list_locales | List all countries and languages that have data for a specific project. Returns lists of country codes (e.g., US, ES) and language codes (e.g., en, es). | All |
| list_sentiments | List all sentiment categories with their metric keys, labels, and colors. Used for understanding sentiment data structure. | All |
| list_prompts | List prompts for a project with optional filtering by collection, locale, prompt_type, brand_kind, and date range. Returns paginated results with prompt id, prompt_text, tags (the authoritative tag/collection memberships as {id, name} pairs; use this to audit tagging), collection_ids, country_code, language_code, prompt_type, brand_kind, and last_executed_at. The legacy collection_id field can be null even when the prompt HAS tags; never conclude a prompt is untagged from collection_id. | All |
| list_prompt_executions | List prompt executions with model, success, execution timing, fan-out queries, and mention/citation presence. duration_ms measures internal processing time of the answer pipeline, NOT the AI model latency, and can be near zero. fan_out_queries is only populated for models/providers that expose query fan-out (mainly chatgpt), null elsewhere. | All |
| list_mentions | List OWN mentions of the project brand only (no competitors). Use list_all_mentions for brand + competitors with an actor_type field. Returns paginated results with mention id, name, prompt_id, prompt_execution_id, and created_at. | All |
| list_citations | List OWN URL citations of the project brand only (no competitors; effectively one citation per answering response). Use list_all_citations for brand + competitors, and list_sources / list_citation_groups for per-URL granularity with url_sha256. position 0 means unranked/background (real positions are 1-indexed). Returns paginated results with citation id, name, domain, prompt_id, prompt_execution_id, url, position, and created_at. | All |
| list_competitor_mentions | List competitor mentions for a project with optional competitor and prompt filters. | All |
| list_competitor_citations | List competitor citations for a project with optional competitor and prompt filters. | All |
| list_all_mentions | List all mentions (brand + competitor) for a project with actor_type field. Returns paginated results combining project and competitor mentions. The competitors filter narrows which competitor rows are included, but project rows are ALWAYS included. | All |
| list_all_citations | List all citations (brand + competitor) for a project with actor_type field. Returns paginated results combining project and competitor citations. The competitors filter narrows which competitor rows are included, but project rows are ALWAYS included. position 0 means unranked/background (real positions are 1-indexed). | All |
| list_sources | List sources (URLs cited by AI models) for a project with optional filtering. Returns paginated results with source id, prompt_execution_id, domain, url, position, source_type (owned, competitor or third_party), and app-store link flags. | All |
| list_citation_groups | List grouped citation intelligence data by URL, domain, or host, including citation rates, model breakdowns, and page-cache awareness. Rows are compact by default; pass include_page_details=true to embed crawled page content details (url view only), and keep per_page moderate when you do. | All |
| get_cited_url_details | Get detailed URL-level citation intelligence for one cited URL, including page-cache metadata and mention evidence. | All |
| list_cited_url_occurrences | List every prompt execution where a specific cited URL appeared, with prompt text, answer preview, model, and citation position. | All |
| get_cited_url_content | Get sanitized cached page content plus page-cache metadata and mention snippets for one cited URL. Text longer than 15,000 characters is truncated (content.text_truncated=true, full length in content.text_total_chars); use max_chars to shrink the slice and offset to page through the rest. | All |
| get_mentions_by_citing_domain | For responses where a given source domain is cited, returns the share of those responses that mention the brand vs each competitor (brand + competitors sum to 100% per domain). Accepts a list of domains so the whole matrix is one call. Answers questions like "when gmac.com is cited, which brands get mentioned?". | All |
| get_timeseries | Get time series metrics data for a project. Supports metrics like mentions, citations, mention_rate (also accepted as visibility), citation_rate, responses, ai_visibility_score (position-weighted visibility, unbounded: it can exceed 100 when several brand mentions rank high in one period), avg_position, net_sentiment, and sentiment breakdowns. Returns data points over time for the project; competitor series are only included when you pass competitors (ids from list_competitors). With week/month granularity the first bucket covers only the in-window days (partial periods are clipped, not back-filled). When comparing the project against competitors 1:1, set brand_kind=non_brand (the in-app Overview default) so brand-focused prompts do not skew the comparison. | All |
| get_summary | Get summary statistics for metrics over a time period. Returns one row per metric and actor with total (count metrics are summed; percentage/rate metrics are averaged across periods, never summed), min, max, and last values. Use group_by to get one summary per AI model or per collection in a single call instead of fanning out multiple filtered calls. When comparing the project against competitors 1:1, set brand_kind=non_brand (the in-app Overview default) so brand-focused prompts do not skew the comparison. | All |
| get_prompt_summary | Get per-prompt aggregated metrics (responses, mentions, citations, mention_rate, citation_rate, avg_mention_position, avg_position) with pagination and sorting. mention_rate (also accepted as visibility) is the percentage of responses mentioning the brand. Returns brand-only metrics broken down by individual prompt. Supports breakdown=model to get per-prompt per-model metrics. Field notes: visibility and mention_rate are the same value (historical alias, both kept for compatibility); avg_mention_position is the average position of the brand WITHIN the answers that mention it, while avg_position is the position-weighted metric used by ai_visibility_score. | All |
| get_sov | Get Share of Voice metrics - shows the relative share of mentions between the project and competitors over time. Returns current share percentages and breakdown by actor, plus a periods array with the sample size (mentions) and a partial flag per bucket: shares in a bucket with 1-3 mentions read as 100/50/33.33 and should be treated as low-sample noise, and partial buckets are still collecting data. Use group_by=model to get the per-model share comparison in ONE call instead of one filtered call per model. For a fair brand-vs-competitor comparison, set brand_kind=non_brand (the in-app Overview default): brand-focused prompts skew the share toward the brand they name. | All |
| get_top_sources | Get top performing source domains for a project. Returns domains ranked by citing responses; avg_visibility (alias avg_mention_rate) is the percentage of all responses in the window that cite the domain at least once (bounded 0-100). | All |
| get_ai_model_summary | Per-AI-model breakdown of mentions, citations, sentiment and weighted visibility for the brand and competitors, in a single call. USE THIS for any question that compares performance across AI models ("which model do I rank best on?", "ChatGPT vs Perplexity vs Gemini", "where am I most visible across models?"). Prefer this over calling get_summary multiple times with different model filters: get_ai_model_summary returns all models at once and avoids hitting the step limit. The in-app AI Model Insights Overview tab defaults to non-brand prompts, so pass brand_kind=non_brand to match its numbers and for fair brand-vs-competitor comparisons. NOTE: mentions_market_share values are the independent mention rate of each actor within a model (mentions divided by the responses of that model); one response can mention several actors, so the values do NOT sum to 100 and must not be charted as a share pie. For a true share partition use get_sov. | All |
| get_ai_model_position_distribution | Get the AI Model Insights position-distribution comparison for the project brand and an optional competitor. For a fair head-to-head, pass brand_kind=non_brand (the in-app AI Model Insights default): brand-focused prompts skew positions toward the brand they name. When brand2 is omitted it defaults to the largest competitor by mentions. Weekly/monthly buckets are aligned to full calendar periods: the first bucket covers the whole week/month containing the range start (so its counts can differ from get_timeseries, which clips partial periods). | All |
| get_ai_overview_results | Get aggregate Google AI Overview result availability over time plus per-prompt breakdowns. | All |
| list_answers | List AI answers/responses with their content, prompt text, model, and basic metrics. Returns paginated results; response text is truncated to 1,500 characters per row by default (response_truncated flags it). Pass full_text=true for up to 10,000 characters per row, or use get_answer for one complete response. Pass query to full-text search the response texts: total then equals the exact number of matching responses (use it for counting questions instead of reading pages), and each row returns a short snippet around the match instead of the full text. | All |
| get_answer | Get detailed information about a single AI answer/response including full response text, mentions, citations, sentiments, and sources. | All |
| list_detailed_sentiments | List detailed sentiment analysis records with comments, topics, scores, and competitor information. This is different from list_sentiments which only returns sentiment categories. | All |
| list_recommendations | List read-only recommendation runs for a project, including type, status, summary, and counts. | All |
| get_recommendation | Get full details for one recommendation run, including items, source references, and report data. Each item carries source_refs codes (e.g. P1, C2); resolve them against the report_data indices (prompts_index, citations_index, own_content_index), which are always included once per response. | All |
| get_project_details | Get detailed information about a project: matching names, industry, business model, primary products, target audience, prompt counts per brand focus (brand / brand_other / non_brand), and data_coverage (the AI models, countries and languages that actually have data). Call this right after list_projects: it replaces separate list_models / list_locales calls and tells you the non_brand prompt pool size before filtered queries. | All |
| get_competitor_details | Get detailed information about a competitor including matching names, mobile app IDs, and icon URLs. | All |
| create_prompts | Add prompts to a project in bulk. Validates against available prompt limits. Skips duplicates. New prompts run ONCE within minutes of creation (so results appear fast) and then join the weekly schedule. brand_kind / prompt_type are classified asynchronously; fetch them via list_prompts a little later. In the response, prompts_available=null means unlimited. | All |
| delete_prompt | Delete a prompt from a project (same as Delete on the Prompts page). IRREVERSIBLE: the prompt disappears immediately, frees a prompt slot, and its whole history (executions, mentions, citations, sentiment, and any GEO Writer tasks created for this prompt) is purged by a background job. Never call this speculatively: only when the user explicitly asked to delete this specific prompt, and confirm the exact prompt text with them first. In the in-app chat the user gets a Confirm/Cancel card; external MCP clients delete immediately. Find prompt ids via list_prompts. | All |
| create_intelligence_task | Create a GEO Writer (formerly Content Intelligence) task. task_type selects what is produced: "brief" = content brief/outline for a topic, "create" = full draft article, "update" = rewrite/improve existing content (requires existing_content or existing_content_url), "pr_insights" = PR/media angle analysis, "custom" = freeform output driven by user_instructions. Pass prompt_id to base the task on an existing prompt, or omit it for agentic mode (then custom_topic or user_instructions is required). Returns task ID for polling status with get_intelligence_task. | All |
| create_competitor | Add a competitor to a project. Validates against the max competitor limit of the plan. Triggers async association recalculation: the competitor row returns processing=true immediately, and mentions/SOV/dashboards include it once the recalculation finishes (typically minutes, longer on large projects). competitors_remaining=null in the response means unlimited. | All |
| update_competitor | Update a competitor: brand_name, matching_names (the name variants used to detect mentions; REPLACES the whole list), and/or chart color. The domain is immutable after creation (delete and re-create to change it). Changing brand_name or matching_names re-runs mention/citation matching in the background: the competitor shows processing=true for a few minutes and edits are blocked meanwhile. Find competitor ids via list_competitors. | All |
| delete_competitor | Delete a competitor from a project (same as Delete on the Competitors page). IRREVERSIBLE: the competitor disappears immediately, frees a competitor slot, and its tracked data (mentions, citations, sentiment, share-of-voice history) is purged by a background job. Never call this speculatively: only when the user explicitly asked to remove this specific competitor, and confirm the brand with them first. In the in-app chat the user gets a Confirm/Cancel card; external MCP clients delete immediately. Find competitor ids via list_competitors. | All |
| create_collection | Create a tag (Collection) in a project. Optionally attach existing prompts in the same call. Tag name is unique per project (case-insensitive). | All |
| update_collection | Rename a tag/collection or change its description (tags and collections are the same object). Prompt membership is managed separately via assign_prompt_tags / remove_prompt_tags. Find tag ids via list_tags / list_collections. | All |
| delete_collection | Delete a tag/collection from a project (same as Delete on the Tags page; tags and collections are the same object). IRREVERSIBLE for the tag itself, but the prompts inside it are NOT deleted: only the grouping disappears. Never call this speculatively: only when the user explicitly asked to delete this specific tag, and confirm its name with them first. In the in-app chat the user gets a Confirm/Cancel card; external MCP clients delete immediately. Find tag ids via list_tags / list_collections. | All |
| assign_prompt_tags | Attach tags (collections) to existing prompts in bulk. BATCH your calls: pass ALL prompt_ids sharing the same tag set in ONE call (up to 500 prompt_ids and 50 tags per call); never call once per prompt. Provide tag_ids for known tags, or tag_names to look up by name (case-insensitive). Pass create_missing=true to create tag names that do not exist yet. Idempotent: re-running with the same input does not duplicate assignments. | All |
| remove_prompt_tags | Detach tags (collections) from existing prompts in bulk: the inverse of assign_prompt_tags, e.g. to undo a tagging mistake. BATCH your calls: pass ALL prompt_ids sharing the same tag set in ONE call (up to 500 prompt_ids and 50 tags per call). Only removes the prompt-tag links; never deletes the tags themselves or the prompts. Idempotent: links that do not exist are reported as skipped. | All |
| list_annotations | List the timeline annotations of a project (the markers shown on dashboard charts), newest first. Includes manual annotations, project automations, GEO test markers, and platform-wide events. The origin field distinguishes them; editable tells you whether update_annotation / delete_annotation can touch the row. Filter by date window (from/to or range) and annotation_category_id. Available on every plan. | All |
| create_annotation | Mark a date in the project timeseries with a title + description. Useful when the agent detects a notable change (campaign launch, product update, news event) and wants to flag it. Annotations are scoped to the project and visible to all members. | All |
| update_annotation | Update a timeline annotation (title, description, date, color, category). Only user-created annotations that belong to your own user can be updated (system annotations and other members annotations cannot; check the editable flag in list_annotations). Available on every plan. | All |
| delete_annotation | Delete a timeline annotation from a project. Only user-created annotations that belong to your own user can be deleted (system annotations and other members annotations cannot). Never call this speculatively: only when the user explicitly asked to delete this specific annotation. In the in-app chat the user gets a Confirm/Cancel card; external MCP clients delete immediately. Find annotation ids via list_annotations. Available on every plan. | All |
| launch_recommendations | Launch a new AI-powered recommendations generation for a project (same engine as the in-app Recommendations page). This is a REAL, quota-consuming action: it spends the project weekly recommendation-item budget (shared across all types, admins exempted) and runs a 1-3 minute background job. Never call it speculatively: only when the user explicitly asked to (re)generate recommendations, and after telling them it consumes the weekly budget. In the in-app chat the user gets a Confirm/Cancel card first; external MCP clients launch immediately, so get the user approval in YOUR conversation before calling. Track progress via get_recommendation / list_recommendations (status pending -> processing -> completed). | All |
| create_technical_geo_report | Run the full technical GEO analysis bundle (crawlability, schema, content readiness, discoverability, site structure, robots.txt, llms.txt, AI visibility) for a given URL + country. This is a REAL, quota-consuming action: it launches multiple scraping and AI analysis jobs (3-10 minutes, counts against a daily report cap per account). Never call it speculatively: only when the user explicitly asked for a technical GEO analysis, and tell them it consumes report quota. In the in-app chat the user gets a Confirm/Cancel card first; external MCP clients launch immediately, so get the user approval in YOUR conversation before calling. Finished reports appear on the Technical GEO page in the app and are emailed to the requesting user. | All |
| list_intelligence_tasks | List GEO Writer (formerly Content Intelligence) tasks for a project with optional filtering by type and status. | All |
| get_intelligence_task | Get a GEO Writer (formerly Content Intelligence) task by ID, including status and result data when completed. | All |
| get_agent_traffic | Get aggregated AI bot traffic for a project from Cloudflare or uploaded server logs. Returns per-day request counts grouped by bot or by company. Available on Scale and above plans. | Scale |
| list_agent_bots | List the catalog of known AI bots (crawlers, assistants, search fetchers) and their parent companies. Use this to discover valid bot slugs and company names for the bot/company filters of get_agent_traffic. Returns each bot's slug, display name, company, category, and description. | Scale |
| get_ai_traffic | AI traffic for a project: the human visits arriving from AI assistants (ChatGPT, Perplexity, Gemini, Claude, Copilot, Grok, Mistral, Meta AI, DeepSeek), measured from the connected web analytics provider (Google Analytics 4, Adobe Analytics, PostHog, Plausible or Piano). Returns per-day users, sessions and conversions grouped by AI source, plus totals and conversion rate. Requires a connected web analytics provider. Available on Scale and above plans. | Scale |
| get_search_console_summary | Google Search Console headline totals (impressions, clicks, CTR, average position) for a project over a date range. Pass dimension=country or dimension=device to also get the breakdown aggregated over the range (country values are lowercase ISO alpha-3 as returned by Google, e.g. usa, gbr, plus the zzz unknown-country sentinel). The response data_through field marks the last day with synced data: Google publishes with a 2-3 day lag, so later days are missing, not zero. Requires the project to have a Search Console connection. | Growth |
| get_search_console_timeseries | Google Search Console property-wide time series (impressions, clicks, CTR, average position) bucketed by day, week or month. The response data_through field marks the last day with synced data: Google publishes with a 2-3 day lag, so trailing days are missing rows, not real zero-drops. Requires the project to have a Search Console connection. | Growth |
| get_search_console_queries | Top Google Search Console search queries for a project over a date range, ranked by impressions, clicks, CTR or average position, with pagination. Knowingly undercounts anonymized queries; for exact headline numbers use get_search_console_summary. Requires a Search Console connection. | Growth |
| get_search_console_pages | Top Google Search Console landing pages for a project over a date range, ranked by impressions, clicks, CTR or average position, with pagination. For exact property totals use get_search_console_summary. Requires a Search Console connection. | Growth |
| create_webhook_subscription | Subscribe a public HTTPS URL to a project event. LLM Pulse will POST a signed JSON payload to the URL every time the event occurs (new mention, new citation, execution completed, negative sentiment detected, recommendation or intelligence task completed). Available on Scale and above plans. Deliveries are signed: the X-LLMPulse-Signature header carries sha256=<HMAC-SHA256 hex of the raw body> using the whsec_ secret returned ONCE by this call (store it; it is never shown again; rotating requires delete + recreate). X-LLMPulse-Event and X-LLMPulse-Delivery headers identify the event and delivery. | Scale |
| create_project | Create a complete project in one call (fast mode): project fields, prompts (queued for execution), competitors, weekly email subscription. Idempotent via external_identifier (embed accounts). Same plan gates and quotas as the in-app wizard. Use this fast mode when you already have every field; use start_project_draft for the step-by-step wizard with AI suggestions. | All |
| update_project | Update a project profile (same fields as Project Settings > General): brand_name, description, industry, business_model, target_audience, primary_products, brand_voice, goals and matching_names. matching_names REPLACES the whole list, so always send the full set including the ones already there (read them first with get_project_details). Changing matching_names re-runs mention/citation matching over the project history in the background, which can move visibility numbers for past weeks; a brand_name change applies to future runs only. Returns an error while a previous rematch is still running. The project name, website URL, country/language, app-store and social profiles are NOT editable here: those stay in Project Settings. In the in-app chat the user gets a Confirm/Cancel card. | All |
| start_project_draft | Start the multi-step project-creation wizard. Returns a draft_id plus AI suggestions (name, description, industry, aliases) for the URL. First call for a new URL may take up to 2 minutes; pass suggest=false to skip AI. Drafts expire after 24h and there is no list endpoint, so STORE the draft_id; a lost id means waiting for expiry. Use this wizard when you want AI suggestions step by step; use create_project instead when you already have all fields and want one call. | All |
| get_project_draft | Read a project draft: state, current step, accumulated data. include_suggestions returns cached suggestions for the current step (never triggers AI). | All |
| update_project_draft | Submit one wizard step (details, prompts, competitors, owned_media). Strict forward gating: a step is only accepted when every previous step is complete; completed steps can be resubmitted. Returns the updated draft plus AI suggestions for the next step (suggest=false to skip). Per-step required fields beyond draft_id+step: details requires name (industry optional but validated); prompts requires a non-empty prompts array of strings within your plan slots; competitors requires an array of {domain, brand_name?, matching_names?} with valid domains within plan limits; owned_media accepts its documented keys. | All |
| finalize_project_draft | Create the real project from a completed draft (same effects as create_project). Idempotent: finalizing an already-finalized draft returns the existing project. Re-validates every plan gate and quota. | All |
| list_webhook_subscriptions | List active webhook subscriptions for the account, optionally filtered by project. Available on Scale and above plans. | Scale |
| delete_webhook_subscription | Delete a webhook subscription by ID. The target URL stops receiving events immediately. Available on Scale and above plans. | Scale |
| get_webhook_sample | Get sample webhook payloads for an event type, built from the project's most recent real data (or a static sample when no data exists). Use this to preview the exact payload shape before creating a webhook subscription with create_webhook_subscription. Available on Scale and above plans. | Scale |
| send_feedback | Send feedback about LLM Pulse to the product team: a bug report, a feature request, or general product feedback. Use it when the user wants to report a problem or suggest an improvement, or when a tool clearly misbehaved. This channel is one-way (no reply); for questions about how the product works use ask_support instead. | All |
| ask_support | Ask the LLM Pulse support assistant a question about the product: features, plans, metric definitions, setup, or API usage. Answers come from the official LLM Pulse knowledge base. Use send_feedback instead to report a bug or request a feature; email support@llmpulse.ai for account-specific issues (billing, invoices). | All |
Protocol
MCP uses JSON-RPC 2.0 over Streamable HTTP. Requests return a JSON-RPC response. Accepted notifications return HTTP 202 with an empty body.
For a simpler guide, see the MCP Setup page.
OAuth 2.1 (ChatGPT Apps SDK, MCP clients)
OAuth 2.1 authorization server with PKCE-S256, Dynamic Client Registration (RFC 7591), and discovery metadata (RFC 8414 + RFC 9728). Used by ChatGPT Apps SDK and any other MCP client that supports OAuth. Available to all plans for the MCP resource at /api/v1/mcp. RS256-signed JWT access tokens and the reusable refresh token share a fixed one-year authorization deadline.
OAuth 2.1 Overview
Use OAuth 2.1 when your client needs per-user delegated access to the MCP endpoint and you cannot ship an API key (e.g., a multi-tenant AI assistant). Use API keys when you control both ends and want a simpler integration (Scale plan and above). MCP via OAuth is available on every plan including the free trial.
Endpoints: /oauth/authorize, /oauth/token, /oauth/register, /oauth/jwks.json, /.well-known/oauth-authorization-server, /.well-known/oauth-protected-resource.
GET/.well-known/oauth-authorization-server
Authorization-server metadata at /.well-known/oauth-authorization-server (RFC 8414) and protected-resource metadata at /.well-known/oauth-protected-resource (RFC 9728). The JWKS used to verify access-token signatures lives at /oauth/jwks.json. Clients should fetch these to discover the authorize, token, and registration endpoints, never hard-code them.
No parameters. Returns JSON with issuer, authorization_endpoint, token_endpoint, registration_endpoint, jwks_uri, scopes_supported, code_challenge_methods_supported, and related metadata.
POST/oauth/register
Dynamic Client Registration per RFC 7591. Unauthenticated and rate-limited to 5/hour per IP. Only RFC 7591 fields are persisted (extra fields are dropped). Redirect URIs must be HTTPS (any host) or HTTP loopback (localhost / 127.0.0.1); custom schemes like javascript:, data:, file: are rejected. Maximum 10 redirect URIs per client; client_name capped at 200 chars; URIs capped at 2048 chars.
JSON body: redirect_uris (required array), client_name, grant_types (defaults to authorization_code refresh_token), token_endpoint_auth_method (none for public PKCE clients, client_secret_post for confidential), scope.
GET/oauth/authorize
Renders an in-app consent screen. On approval, redirects the user back to redirect_uri with a single-use code (10-minute TTL) and the original state. PKCE-S256 is mandatory; plain challenges are rejected.
Params: response_type=code (required), client_id (required), redirect_uri (required, must match a registered URI exactly), code_challenge (required), code_challenge_method=S256 (required), scope (space-separated: mcp:read mcp:write), state, resource (RFC 8707 resource indicator).
POST/oauth/token
Exchanges an authorization code for an access token + refresh token, or refreshes an access token. Uses application/x-www-form-urlencoded. Rate-limited to 60/minute per IP. Refresh responses return the same reusable refresh token, and all credentials expire at the fixed one-year authorization deadline.
Body: grant_type (authorization_code or refresh_token), client_id (required), client_secret (required for confidential clients), and either {code, code_verifier, redirect_uri} OR {refresh_token, optional scope for downscoping}.
Scopes & Audience Verification
Two scopes are defined. mcp:read grants access to every read tool (list_*, get_*). mcp:write additionally grants the write tools (create_prompts, create_competitor, create_collection, assign_prompt_tags, create_annotation, create_intelligence_task, launch_recommendations, create_technical_geo_report). A token issued with only mcp:read cannot invoke write tools, both tools/list hides them and direct tools/call returns an error. The JWT aud claim must equal the resource server URL; tokens with a different audience are rejected at /api/v1/mcp.
When refreshing a token, you MAY pass a narrower scope, anything broader than the original grant returns invalid_grant.
Changelog
The three most recent API changes. The full history lives on its own page.
- 2026-08: Native Rust CLI and official SDKs. CLI v2 replaces the JavaScript implementation with native binaries for macOS, Linux and Windows while preserving the existing configuration and profile format. Typed commands cover all 71 REST operations, with JSON, table and CSV output plus a direct REST command. Official generated clients are now maintained for TypeScript, Python, Go, Java, Kotlin, C#, PHP, Ruby, Rust, Swift, Dart and R. The OpenAPI document uses OpenAPI 3.0-compatible nullable fields so every client can be generated with the same pinned toolchain.
-
2026-08:
Automatic annotations and all-plan access (v1.23.0). Annotations are now available on every plan, including Starter and trial accounts. Rows returned by
GET /annotationsand the MCPlist_annotationstool includeorigin:manual,automation,geo_test, orplatform. Automatic project annotations record daily prompt-set changes, enabled AI model changes, and tracking frequency changes. Existing fields and write behavior are unchanged. -
2026-08:
Share of Voice sample sizes and per-model grouping (v1.22.0).
GET /metrics/sovnow returns aperiodsarray with, per bucket, the totalmentionsthe shares were computed on (the sample size: a bucket with 1-3 mentions reads as 100/50/33.33 and should be treated as low-sample) and apartialflag marking buckets still collecting data or clipped by the requested window. Eachcurrentrow also carries precomputed deltas:previous_share(last complete bucket) andavg_share(mean over complete buckets with data; partial buckets excluded). Existing fields are unchanged. The MCPget_sovtool gainsgroup_by=modelreturning one compact per-model share comparison per call (addinclude_series=truefor per-model trend series), every project-scoped MCP tool now accepts the project domain or exact name/brand name inproject_idbesides the numeric id, MCP metric responses include anapp_urlsource link, and MCP metric tools render interactive widgets in hosts that support them: share-of-voice donut, visibility summary card, metric-over-time line chart (get_timeseries) and top cited domains (get_top_sources).