Accounts
Platform accounts owned by a creator. List, add, update, deactivate, remove, scrape, and read follower history.
An account is a single platform presence: a TikTok or Instagram handle: owned by a creator. Tracking configuration (the handle, tracking_mode, and the tracked date window) lives on the account, and videos hang off accounts. Plan limits count accounts, since accounts are what actually get scraped. Deactivated accounts don't count.
Account fields#
| Field | Type | Description |
|---|---|---|
id | uuid | Account ID |
creator_id | uuid | Creator that owns this account |
project_id | uuid | Project this account belongs to |
org_id | uuid | Owning organization ID |
platform | tiktok | instagram | youtube | Which platform this account is on |
handle | string | Platform @username |
platform_user_id | string | null | The platform's internal user ID |
display_name | string | null | Display name from the platform |
avatar_url | string | null | Profile image URL |
bio_link | string | null | Link in the account's bio |
follower_count | number | Current follower count (latest snapshot) |
following_count | number | Current following count |
total_likes_count | number | Cumulative total likes |
video_count | number | Current total video count |
tracking_mode | auto | selective | hashtag | auto: track all videos. selective: new videos land in the inbox. hashtag: track videos whose caption contains a tracked hashtag. |
tracking_hashtags | string[] | Hashtag-mode only. Normalized server-side and by a database trigger: NFC + lowercase, leading # stripped, and characters that can't appear in a hashtag removed (#Black-Friday becomes blackfriday). Whitespace and commas separate tags. Max 50 tags, 100 chars each. |
hashtag_inbox_non_matching | boolean | Hashtag-mode only. true (default) sends non-matching videos to the inbox; false excludes them. |
tracking_start_date | YYYY-MM-DD | null | Start of the tracked window |
tracking_end_date | YYYY-MM-DD | null | Last day of the tracked window, inclusive (null = no end). The window spans each date in both UTC and the org's analytics timezone, whichever is wider. |
is_active | boolean | false once the account has been removed. A deactivated account is still true |
deactivation | object | null | null while the account is active. See Deactivation |
last_scraped_at | ISO 8601 | null | When the account was last scraped |
tags | array | The account's tags, [{ id, name, color }] sorted by name. Returned by GET /api/v2/accounts and GET /api/v2/accounts/{id}. Change them with /api/v2/accounts/{id}/tags |
created_at | ISO 8601 | When the account was added |
updated_at | ISO 8601 | Last update |
Deactivation#
deactivation is null while an account is active. Once an org admin deactivates the account, or its creator, it is:
| Field | Type | Description |
|---|---|---|
deactivated_at | ISO 8601 | When the account was deactivated |
deactivated_by | uuid | null | User who deactivated it |
video_choice | keep_tracking | freeze | stop_tracking | What happened to its videos |
reason | string | null | The reason given, if any |
via_creator | boolean | true when it was deactivated because its creator was. It comes back when the creator is reactivated |
video_counts | { frozen, stopped } | Single GET only. How many of its videos are frozen or stopped. When either is above 0, reactivating needs existing_videos |
The raw columns (deactivated_at, deactivated_by, deactivated_via_cascade, deactivation_video_choice, deactivation_reason) are also returned. Prefer deactivation.
GET/api/v2/accounts#
List accounts across your organization.
curl -H "Authorization: Bearer tga_<key>" \
"https://www.trackagoat.com/api/v2/accounts?project_id=<uuid>&platform=instagram"Query parameters#
| Parameter | Type | Default | Description |
|---|---|---|---|
project_id | uuid | None | Filter to a specific project |
creator_id | uuid | None | Filter to a specific creator |
platform | tiktok | instagram | youtube | None | Filter to one platform |
search | string | None | Partial match on handle |
status | active | deactivated | all | active | active hides deactivated accounts (including those of a deactivated creator), deactivated lists only them, all lists both |
tags | string | None | Comma-separated tag names (any casing) or ids, up to 20, as in ?tags=backup. See Filtering lists by tag |
tags_match | any | all | any | any: accounts with at least one of the tags. all: accounts with every one |
limit | number | 50 | Items per page (max 100) |
cursor | string | None | Pagination cursor |
Returns a paginated array of account objects.
GET/api/v2/creators//accounts#
List all accounts belonging to a single creator (ordered oldest first).
curl -H "Authorization: Bearer tga_<key>" \
https://www.trackagoat.com/api/v2/creators/<uuid>/accountsReturns an array of account objects. 404 if the creator doesn't exist or isn't in your org.
POST/api/v2/creators//accounts#
Add a platform account to an existing creator and dispatch a scrape. Requires the write scope. Enforces the per-org account limit.
If the creator is deactivated, the new account is deactivated with them, with the same choices (deactivation.via_creator: true), and comes back when the creator is reactivated. If you add the handle of an account that was removed while it was deactivated, that is a fresh add: the account comes back active (deactivation: null), its frozen or stopped videos are tracked again (views they gained in the meantime are still not paid), and any payout pause it started ends.
curl -X POST \
-H "Authorization: Bearer tga_<key>" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{"platform": "instagram", "handle": "charli"}' \
https://www.trackagoat.com/api/v2/creators/<uuid>/accountsBody#
| Field | Type | Default | Description |
|---|---|---|---|
platform | tiktok | instagram | youtube | required | Which platform this account is on. |
handle | string | required | Platform @username, or a profile URL on platform (max 200 chars). Normalized: leading @ stripped, lowercased. See accepted profile links. |
tracking_mode | auto | selective | hashtag | auto | Video discovery mode. |
tracking_hashtags | string[] | [] | Required (non-empty) when tracking_mode is hashtag. Normalized server-side and by a database trigger: NFC + lowercase, leading # stripped, and characters that can't appear in a hashtag removed (#Black-Friday becomes blackfriday). Whitespace and commas separate tags. Max 50 tags, 100 chars each. |
hashtag_inbox_non_matching | boolean | true | Hashtag mode: route non-matching videos to the inbox (true) or exclude them (false). |
tracking_start_date | YYYY-MM-DD | today (org timezone) | First day of the tracked window. Defaults to today in the org's analytics timezone. |
tracking_end_date | YYYY-MM-DD | None | Optional last day, inclusive (must be ≥ start date; equal to the start date tracks a single day). |
Responses#
| HTTP | Cause |
|---|---|
| 201 | Account added; body is the full account object. |
| 400 | invalid_account: the handle or URL can't become an account. meta.reason is invalid_handle, video_url, no_handle_in_url, unrecognized_url, platform_mismatch, short_url_unresolved or too_many_short_links. |
| 402 | max_accounts_per_org limit reached. |
| 403 | The handle is banned on this platform (creator_banned). |
| 404 | Creator not found (or not in your org). |
| 409 | already_tracked: the handle is already tracked in this project. creator_inactive: the creator has been removed. |
GET/api/v2/accounts/#
Get a single account.
curl -H "Authorization: Bearer tga_<key>" \
https://www.trackagoat.com/api/v2/accounts/<uuid>Returns an account object. While the account is deactivated, deactivation also carries video_counts. 404 if not found.
PATCH/api/v2/accounts/#
Rename the handle or change tracking configuration. At least one field is required. Requires the write scope. Changing the handle dispatches a re-scrape of the account's profile and videos.
curl -X PATCH \
-H "Authorization: Bearer tga_<key>" \
-H "Content-Type: application/json" \
-d '{"handle": "charlidamelio", "tracking_mode": "selective"}' \
https://www.trackagoat.com/api/v2/accounts/<uuid>Body#
| Field | Type | Description |
|---|---|---|
handle | string | Rename the account handle (or pass a profile URL). Normalized like account creation. Triggers a re-scrape. 409 handle_taken if another account in the project, including a removed one, already has that handle; 404 if the account was removed. |
tracking_mode | auto | selective | hashtag | Switch between auto-tracking, inbox review, and hashtag matching. |
tracking_hashtags | string[] | Replace the tracked hashtag list. Must be non-empty if the resulting mode is hashtag. |
hashtag_inbox_non_matching | boolean | Route non-matching videos to the inbox or exclude them. |
tracking_start_date | YYYY-MM-DD | null | Start of the tracked window. null clears it. |
tracking_end_date | YYYY-MM-DD | null | Last day of the tracked window, inclusive. null = no end. |
Returns the updated account object. 404 if not found.
DELETE/api/v2/accounts/#
Soft-delete an account (its history and videos are preserved). This removes the account; it can't be undone through the API, but you can add the handle again. To pause it instead, deactivate it. Requires the write scope.
curl -X DELETE \
-H "Authorization: Bearer tga_<key>" \
https://www.trackagoat.com/api/v2/accounts/<uuid>Returns { "deleted": true }.
POST/api/v2/accounts//scrape#
Trigger a manual scrape for a single account. Consumes from the org's daily manual-scrape quota. Requires the write scope.
curl -X POST \
-H "Authorization: Bearer tga_<key>" \
-H "Content-Type: application/json" \
-d '{"job_type": "video_stats"}' \
https://www.trackagoat.com/api/v2/accounts/<uuid>/scrape| Body field | Values | Description |
|---|---|---|
job_type | creator_profiles | video_stats | discover_videos | Which scrape job to dispatch (optional). |
The response echoes { job_type, account_id, job_id }.
| HTTP | Cause |
|---|---|
| 200 | Scrape dispatched. |
| 400 | Account is disabled. |
| 429 | Daily scrape limit exceeded. |
POST/api/v2/accounts//deactivate#
Deactivate one account, for example a creator's Instagram while you keep tracking their TikTok. trackagoat stops looking for its new posts and updating its profile, and hides it from lists unless you ask for status=deactivated. The creator and their other accounts are not changed. The account keeps its campaign membership and you can reactivate it. While deactivated, it doesn't count toward max_accounts_per_org. To deactivate a whole creator, use POST /api/v2/creators/{id}/deactivate.
Requires the write scope, and the member the key acts as must be an org admin (403 insufficient_role otherwise). Accepts an Idempotency-Key header.
curl -X POST \
-H "Authorization: Bearer tga_<key>" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{"videos": "stop_tracking", "reason": "Personal account"}' \
https://www.trackagoat.com/api/v2/accounts/<uuid>/deactivateBody#
| Field | Type | Description |
|---|---|---|
videos | keep_tracking | freeze | stop_tracking | Required. What happens to the account's videos already tracked. Same meaning as for creators. |
payouts | pause | keep | Required only when this is the creator's last active account and the creator has payout structures assigned (400 payouts_required otherwise). Ignored in every other case: while the creator has another active account, their payouts carry on. Same meaning as for creators. |
reason | string | Optional, up to 1,000 characters. Shown in the creator's History. |
Response#
{
"data": {
"account": {
"id": "uuid",
"platform": "instagram",
"handle": "someuser",
"deactivation": {
"deactivated_at": "2026-10-12T09:30:00Z",
"deactivated_by": "uuid",
"video_choice": "stop_tracking",
"reason": "Personal account",
"via_creator": false
}
},
"result": { "account_id": "uuid", "creator_id": "uuid", "videos_frozen": 0, "videos_stopped": 14, "payouts": null }
},
"error": null,
"meta": null
}account is the full account object after the change (shortened here). result.creator_id is null for an account without a creator. result.payouts is pause or keep when the payout question applied, otherwise null.
| HTTP | Cause |
|---|---|
| 200 | Deactivated. |
| 400 | invalid_body. payouts_required: this is the creator's last active account, the creator has payout structures assigned, and payouts was left out; meta.assignments is how many. Nothing changed. |
| 403 | Key lacks the write scope (insufficient_scope), or acts as a member who isn't an org admin (insufficient_role). |
| 404 | not_found: the account doesn't exist, it or its creator was removed, or it isn't in your org. |
| 409 | already_deactivated, including when its creator is deactivated. |
POST/api/v2/accounts//reactivate#
Reactivate a deactivated account. New posts follow its tracking mode again, and a full check for posts made while it was deactivated runs with the next discovery cycle (usually within 12 hours). An account whose creator is deactivated can't be reactivated on its own: reactivate the creator with POST /api/v2/creators/{id}/reactivate. If the creator's payouts were paused, reactivating any one of their accounts starts them again from the next period.
The account counts toward max_accounts_per_org again, so reactivating needs room under the limit. If it doesn't fit, the call fails with 402 limit_reached and nothing changes.
Requires the write scope, and the member the key acts as must be an org admin. Accepts an Idempotency-Key header.
curl -X POST \
-H "Authorization: Bearer tga_<key>" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{"missed_posts": "ignore", "existing_videos": "keep"}' \
https://www.trackagoat.com/api/v2/accounts/<uuid>/reactivateBody#
| Field | Type | Description |
|---|---|---|
missed_posts | inbox | track | ignore | Required. What happens to posts made while deactivated. Same meaning as for creators. |
existing_videos | resume | keep | stop | Required when the account has frozen or stopped videos (deactivation.video_counts on GET /api/v2/accounts/{id}), ignored otherwise. |
note | string | Optional, up to 1,000 characters. Shown in the creator's History. |
Response#
{
"data": {
"account": { "id": "uuid", "deactivation": null },
"result": {
"account_id": "uuid",
"creator_id": "uuid",
"videos_resumed": 0,
"videos_stopped": 0,
"missed_posts_updated": 2
}
},
"error": null,
"meta": null
}| HTTP | Cause |
|---|---|
| 200 | Reactivated. |
| 400 | invalid_body. existing_videos_required: the account has frozen or stopped videos and existing_videos was left out; meta.frozen and meta.stopped say how many. Nothing changed. |
| 402 | limit_reached: you're at your plan's account limit. meta.limitKey is max_accounts_per_org, with meta.current (active accounts now, deactivated ones not counted) and meta.max. Nothing changed. |
| 403 | Key lacks the write scope, or acts as a member who isn't an org admin (insufficient_role). |
| 404 | not_found. |
| 409 | not_deactivated: the account is active. creator_deactivated: its creator is deactivated; reactivate the creator instead. |
POST/api/v2/projects//accounts/bulk-deactivate#
Deactivate up to 100 accounts in one project, each exactly like POST /api/v2/accounts/{id}/deactivate, with one videos choice for all of them. Requires the write scope, and the member the key acts as must be an org admin. Accepts an Idempotency-Key header.
curl -X POST \
-H "Authorization: Bearer tga_<key>" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{"account_ids": ["<uuid1>", "<uuid2>"], "videos": "keep_tracking"}' \
"https://www.trackagoat.com/api/v2/projects/<projectId>/accounts/bulk-deactivate"Body: account_ids (1 to 100 UUIDs), videos, payouts and an optional reason. payouts is needed when the batch includes the last active account of a creator with payout structures assigned.
{
"data": {
"done": [{ "account_id": "uuid", "creator_id": "uuid", "videos_frozen": 0, "videos_stopped": 0 }],
"skipped": [{ "id": "uuid", "reason": "not_found" }],
"done_count": 1,
"skipped_count": 1
},
"error": null,
"meta": null
}Skipped reasons: not_found (unknown, removed, its creator removed, or in another project), already_deactivated, or payouts_required (with assignments: the batch would leave a creator with payout structures assigned and no active account, and payouts was left out; every account of that creator in the batch is skipped). The rest go ahead. 404 if the project isn't in your org.
POST/api/v2/projects//accounts/bulk-reactivate#
Reactivate up to 100 accounts in one project, each exactly like POST /api/v2/accounts/{id}/reactivate, with one set of choices for all of them. Requires the write scope, and the member the key acts as must be an org admin. Accepts an Idempotency-Key header.
curl -X POST \
-H "Authorization: Bearer tga_<key>" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{"account_ids": ["<uuid1>", "<uuid2>"], "missed_posts": "inbox"}' \
"https://www.trackagoat.com/api/v2/projects/<projectId>/accounts/bulk-reactivate"Body: account_ids (1 to 100 UUIDs), missed_posts, existing_videos and an optional note. The response has the same done, skipped, done_count and skipped_count shape, and each done item is a reactivation result. Each account that can't be reactivated is returned in skipped with a reason, and the rest go ahead:
reason | Why |
|---|---|
not_found | Unknown, removed, its creator removed, or in another project |
not_deactivated | The account is active |
creator_deactivated | Its creator is deactivated. Reactivate the creator instead |
existing_videos_required | The account has frozen or stopped videos and existing_videos was left out. Includes frozen and stopped counts |
limit_reached | You're at your plan's account limit. Includes current and max. Accounts are reactivated in order until the limit is reached |
GET/api/v2/accounts//stats#
Get an account's follower/stat snapshot history. This series is append-only: snapshots are only ever inserted, never updated.
curl -H "Authorization: Bearer tga_<key>" \
"https://www.trackagoat.com/api/v2/accounts/<uuid>/stats?from=2026-01-01&to=2026-03-31"Query parameters#
| Parameter | Type | Default | Description |
|---|---|---|---|
from | YYYY-MM-DD | None | Start of the range (inclusive) |
to | YYYY-MM-DD | None | End of the range (inclusive) |
limit | number | 365 | Max snapshots to return (max 1000) |
Response fields#
Each element of the returned array:
| Field | Type | Description |
|---|---|---|
account_id | uuid | Account this snapshot belongs to |
snapshot_at | ISO 8601 | When the snapshot was taken |
follower_count | number | null | Followers at snapshot time |
following_count | number | null | Following count at snapshot time |
total_likes_count | number | null | Cumulative likes at snapshot time |
video_count | number | null | Total video count at snapshot time |
is_baseline | boolean | Whether this is the initial baseline snapshot |