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 for the live numbers.
Base URL: https://www.trackagoat.com/api/v2
Machine-readable spec#
This is the one place these locations are documented; other pages link here.
- OpenAPI spec:
GET /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. Entities, fields and relationships. See OpenAPI and schema. - MCP server:
https://www.trackagoat.com/api/mcp, for Claude and other MCP clients. See MCP server. - Changelog:
GET /api/v2/changelog. Every changelog entry as JSON, newest first. No API key needed. See Changelog API. - These docs as Markdown:
/llms.txt, or append.mdto any docs URL. See llms.txt and raw docs.
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-levelhandle(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 for the full concept.
Authentication#
See Authentication for how to generate and use API keys.
Response envelope#
Every endpoint returns JSON with this shape:
{
"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:
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:
{
"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.
GET /api/v2/analytics?entity=creator&entity_id=<uuid>&metric=views&from=2026-01-01&to=2026-03-31API 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_bodyor a404on 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_busyon 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.
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:
{
"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: 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.
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 |
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.
Changelog#
| Method | Path | Scope | Description |
|---|---|---|---|
GET | /api/v2/changelog | none (public) | trackagoat's changelog, newest first; filter by since and q |