Integrations and API
REST API
Pull your AI Peekaboo data programmatically using an API key, with read or read+write scopes, filtering, and bulk writes.
7 minute read · Last reviewed: August 14, 2026
You want to pull your AI Peekaboo data programmatically, whether that's for a custom dashboard, an automation, or feeding another tool.
Base URL and authentication
The API base URL is:
https://www.aipeekaboo.com/api/v1Authenticate every request with an X-API-Key header (a lowercase x-api-key or an Authorization: Bearer header work too). Your key looks like:
pk_{projectId}_{secret}Generate a key from Settings → Integrations. You can revoke a key at any time from the same page.
Read vs. read+write scopes
When you generate a key, you choose its scope:
- Read keys can pull data: brands, visibility, competitors, sources, prompts, categories, and recommended prompts.
- Read+write keys can also create, update, and delete brands, prompts, competitors, and categories.
The read endpoints you'll use most
These GET endpoints cover the same core data you see in the dashboard. Any valid key can call them.
| Endpoint | Method | What it returns |
|---|---|---|
/brands | GET | Every brand in your project, with basic detail |
/brands/:brandId | GET | One brand's metadata: name, URL, industry, prompt and competitor counts, analysis frequency |
/brands/:brandId/snapshot | GET | Visibility score, top prompts, top sources, competitor rankings, and traffic in one pre-computed call |
/brands/:brandId/visibility | GET | Visibility score, trend, and market share for a 7d, 30d, or 90d window |
/brands/:brandId/competitors | GET | Competitor scores on the same formula as your brand, plus traffic and rank |
/brands/:brandId/sources | GET | Domains cited by AI models, with model attribution and mention counts |
/brands/:brandId/prompts | GET | Your tracked prompts with score, trend, best and worst score, and search intent |
/brands/:brandId/prompts/:promptId | GET | One prompt's per-run history, including cited article URLs and every entity mentioned |
/brands/:brandId/categories | GET | Your prompt categories with aggregate performance per category |
/brands/:brandId/recommendations | GET | Gap-driven prompt suggestions tied to real measured gaps, not generic ideas |
A worked example: the snapshot call
One authenticated GET gives you the whole picture for a brand:
curl -H "X-API-Key: $API_KEY" \
https://www.aipeekaboo.com/api/v1/brands/$BRAND_ID/snapshotThe response wraps everything in the standard envelope, with the payload under data:
{
"success": true,
"data": {
"brand": { "id": "a1b2c3d4-...", "name": "Acme Corp" },
"snapshotDate": "2026-02-24T02:00:00.000Z",
"visibility": {
"score": 42,
"rank": 3,
"maxScore": 100,
"totalCitations": 87,
"totalChatsAnalyzed": 40
},
"prompts": [
{
"promptText": "Best project management tools for teams",
"category": "Discovery",
"mentions": 8,
"averageScore": 78,
"aiModels": ["gpt-4o-mini", "gemini-2.5-flash", "sonar"]
}
],
"sources": [
{ "domain": "forbes.com", "mentions": 12, "aiModels": ["gpt-4o-mini"] }
],
"competitors": [
{
"id": "c1d2e3f4-...",
"name": "Competitor A",
"url": "https://competitor-a.com",
"score": 58,
"change": "+12%",
"monthlyVisits": 4500000,
"globalRank": 12000,
"rank": 1
}
],
"aiSuggestions": ["Focus on discovery prompts where competitors outrank you"],
"traffic": {
"monthlyVisits": 250000,
"globalRank": 45000,
"countryRank": 8500,
"bounceRate": 0.42,
"pagesPerVisit": 3.2,
"avgTimeOnSite": 185
}
},
"metadata": {
"requestId": "550e8400-e29b-41d4-a716-446655440000",
"timestamp": "2026-02-25T14:30:00.000Z",
"queryTimeMs": 10
}
}Every response uses that same envelope: success, then data, then metadata carrying a requestId worth quoting in any support ticket. Paginated endpoints add a pagination object with offset, limit, total, and hasMore. If analysis hasn't run for the brand yet, snapshot comes back null rather than erroring.
Query parameters for filtering and paging
| Parameter | Default | Accepted values | Works on |
|---|---|---|---|
time_range | 7d | 7d, 30d, 90d | /visibility, /prompts, /prompts/:promptId, /categories |
offset | 0 | 0 or greater | /prompts |
limit | 50 | 1 to 200 | /prompts |
category | none | Any of your category names | /prompts |
search_intent | none | INFORMATIONAL, COMMERCIAL, TRANSACTIONAL, NAVIGATIONAL, LOCAL, INVESTIGATIONAL, SENTIMENT, BRANDED | /prompts, /categories |
Ninety days is the longest window the API will serve, and no all-time option exists, so anything longer has to be pulled on a schedule and stored on your side.
curl -H "X-API-Key: $API_KEY" \
"https://www.aipeekaboo.com/api/v1/brands/$BRAND_ID/prompts?time_range=30d&search_intent=COMMERCIAL&limit=200&offset=0"The write endpoints
A read+write key unlocks create, update, and delete across brands, prompts, competitors, and categories. The bulk routes are the reason to bother: the dashboard adds items one at a time, and these load a whole account in one call.
| Endpoint | Method | What it does |
|---|---|---|
/brands | POST | Create a brand (name required, plus optional url, industry, productDescription) |
/brands/:brandId | PUT | Update a brand's name, URL, industry, or description |
/brands/:brandId | DELETE | Soft-delete a brand |
/brands/:brandId/prompts | POST | Add one prompt |
/brands/:brandId/prompts/bulk | POST | Add up to 100 prompts in one request |
/brands/:brandId/prompts/:promptId | PUT | Edit a prompt's text or category |
/brands/:brandId/prompts/:promptId | DELETE | Soft-delete one prompt |
/brands/:brandId/prompts/bulk-delete | POST | Soft-delete up to 100 prompts by ID |
/brands/:brandId/competitors | POST | Add one competitor |
/brands/:brandId/competitors/bulk | POST | Add up to 50 competitors in one request |
/brands/:brandId/competitors/:competitorId | PUT / DELETE | Update or remove a competitor |
/brands/:brandId/categories | POST | Create a prompt category |
/brands/:brandId/categories/:categoryId | PUT / DELETE | Update or remove a category |
Field length limits are enforced server side: brand and competitor names up to 200 characters, URLs up to 500, prompt text up to 1,000, category names up to 100, and product descriptions up to 2,000. Anything longer comes back as INVALID_PARAMS rather than being silently truncated.
Error codes and what they mean
Errors come back with success: false and an error object holding a code, a human-readable message, and sometimes details.
| Code | HTTP | What went wrong |
|---|---|---|
UNAUTHORIZED | 401 | No X-API-Key header, or the key is invalid or revoked |
FORBIDDEN | 403 | A read-only key hit a write endpoint, or writes are temporarily disabled |
SUBSCRIPTION_INACTIVE | 403 | No active subscription on the project, or it has lapsed |
LIMIT_EXCEEDED | 403 | You hit a plan limit, typically max prompts, competitors, or brands |
INVALID_PARAMS | 400 | Bad UUID, out-of-range pagination, or a body that failed validation |
NOT_FOUND | 404 | The brand or prompt doesn't exist, or isn't in your project |
CONFLICT | 409 | The change collides with existing state, such as a duplicate prompt or competitor name |
RATE_LIMITED | 429 | Per-minute or daily limit reached |
INTERNAL_ERROR | 500 | Something broke on our side. Send us the requestId from metadata |
A brand that belongs to another project returns NOT_FOUND rather than FORBIDDEN, so a 404 on an ID you believe is valid usually means the key belongs to a different project.
Rate limits by plan
Limits are counted per API key, on a per-minute window plus a daily budget that resets at midnight UTC.
| Plan | Per minute | Per day |
|---|---|---|
| Starter and Peek plans | 5 | 50 |
| Grow plans | 20 | 1,000 |
| Custom and Enterprise plans | 40 | 2,000 |
Every response, not just a 429, carries the full set of counters:
| Header | Meaning |
|---|---|
X-RateLimit-Limit | Your per-minute ceiling |
X-RateLimit-Remaining | Requests left in the current minute |
X-RateLimit-Reset | Unix epoch in seconds when the minute window resets |
X-RateLimit-Daily-Limit | Your daily ceiling |
X-RateLimit-Daily-Remaining | Requests left today |
Read X-RateLimit-Remaining before firing the next call and sleep until X-RateLimit-Reset when it reaches zero, rather than retrying into a wall of 429s. Starter and Peek keys hit the ceiling almost immediately, so production automations belong on Grow or higher.
Gotchas worth knowing before you build
- Prompt history uses `aiModel`, not `model`. In each
/prompts/:idhistory entry, the model name lives in theaiModelfield. Readingmodelreturns nothing and collapses every row to "unknown". - Prompt history caps at 100 entries. That endpoint returns the 100 most recent runs with no pagination. Since each run produces one entry per model, a daily brand only reaches back about 20 days. To keep more history, pull on a schedule and store it yourself.
- Only `7d`, `30d`, and `90d` windows work. Any other
time_rangevalue silently falls back to 7 days rather than erroring, so a typo quietly returns the wrong window. - `/recommendations` is slow, so cache it. It runs a fresh model call per suggestion and can take 8 to 15 seconds. Store the result on your side instead of calling it on every page load.
Who can use it
The REST API requires an active paid subscription on any tier. It isn't available on free, no-subscription workspaces.
