# API overview

> Base URL, response envelope, pagination, plan access, the OpenAPI spec and API versioning.

The trackagoat API is a REST API over HTTPS. Authenticate with a Bearer API key, send and receive JSON, and every response has the same shape: `{ data, error, meta }`. Every plan includes API access: Free allows 200 requests a day, Starter 1,000 and Ultra 50,000, with a per-key limit of 60 a minute. See [Plans and limits](https://www.trackagoat.com/docs/guides/limits.md) for the live numbers.

**Base URL:** `https://www.trackagoat.com/api/v2`

**Install with your coding agent.** Paste this prompt into Claude Code, Codex, Cursor or another coding agent. It installs the MCP server, has you sign in, and checks the connection.

Prompt to paste:

```text
Install the trackagoat MCP server in this client and connect it to my trackagoat account. trackagoat tracks creators' public TikTok and Instagram posts, works out what each creator is owed from the payout structures I set up, and shows which creators need attention. Its MCP server can read all of that and do the day-to-day work too: add creators and videos, set goals, manage payout structures and record payments. Every record in trackagoat, and each person, has a Markdown document: read the relevant ones before you act, and add what you find.

Details: https://www.trackagoat.com/docs/agents/mcp.md. If I don't have an account yet, follow https://www.trackagoat.com/docs/agents/setup.md instead.

Every plan includes MCP and API access. New organizations start on Free, which allows 200 requests a day (each MCP tool call counts as one) and 1 API key. Starter and Ultra raise those limits; to upgrade, I email support@trackagoat.com with my organization name and the plan I want. If a call fails with rate_limit_exceeded, wait the retry_after_seconds it returns before trying again.

Rules:
- Don't create accounts, sign in for me or type passwords. Tell me what to open and click, then wait for me.
- Don't ask me to paste an API key into this chat, and never print, log or commit one. If a key is needed, I'll set the TRACKAGOAT_API_KEY environment variable myself.

Steps:

1. Connect the trackagoat MCP server: https://www.trackagoat.com/api/mcp (Streamable HTTP). Use sign-in (OAuth) first, because it needs no API key: a trackagoat page opens, I pick the organization and choose "View data", plus "Make changes" if you should be able to change things, such as adding creators, setting goals or recording payouts. Set it up for the client you are running in:
   - Claude Code: run `claude mcp add --transport http trackagoat https://www.trackagoat.com/api/mcp`. Then I run /mcp, choose trackagoat and sign in.
   - Codex CLI: run `codex mcp add trackagoat --url https://www.trackagoat.com/api/mcp`, then `codex mcp login trackagoat`.
   - Cursor: add `"trackagoat": { "url": "https://www.trackagoat.com/api/mcp" }` under "mcpServers" in ~/.cursor/mcp.json. Then I sign in from Cursor's MCP settings.
   - VS Code: add `"trackagoat": { "type": "http", "url": "https://www.trackagoat.com/api/mcp" }` under "servers" in .vscode/mcp.json. Then I start the server and sign in.
   - Claude.ai or Claude Desktop: I add a custom connector with that URL in Settings → Connectors. You cannot do this step.
   Sign-in is the best way for each person to connect their own agent: it identifies them directly, so nobody shares a key. Only if this client can't sign in, use an API key instead. An org admin creates one in trackagoat under Org settings → API keys; the key acts as one member (under "Acts as"), so it should act as me. I set it as TRACKAGOAT_API_KEY. You configure the client to send `Authorization: Bearer <key>`, read from that variable, never written out. The setup guide has the exact config for each client.

2. Check the connection: call the list_projects tool and show me my project names. If the trackagoat tools don't appear yet, ask me to restart this session or reload the client, then try again. Then call get_my_profile to see who you're connected as and whether I already have a personalization document; if I do, follow it.

3. Offer to write my personalization document together, so every future session starts knowing me. It's the Markdown document in trackagoat under Settings → My README, and trackagoat sends it to you at the start of each session. Ask me a few short questions, one or two at a time:
   - who I am and my role;
   - what my job is in running the creator program;
   - the program, creators and goals I care about most;
   - how I most want you to help;
   - preferences: tone, how often to check in, what to look at first, and what you should never do without asking.
   Draft it in Markdown with these headings: About me, My job in the program, What I care about, How to help me, Preferences, Never without asking. Show me the draft, and save it with update_my_readme only after I approve. Everyone in my organization, and their agents, can read it, so leave out anything private. If I say no, move on. Later, when my role or preferences change, offer to update it.
```

## Machine-readable spec

This is the one place these locations are documented; other pages link here.

- **OpenAPI spec:** [`GET /api/v2/openapi.json`](https://www.trackagoat.com/api/v2/openapi.json). Import it into Postman, Insomnia or any OpenAPI-compatible tool, or generate a client from it.
- **Data model:** [`GET /api/v2/schema`](https://www.trackagoat.com/api/v2/schema). Entities, fields and relationships. See [OpenAPI and schema](https://www.trackagoat.com/docs/api-reference/schema.md).
- **MCP server:** `https://www.trackagoat.com/api/mcp`, for Claude and other MCP clients. See [MCP server](https://www.trackagoat.com/docs/agents/mcp.md).
- **Changelog:** [`GET /api/v2/changelog`](https://www.trackagoat.com/api/v2/changelog). Every changelog entry as JSON, newest first. No API key needed. See [Changelog API](https://www.trackagoat.com/docs/api-reference/changelog.md).
- **These docs as Markdown:** [`/llms.txt`](https://www.trackagoat.com/llms.txt), or append `.md` to any docs URL. See [llms.txt and raw docs](https://www.trackagoat.com/docs/agents/llms-txt.md).

> **Note:**
>
> The apex domain `trackagoat.com` redirects to `www.trackagoat.com`. Always use `www.trackagoat.com` as your base URL to avoid redirect overhead.

## The multi-platform model

Trackagoat 2.0 is multi-platform. A **creator** is a person or brand, and an **account** is one of their presences on a platform (`tiktok` or `instagram`; the `platform` enum also accepts `youtube`, reserved for YouTube tracking, which isn't available yet). A creator owns one or more accounts, and **videos hang off accounts**.

- Creators embed their `accounts[]` array and expose a derived top-level `handle` (the primary account's handle: TikTok first, else earliest-created).
- Tracking configuration (`tracking_mode`, start/end dates, the handle) lives on the **account**, not the creator.
- Plan limits count **accounts**: the thing that gets scraped: not creators.

See the [Creators and accounts guide](https://www.trackagoat.com/docs/guides/accounts.md) for the full concept.

## Authentication

See [Authentication](https://www.trackagoat.com/docs/api-reference/authentication.md) for how to generate and use API keys.

## Response envelope

Every endpoint returns JSON with this shape:

```json
{
  "data": <payload or null>,
  "error": <error string or null>,
  "meta": <pagination info or null>
}
```

Successful responses have `data` set and `error: null`. Error responses have `data: null` and `error` set to a message string.

## Pagination

List endpoints use **cursor-based pagination**:

```bash
GET /api/v2/creators?limit=50&cursor=<value>
```

| Parameter | Default | Max | Description |
|-----------|---------|-----|-------------|
| `limit` | 50 | 100 | Items per page |
| `cursor` | None | None | Pass `meta.nextCursor` from the previous response |

The `meta` object on list responses:

```json
{
  "hasMore": true,
  "nextCursor": "2026-03-15T10:00:00Z"
}
```

Keep fetching until `meta.hasMore` is `false`.

## Date ranges

Analytics and stats endpoints accept `?from=YYYY-MM-DD&to=YYYY-MM-DD`. Both default to the last 30 days if omitted.

```bash
GET /api/v2/analytics?entity=creator&entity_id=<uuid>&metric=views&from=2026-01-01&to=2026-03-31
```

## API key scopes

Keys carry explicit permission scopes set at creation time:

| Scope | Grants access to |
|-------|-----------------|
| `read` | All `GET` endpoints |
| `write` | All `POST`, `PATCH`, and `DELETE` endpoints |
| `admin` | Org-administration endpoints (projects, members, invitations, API keys, creating orgs), PIN reads and hard deletes. Only effective while the key's owner is an **org admin** |

Write endpoints reject keys that only have `read` scope with **403 `insufficient_scope`**.

A key acts on behalf of one member: the person who created it, or the member an org admin picked under **Acts as**. It can never do more than that member can in the app. Its scopes are a ceiling, checked against the member's **current** org role on every request: if they are demoted from org admin the key loses `admin` and admin-only actions (`403 insufficient_role`), and if they leave or are removed from the org the key stops working (`401 key_member_removed`). A key made for someone else also stops working if the admin who created it leaves, is changed to member or is suspended (`401 key_creator_removed`, `key_creator_not_admin`, `key_creator_banned`). `GET /api/v2/me` shows who a key acts as.

## Idempotency

POST endpoints that create resources accept an `Idempotency-Key` header (≤ 255 characters). Send a fresh UUID per logical request; if the call times out or the connection drops, retry with the **same key and the same body**. The action runs at most once.

| You send the key again… | You get |
|---|---|
| after the first request finished, with the same body | The original status and body, plus an `Idempotency-Replay: true` header. Nothing runs again. |
| while the first request is still running | **409 `idempotency_in_progress`** with a `Retry-After` header (seconds). Wait, then retry with the same key. |
| with a different body | **422 `idempotency_key_reused`**. A key belongs to one request; use a new key for a new request. |
| on a different endpoint | **409 `idempotency_conflict`** |
| more than 24 hours after its last use | Treated as a new key: the request runs. |

Which outcomes are replayed:

- **2xx and 4xx are stored and replayed** for 24 hours, whether the request succeeded or was rejected (for example a `400 invalid_body` or a `404` on one item in a batch). Fix the request and send it with a **new** key.
- **5xx and 429 are not stored.** Retry with the same key and the request runs again.
- A few retryable conflicts are not stored either, such as the `409 notes_conflict` / `notes_busy` on the notes endpoint.

Body comparison ignores key order and whitespace in the JSON.

Secrets are never stored in the replay cache. A replayed API-key creation returns `key: null`, and a replayed share-link creation returns `pin: null`; fetch a PIN with `GET /api/v2/creators/{id}/share-link?include_pin=true` and a `write`-scope key.

```bash
curl -X POST \
  -H "Authorization: Bearer tga_<key>" \
  -H "Idempotency-Key: 550e8400-e29b-41d4-a716-446655440000" \
  -H "Content-Type: application/json" \
  -d '{"accounts": [{"platform": "tiktok", "handle": "charlidamelio"}]}' \
  "https://www.trackagoat.com/api/v2/projects/<id>/creators"
```

## API versioning

The current version is **v2**. All endpoints live under `/api/v2/`.

**v1 has been removed.** Every `/api/v1/*` path now returns **410 Gone** with a pointer to its successor:

```json
{
  "data": null,
  "error": "API v1 has been removed. Use /api/v2 (see /docs/api-reference/overview).",
  "meta": { "code": "api_version_removed", "successor": "/api/v2" }
}
```

The response also carries a `Link: </api/v2>; rel="successor-version"` header. If you are migrating from v1, the biggest change is the [accounts model](https://www.trackagoat.com/docs/guides/accounts.md): a creator no longer has a `tiktok_handle`. It carries an `accounts[]` array, and you create creators with a list of accounts.

## Available endpoints

For the full machine-readable spec, download [`/api/v2/openapi.json`](https://www.trackagoat.com/api/v2/openapi.json).

### Creators

| Method | Path | Scope | Description |
|--------|------|-------|-------------|
| `GET` | `/api/v2/creators` | read | List creators (accounts embedded) |
| `POST` | `/api/v2/creators` | write | Create a creator with one or more accounts |
| `POST` | `/api/v2/projects/{id}/creators` | write | Add creator(s) to a project; bulk up to 50 |
| `GET` | `/api/v2/creators/{id}` | read | Get a creator |
| `PATCH` | `/api/v2/creators/{id}` | write | Update creator-level fields |
| `DELETE` | `/api/v2/creators/{id}` | write | Soft-delete creator |
| `POST` | `/api/v2/creators/{id}/scrape` | write | Trigger manual scrape (primary account, or one via `?account_id=`) |

### Accounts

| Method | Path | Scope | Description |
|--------|------|-------|-------------|
| `GET` | `/api/v2/accounts` | read | List accounts |
| `GET` | `/api/v2/creators/{id}/accounts` | read | List a creator's accounts |
| `POST` | `/api/v2/creators/{id}/accounts` | write | Add an account to a creator |
| `GET` | `/api/v2/accounts/{id}` | read | Get an account |
| `PATCH` | `/api/v2/accounts/{id}` | write | Rename handle / change tracking config |
| `DELETE` | `/api/v2/accounts/{id}` | write | Soft-delete account |
| `POST` | `/api/v2/accounts/{id}/scrape` | write | Trigger a scrape for a single account |
| `GET` | `/api/v2/accounts/{id}/stats` | read | Follower/stat snapshot history |

### Videos

| Method | Path | Scope | Description |
|--------|------|-------|-------------|
| `GET` | `/api/v2/videos` | read | List videos (filter by platform / account / content group) |
| `POST` | `/api/v2/projects/{id}/videos` | write | Add video(s) by URL; bulk up to 50 |
| `PATCH` | `/api/v2/videos/{id}` | write | Update title, readme, tracking_status |
| `DELETE` | `/api/v2/videos/{id}` | write | Remove video from tracking (sets `tracking_status: excluded`; the row is kept) |
| `POST` | `/api/v2/videos/{id}/scrape` | write | Refresh this video's stats |
| `POST` | `/api/v2/videos/{id}/tracking-disable` | write | Disable tracking |
| `POST` | `/api/v2/videos/{id}/tracking-enable` | write | Re-enable tracking |
| `POST` | `/api/v2/videos/{id}/tracking-unexempt` | write | Remove exemption flag |

### Content Groups

| Method | Path | Scope | Description |
|--------|------|-------|-------------|
| `GET` | `/api/v2/content-groups` | read | List content groups |
| `POST` | `/api/v2/content-groups` | write | Create a content group |
| `GET` | `/api/v2/content-groups/{id}` | read | Get a content group |
| `PATCH` | `/api/v2/content-groups/{id}` | write | Rename / edit notes / add or remove members |
| `DELETE` | `/api/v2/content-groups/{id}` | write | Delete a content group |
| `GET` | `/api/v2/content-groups/{id}/stats` | read | Combined stats across the group |

### Campaigns, Projects, Goals

| Method | Path | Scope | Description |
|--------|------|-------|-------------|
| `GET` | `/api/v2/campaigns` | read | List campaigns |
| `POST` | `/api/v2/projects/{id}/campaigns` | write | Create campaign |
| `PATCH` | `/api/v2/campaigns/{id}` | write | Update campaign |
| `DELETE` | `/api/v2/campaigns/{id}` | write | Delete campaign |
| `POST` | `/api/v2/campaigns/{id}/items` | write | Add item to campaign |
| `DELETE` | `/api/v2/campaigns/{id}/items` | write | Remove item from campaign |
| `GET` | `/api/v2/projects` | read | List projects |
| `POST` | `/api/v2/organizations/{id}/projects` | admin | Create project |
| `PATCH` | `/api/v2/organizations/{id}/projects/{pid}` | admin | Update project |
| `PATCH` | `/api/v2/projects/{id}/inbox` | write | Approve/exclude inbox videos |
| `POST` | `/api/v2/creators/{id}/goals` | write | Create goal (platform-scoped) |
| `PATCH` | `/api/v2/creators/{id}/goals/{gid}` | write | Update goal |
| `DELETE` | `/api/v2/creators/{id}/goals/{gid}` | write | Delete goal |

### Organizations, Members, Invitations, API Keys

| Method | Path | Scope | Description |
|--------|------|-------|-------------|
| `POST` | `/api/v2/user/organizations` | admin | Create organization |
| `POST` | `/api/v2/organizations/{id}/members` | admin | Add member |
| `PATCH` | `/api/v2/organizations/{id}/members/{uid}` | admin | Change member role |
| `DELETE` | `/api/v2/organizations/{id}/members/{uid}` | admin | Remove member |
| `POST` | `/api/v2/organizations/{id}/invitations` | admin | Send invitation |
| `DELETE` | `/api/v2/organizations/{id}/invitations/{iid}` | admin | Revoke invitation |
| `POST` | `/api/v2/organizations/{id}/api-keys` | admin | Create API key (only with scopes the calling key holds) |
| `DELETE` | `/api/v2/organizations/{id}/api-keys/{kid}` | admin | Revoke API key |

### Payouts

| Method | Path | Scope | Description |
|--------|------|-------|-------------|
| `GET/POST` | `/api/v2/payout-structures` | read/write | List / create payout structures |
| `GET/PATCH/DELETE` | `/api/v2/payout-structures/{id}` | read/write | Read / update / delete structure |
| `GET/POST/DELETE` | `/api/v2/payout-structures/{id}/assignments` | read/write | Manage creator assignments |
| `GET/POST` | `/api/v2/payout-methods` | read/write | List / create payout methods |
| `GET/PATCH/DELETE` | `/api/v2/payout-methods/{id}` | read/write | Read / update / delete method |
| `GET/POST` | `/api/v2/payout-payments` | read/write | List / create payments |
| `GET/PATCH` | `/api/v2/payout-payments/{id}` | read/write | Read / update payment |
| `GET/PATCH` | `/api/v2/payout-accruals/{id}` | read/write | Read / update accrual |
| `GET/POST` | `/api/v2/projects/{projectId}/conversion-events` | read/write | List / create conversion event types |
| `GET/PATCH/DELETE` | `/api/v2/projects/{projectId}/conversion-events/{id}` | read/write | Read / update / deactivate an event type (`?mode=hard` needs `admin`) |
| `GET/POST` | `/api/v2/projects/{projectId}/conversions` | read/write | List / record conversions (single or batch up to 500) |
| `GET/DELETE` | `/api/v2/projects/{projectId}/conversions/{id}` | read/write | Read / void a conversion (`?mode=hard` needs `admin`) |
| `POST` | `/api/v2/payouts/payment-receipts/upload-url` | write | Get signed receipt upload URL |

### Analytics

| Method | Path | Scope | Description |
|--------|------|-------|-------------|
| `GET` | `/api/v2/analytics` | read | Unified analytics (time-series + aggregates) |
| `GET` | `/api/v2/schema` | read | Machine-readable data model |

### Notes and documents

| Method | Path | Scope | Description |
|--------|------|-------|-------------|
| `GET` | `/api/v2/notes` | read | Every document with text in the org, with previews (filter by type, project or text) |
| `GET` | `/api/v2/notes/{entity_type}/{id}` | read | One document in full, with its `readme_version` |
| `POST` | `/api/v2/notes/{entity_type}/{id}` | write | Append to or replace a document (organization, project and payout documents need an org admin) |
| `GET` | `/api/v2/me` | read | Who the key acts as, and their personalization document |
| `PATCH` | `/api/v2/me` | write | Replace that person's personalization document |
| `GET` | `/api/v2/members` | read | The org's members and whether each has a personalization document |

See [Notes and documents API](https://www.trackagoat.com/docs/api-reference/notes.md).

### CSV exports

| Method | Path | Scope | Description |
|--------|------|-------|-------------|
| `GET` | `/api/v2/exports/{dataset}` | read | The same CSV as the app's Export buttons: creators, videos, campaigns, goals, campaign leaderboard, payouts tracker, payments, accruals or analytics |

See [CSV exports](https://www.trackagoat.com/docs/api-reference/exports.md).

### Changelog

| Method | Path | Scope | Description |
|--------|------|-------|-------------|
| `GET` | `/api/v2/changelog` | none (public) | trackagoat's changelog, newest first; filter by `since` and `q` |

- [Authentication](https://www.trackagoat.com/docs/api-reference/authentication.md): API key setup and Bearer token usage.
- [Errors](https://www.trackagoat.com/docs/api-reference/errors.md): Status codes, rate limits, and error handling.
- [Schema](https://www.trackagoat.com/docs/api-reference/schema.md): Machine-readable data model for agents.

---
Source: https://www.trackagoat.com/docs/api-reference/overview
