> ## Documentation Index
> Fetch the complete documentation index at: https://docs.theaitracker.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Endpoints

> Every endpoint in the v1 External API, with example requests and responses.

All endpoints require a bearer token and are scoped to your own campaigns. A
campaign is addressed by its **uuid** (returned as `uuid`); requesting one you
don't own returns `404`.

Base URL: `https://app.theaitracker.com/api/v1`

## Current user

```http theme={null}
GET /api/v1/me
```

Confirms which account a key belongs to and which plan it's on — the quickest
way to check a key works.

```json theme={null}
{
  "data": {
    "name": "Ada Lovelace",
    "email": "ada@example.com",
    "plan": "starter",
    "plan_label": "Starter"
  }
}
```

## Campaigns

### List campaigns

```http theme={null}
GET /api/v1/campaigns
```

Paginated (`page`, `per_page`). Start here — every other endpoint needs a
campaign `uuid`.

```bash theme={null}
curl -H "Authorization: Bearer <your-key>" \
  https://app.theaitracker.com/api/v1/campaigns
```

```json theme={null}
{
  "data": [
    {
      "uuid": "54219811-af67-46a7-b33a-88aecd5acbc4",
      "name": "API Demo Campaign",
      "domain": "api-demo.example.com",
      "mode": "brand",
      "industry": "SaaS",
      "geographic_market": "US",
      "language": "en",
      "is_active": true,
      "enabled_providers": ["openai", "gemini", "perplexity", "grok"],
      "tags": [],
      "created_at": "2026-08-03T14:02:11+00:00"
    }
  ],
  "links": { "first": "…", "last": "…", "prev": null, "next": null },
  "meta": { "current_page": 1, "per_page": 25, "total": 1 }
}
```

### Get a campaign

```http theme={null}
GET /api/v1/campaigns/{uuid}
```

The same fields as the list, plus a `visibility_summary` for the last 30 days.

```json theme={null}
{
  "data": {
    "uuid": "54219811-…",
    "name": "API Demo Campaign",
    "visibility_summary": {
      "period": { "from": "2026-07-04", "to": "2026-08-03", "days": 30 },
      "overall": {
        "runs": 98,
        "with_visibility": 49,
        "score": 42,
        "link_rate": 33.7,
        "mention_rate": 16.3,
        "trend": -11,
        "trend_direction": "down"
      }
    }
  }
}
```

<Note>
  `score` is the visibility percentage (0–100), computed exactly as in the app:
  a run where your brand is **linked** counts as 1.0, a run where it's only
  **mentioned** counts as 0.5.
</Note>

## Visibility

```http theme={null}
GET /api/v1/campaigns/{uuid}/visibility
```

<ParamField query="days" type="integer" default="30">
  Window for the overall summary (1–365).
</ParamField>

<ParamField query="from" type="date">
  Start date for the per-provider breakdown (`YYYY-MM-DD`).
</ParamField>

<ParamField query="to" type="date">
  End date for the per-provider breakdown.
</ParamField>

```json theme={null}
{
  "data": {
    "period": { "from": "2026-07-04", "to": "2026-08-03", "days": 30 },
    "overall": { "runs": 98, "score": 42, "trend": -11, "trend_direction": "down" },
    "by_provider": [
      { "provider": "openai", "runs": 48, "with_visibility": 30, "score": 53, "link_rate": 43.8, "mention_rate": 18.8 }
    ]
  }
}
```

<Note>
  `by_provider` only contains platforms your plan actually runs. On Starter
  that's ChatGPT (`openai`) alone — see
  [Plans and billing](/guides/billing).
</Note>

## Prompts

### List prompts

```http theme={null}
GET /api/v1/campaigns/{uuid}/prompts
```

Paginated. Each prompt carries a `runs_count`.

```json theme={null}
{
  "data": [
    {
      "id": 12,
      "text": "best analytics tools for startups",
      "is_active": true,
      "status": "active",
      "tags": [],
      "location_code": "us",
      "est_volume": 1400,
      "runs_count": 32,
      "last_run_at": "2026-08-02T06:00:00+00:00"
    }
  ],
  "meta": { "current_page": 1, "per_page": 25, "total": 6 }
}
```

### Create prompts

```http theme={null}
POST /api/v1/campaigns/{uuid}/prompts
```

The only write endpoint. Adds one prompt, or several in a single request, and
returns `201` with the created prompts.

<ParamField body="text" type="string | string[]" required>
  One prompt, or several as a list — **one per line**. Leading `1.`, `2)`,
  `(3)`, `-` or `*` markers are stripped. Pass a JSON array instead when a
  prompt itself contains newlines; array elements are never split.
</ParamField>

<ParamField body="topic" type="string" required>
  Topic to file the prompts under, applied to the whole request. Matched
  case-insensitively against the campaign's topics and **created if there is no
  match**.
</ParamField>

<ParamField body="location_code" type="string" default="us">
  Two-letter market code, e.g. `us`, `gb`.
</ParamField>

<ParamField body="tags" type="string[]">
  Up to 8 tags, max 24 characters each. Lowercased on save.
</ParamField>

```json theme={null}
{
  "text": "1. best analytics tools for startups\n2. cheapest analytics with Xero sync",
  "topic": "Analytics",
  "location_code": "gb",
  "tags": ["comparison"]
}
```

The response carries the created prompts in `data`, with `meta` explaining what
happened to the batch:

```json theme={null}
{
  "data": [ /* prompt objects */ ],
  "meta": {
    "created_count": 2,
    "skipped": [],
    "topic": { "id": 4, "name": "Analytics", "created": true },
    "inactive_count": 0,
    "remaining_slots": 8,
    "note": "Added 2 prompts."
  }
}
```

**Limits.** Max 2,000 characters per prompt and 50 prompts per request.
Over-long prompts are *skipped and reported* in `meta.skipped` rather than
failing the rest; a request where every prompt is over-long returns `422` and
creates nothing.

<Warning>
  A campaign only tracks a capped number of **active** prompts. Anything past
  the cap is still created but left inactive and will not run — check
  `meta.inactive_count` and `meta.remaining_slots`. Nothing is silently
  dropped, but nothing beyond the cap starts running either. See
  [the active prompt cap](/guides/prompts#the-active-prompt-cap).
</Warning>

### Prompt runs

```http theme={null}
GET /api/v1/campaigns/{uuid}/prompt-runs
```

The raw per-provider answers over time — the actual text each AI platform
returned, and the sources it cited.

<ParamField query="prompt_id" type="integer">
  Limit to a single prompt.
</ParamField>

<ParamField query="provider" type="string">
  Filter by provider (e.g. `openai`, `gemini`, `perplexity`, `grok`).
</ParamField>

<ParamField query="from" type="date" />

<ParamField query="to" type="date" />

```json theme={null}
{
  "data": [
    {
      "id": 9001,
      "prompt_id": 12,
      "provider": "openai",
      "model": "gpt-4o",
      "answer": "…",
      "sources": [{ "title": "…", "url": "https://…" }],
      "link_visibility": true,
      "mention_visibility": true,
      "error": null,
      "created_at": "2026-08-02T06:00:00+00:00"
    }
  ],
  "meta": { "current_page": 1, "per_page": 25, "total": 192 }
}
```

<Tip>
  Answers are long. Filter by `prompt_id` and a date range rather than paging
  through everything — and remember `per_page` maxes out at 100.
</Tip>

## Sentiment

```http theme={null}
GET /api/v1/campaigns/{uuid}/sentiment
```

<ParamField query="platform" type="string">
  Filter by AI platform (`openai`, `gemini`, `perplexity`).
</ParamField>

<ParamField query="from" type="date" />

<ParamField query="to" type="date" />

```json theme={null}
{
  "data": [
    {
      "id": 5,
      "llm_platform": "openai",
      "domain": "api-demo.example.com",
      "brand_sentiment": 6,
      "brand_awareness": 8,
      "normalized_sentiment": 8,
      "converted_sentiment": 8,
      "summary_text": "…",
      "positive_findings": ["…"],
      "negative_findings": ["…"],
      "created_at": "2026-08-01T09:00:00+00:00",
      "mentions": [
        {
          "mention_term": "API Demo",
          "page_url": "https://…",
          "mention_type": "linked",
          "context_text": "…",
          "sentiment_classification": "positive",
          "confidence_score": "0.82"
        }
      ]
    }
  ],
  "meta": { "current_page": 1, "per_page": 25, "total": 3 }
}
```

## Traffic

```http theme={null}
GET /api/v1/campaigns/{uuid}/traffic
```

Analytics and Search Console sessions per day, source and medium. Returns
nothing until the campaign has a
[connected integration](/integrations/overview).

<ParamField query="from" type="date" />

<ParamField query="to" type="date" />

<ParamField query="source" type="string" />

<ParamField query="medium" type="string" />

```json theme={null}
{
  "data": [
    { "date": "2026-08-03", "sessions": 504, "source": "direct", "medium": "none" }
  ],
  "meta": { "current_page": 1, "per_page": 25, "total": 120 }
}
```


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.