REST API Documentation
Access your AI visibility data programmatically via the REST API. Use it with any tool that supports HTTP requests.
TL;DR
Generate a personal API key in your account settings. Then use standard HTTP GET requests with your API key to retrieve visibility scores, mention counts, and sentiment data from ChatGPT, Gemini, Perplexity, and Claude. Works with Excel, Google Sheets, Power BI, Tableau, Python, and any other HTTP client.
Base URL
All API endpoints are available under the following base URL:
https://your-domain.com/api/v1/looker/
Replace your-domain.com with the actual domain of your AI Visibility Tool instance.
Authentication
All API requests require authentication via a personal API key. You can create API keys in your account settings under "API Keys".
How to authenticate
Include your API key in every request using one of these methods:
curl -H "Authorization: Bearer avt_your_key_here" \
https://your-domain.com/api/v1/looker/data
curl "https://your-domain.com/api/v1/looker/data?api_key=avt_your_key_here"
avt_ followed by 48 characters. Keep your API key secret — it provides full read access to your visibility data.
API Key Management
- Create keys: Account menu → API Keys → Create API Key
- Maximum 3 active keys at the same time
- Keys are shown only once at creation — store them securely
- Delete unused keys at any time from the API Keys page
Rate Limits
| Limit | Value |
|---|---|
| Requests per minute | 100 per API key |
| Maximum records per request | 10,000 |
When the rate limit is exceeded, the API returns HTTP 429. Wait 60 seconds before retrying.
Endpoints
Returns the data schema with field names, types, and semantic information. Useful for understanding the data structure before querying.
Parameters: None
Example Request:
curl -H "Authorization: Bearer avt_your_key_here" \
https://your-domain.com/api/v1/looker/schema
Example Response:
{
"schema": [
{
"name": "date",
"label": "Date",
"dataType": "STRING",
"semantics": {
"conceptType": "DIMENSION",
"semanticType": "YEAR_MONTH_DAY"
}
},
{
"name": "visibility_score",
"label": "Visibility Score",
"dataType": "NUMBER",
"semantics": {
"conceptType": "METRIC"
}
}
]
}
Returns your AI visibility analysis results. Supports filtering by date, topic area, and AI system. Includes pagination for large datasets.
Query Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
date_from |
String | No | Start date filter (YYYY-MM-DD) |
date_to |
String | No | End date filter (YYYY-MM-DD) |
selection_id |
Integer | No | Filter by topic area ID (get IDs from /selections endpoint) |
ai_system |
String | No | Filter by AI system: chatgpt, gemini, perplexity, or claude |
limit |
Integer | No | Number of records to return (default: 1000, max: 10000) |
offset |
Integer | No | Number of records to skip for pagination (default: 0) |
Example Request:
curl -H "Authorization: Bearer avt_your_key_here" \
"https://your-domain.com/api/v1/looker/data?date_from=2025-01-01&date_to=2025-01-31&ai_system=chatgpt&limit=500"
Example Response:
{
"data": [
{
"date": "20250115",
"topic_area": "Brand Monitoring",
"prompt": "What is the best project management tool?",
"category": "Product Comparison",
"funnel_stage": "Consideration",
"ai_system": "chatgpt",
"brand": "Asana",
"visibility_score": 75,
"mention_count": 3,
"position_score": 85,
"sentiment_score": 0.8,
"web_search_used": false
}
],
"pagination": {
"total": 1250,
"limit": 500,
"offset": 0,
"has_more": true
}
}
Returns a list of your topic areas (selections) with their IDs. Use these IDs to filter data in the /data endpoint.
Parameters: None
Example Request:
curl -H "Authorization: Bearer avt_your_key_here" \
https://your-domain.com/api/v1/looker/selections
Example Response:
{
"selections": [
{
"id": 42,
"name": "Brand Monitoring",
"description": "Track brand mentions across AI platforms",
"prompt_count": 25,
"is_active": true,
"created_at": "2025-01-10T14:30:00"
}
]
}
Data Fields Reference
Each record in the /data response contains the following fields:
Dimensions
| Field | Type | Description |
|---|---|---|
date |
String | Analysis date in YYYYMMDD format |
topic_area |
String | Name of the topic area (selection) being monitored |
prompt |
String | The prompt text sent to the AI system |
category |
String | Category assigned to the prompt |
funnel_stage |
String | Marketing funnel stage (e.g. Awareness, Consideration, Decision) |
ai_system |
String | The AI platform queried (chatgpt, gemini, perplexity, claude) |
brand |
String | The brand being tracked for mentions |
Metrics
| Field | Type | Range | Description |
|---|---|---|---|
visibility_score |
Number | 0–100 | Overall visibility score for the brand in the AI response |
mention_count |
Number | 0+ | Number of times the brand was mentioned in the AI response |
position_score |
Number | 0–100 | Position ranking score — higher values indicate earlier mentions |
sentiment_score |
Number | -1 to +1 | Sentiment score from -1 (negative) to +1 (positive) |
web_search_used |
Boolean | true/false | Whether the AI system used web search to generate the response |
Response Format
All responses are returned as JSON with UTF-8 encoding. The HTTP Content-Type header is set to application/json.
HTTP Status Codes
| Status Code | Meaning |
|---|---|
| 200 OK | Request successful |
| 401 Unauthorized | API key missing, invalid, or deactivated |
| 429 Too Many Requests | Rate limit exceeded — wait 60 seconds |
Error Handling
Error responses always include a JSON body with an error message:
{
"error": "API key required. Use Authorization: Bearer <key> header or ?api_key=<key> query parameter."
}
| Error | Cause | Solution |
|---|---|---|
API key required |
No API key in request | Add Authorization header or api_key parameter |
Invalid or inactive API key |
Key is wrong, deleted, or deactivated | Check the key on your API Keys page; create a new one if needed |
Rate limit exceeded |
More than 100 requests in 60 seconds | Wait 60 seconds, then retry; consider caching results |
Code Examples
import requests
API_KEY = "avt_your_key_here"
BASE_URL = "https://your-domain.com/api/v1/looker"
headers = {"Authorization": f"Bearer {API_KEY}"}
# Get all topic areas
selections = requests.get(f"{BASE_URL}/selections", headers=headers).json()
print(selections)
# Get visibility data for January 2025
params = {
"date_from": "2025-01-01",
"date_to": "2025-01-31",
"limit": 1000
}
data = requests.get(f"{BASE_URL}/data", headers=headers, params=params).json()
print(f"Total records: {data['pagination']['total']}")
# Paginate through all results
all_records = []
offset = 0
while True:
params["offset"] = offset
response = requests.get(f"{BASE_URL}/data", headers=headers, params=params).json()
all_records.extend(response["data"])
if not response["pagination"]["has_more"]:
break
offset += params["limit"]
print(f"Fetched {len(all_records)} records total")
const API_KEY = "avt_your_key_here";
const BASE_URL = "https://your-domain.com/api/v1/looker";
const headers = { "Authorization": `Bearer ${API_KEY}` };
// Get visibility data
const response = await fetch(`${BASE_URL}/data?date_from=2025-01-01&limit=500`, { headers });
const result = await response.json();
console.log(`Total: ${result.pagination.total} records`);
# Get schema
curl -H "Authorization: Bearer avt_your_key_here" \
https://your-domain.com/api/v1/looker/schema
# Get data with filters
curl -H "Authorization: Bearer avt_your_key_here" \
"https://your-domain.com/api/v1/looker/data?date_from=2025-01-01&ai_system=chatgpt&limit=100"
# Get topic areas
curl -H "Authorization: Bearer avt_your_key_here" \
https://your-domain.com/api/v1/looker/selections
function getVisibilityData() {
const API_KEY = "avt_your_key_here";
const url = "https://your-domain.com/api/v1/looker/data?limit=500";
const options = {
headers: { "Authorization": "Bearer " + API_KEY },
muteHttpExceptions: true
};
const response = UrlFetchApp.fetch(url, options);
const json = JSON.parse(response.getContentText());
// Write data to the active sheet
const sheet = SpreadsheetApp.getActiveSheet();
const headers = Object.keys(json.data[0]);
sheet.getRange(1, 1, 1, headers.length).setValues([headers]);
const rows = json.data.map(row => headers.map(h => row[h]));
sheet.getRange(2, 1, rows.length, headers.length).setValues(rows);
}