| Endpoint | Purpose |
|---|---|
GET /v1/ai-visibility/:appId/intents | List with metrics — drives the dashboard table |
GET /v1/ai-visibility/:appId/intents/:intentId | Drill-down: prompts + latest AI answers |
POST /v1/ai-visibility/:appId/intents | Manually add an intent |
PATCH /v1/ai-visibility/:appId/intents/:intentId | Rename / pause / archive |
DELETE /v1/ai-visibility/:appId/intents/:intentId | Archive (soft delete) |
List intents with metrics
Query parameters
| Name | Type | Default | Description |
|---|---|---|---|
| country | string | us | ISO country code |
| model | string | chatgpt | One of chatgpt, claude, gemini, perplexity — metrics are scored per model |
Response
| Field | Description |
|---|---|
intentId | UUID — use this for drill-down or update calls. |
label | Display text, sentence-case. |
description | One-sentence explanation of the user goal. May be null for legacy or manually-added intents. |
status | active (scanned daily), paused (kept around but not scanned), archived (hidden from list endpoints). |
source | llm (generated by the bootstrap), user (you added it manually). |
visibilityPct | % of this intent’s prompts where your app appeared, position-weighted. |
sentimentPct | Average tone of the assistant when it mentioned your app, on a 0–100% scale. null if you weren’t mentioned at all. |
positionAvg | Average rank in the assistant’s list when your app was mentioned. null if you weren’t mentioned. |
promptsTotal | Number of active prompts under this intent (those used in the most recent scan). |
topApps | Up to 3 apps most frequently surfaced for this intent in the latest scan. isOwnerApp: true marks your own app. |
Drill into one intent
Query parameters
| Name | Type | Default | Description |
|---|---|---|---|
| country | string | us | ISO country code |
| model | string | chatgpt | Filters the latest answers to this model |
Response (truncated)
prompts[].latestAnswers[].apps list is ordered by position. apps[].trackId is null when the assistant mentioned an app we couldn’t confidently match against the App Store (very rare brands or a misspelling).
For the raw model output and parsed sentiment per app, use GET /answers/:answerId with the answerId returned here.
Add an intent manually
- The LLM bootstrap missed something (e.g. a niche use case).
- You’re launching a new feature and want to start tracking visibility for it before the first scan.
- You want to track a specific competitor angle (“Apps similar to Calm”).
Body
| Field | Type | Required | Description |
|---|---|---|---|
label | string | Yes | Sentence-case user goal, 8–80 chars |
description | string | No | One-sentence explanation, ≤ 200 chars |
Response
fingerprint is a content hash. Re-posting the same label is safe — it returns the existing intent rather than creating a duplicate.
Update / pause / archive
status: "paused" to keep the intent and its prompts visible but stop sending them to the AI models in the next scan. Use status: "archived" (or DELETE) to hide it everywhere.
Delete (archive)
PATCH { status: "archived" }.
Code examples
Credits
| Endpoint | Cost |
|---|---|
GET /intents | 2 credits |
GET /intents/:intentId | 2 credits |
POST /intents | 1 credit |
PATCH /intents/:intentId | Free |
DELETE /intents/:intentId | Free |
Errors
| Status | Code | When |
|---|---|---|
| 400 | INVALID_INPUT | label shorter than 8 characters or status is not one of the allowed values |
| 404 | NOT_FOUND | Intent doesn’t exist or doesn’t belong to this app |
| 401 | — | Missing or invalid API key / JWT |
| 429 | — | Insufficient monthly credits |

