Authentication and API keys
Create an API key, choose its scopes and authenticate with a Bearer token. Covers revocation, limits and testing safely.
Every v2 API request needs an API key. Create one in the app, send it as a Bearer token, and give it only the scopes it needs. Every plan includes API access. Free and Starter allow 1 key each, Ultra allows 5. Free allows 200 requests a day, Starter 1,000 and Ultra 50,000.
Keys are:
- Org-scoped: a key can only reach data in the org it was created in.
- Shown once: the plaintext key is displayed at creation and can't be recovered.
- Hashed at rest: trackagoat stores only a SHA-256 hash of the key, never the plaintext.
- Acting as one member: a key acts on behalf of the person who created it, or of the member an org admin picked under Acts as. Every call is attributed to that member and can never do more than they can in the app. If they leave or are removed from the org, the key stops working. If they stop being an org admin, the key loses the
adminscope and admin-only actions.
Creating an API key#
Open org settings
Go to Org settings → API keys (org admins only).
Click + New API key
Give the key a descriptive name, such as
Claude MCP accessorAnalytics script, choose who it acts as (you, by default, or any member of the org) and choose its scopes.Copy your key immediately
After you click Create, the full key (
tga_<64 hex chars>) is shown once. Copy it now.
Using the key#
Include the key as a Bearer token on every request:
Authorization: Bearer tga_<your-key>Example:
curl -H "Authorization: Bearer tga_abc123" \
https://www.trackagoat.com/api/v2/projectsThe one endpoint that needs no key is GET /api/v2/changelog: the changelog is public.
Key format#
tga_<64 lowercase hex characters>Example: tga_a1b2c3d4e5f6... (64 hex chars after the prefix).
Org scoping#
Keys are org-scoped: all data returned is limited to the organization the key belongs to. A key can only read and write data inside its own org.
Scoping stops at the org boundary; it does not go down to the project level. A key grants access to every project in its org, including ones created after the key was issued. There is no way to issue a key that is limited to a single project.
Testing against the API#
Because keys are org-wide, do not run integration tests with a key from an org that holds real data: a test POST or DELETE will hit production records.
Create a separate organization for testing and use a key from that org. It gives you complete isolation: separate creators, campaigns, conversions, and analytics, with no path back to your live org. Ask support to disable scraping on it, which also guarantees test conversions can never generate payout accruals.
This is how you get a sandbox on trackagoat: there is no separate sandbox host or test-mode key prefix. The base URL and key format are the same; the org is what separates test from live.
Permission scopes#
Each key carries one or more permission scopes, chosen at creation time. The scope controls which HTTP methods the key may use:
| Scope | Grants |
|---|---|
read | All GET endpoints |
write | All POST, PATCH, and DELETE endpoints (in addition to reads if read is also granted) |
admin | Org administration: projects, members, invitations, API keys and creating organizations; also entrance-PIN reads and hard deletes. Platform-admin endpoints under /api/v2/admin/* additionally need the owner to be a platform admin |
New keys default to ['read', 'write'] unless you narrow the scopes at creation.
Who a key acts as#
A key acts on behalf of one member of the org. By default that is the org admin who created it. An admin can instead pick another member under Acts as, for example for a script that a teammate runs. Every request is attributed to that member: change logs, notes signatures, the audit log and GET /api/v2/me all show them. The keys list shows each key as "Acts as name · created by admin".
The key can never do more than that member can do in the app. Its scopes are a ceiling rather than a grant, and every request is checked against the member's current role in the org:
- Member is an org admin: the key gets all of its scopes.
- Member is not an org admin (for example, demoted after the key was created):
adminis dropped, and everything only org admins can do or see in the app returns403 insufficient_role: payments and payout setup, a creator's payout account, removing or re-enabling creators, removing accounts or videos, stopping video tracking, manual scrapes, share pages, comment settings, and organization and project documents. Everything else thatreadandwriteallow still works. The OpenAPI spec marks each of these endpoints "Requires an org admin". - Member left or was removed from the org: the key is rejected with
401 key_member_removed. Removing a member also deactivates the keys that act as them. - The key was made for someone else, and the admin who created it lost access: the admin has seen the key, so it only works while they are still an org admin of this org. If they leave or are removed, the key is rejected with
401 key_creator_removed; if they are changed to member,401 key_creator_not_admin; if their account is suspended,401 key_creator_banned. Removing, demoting or suspending that person also deactivates those keys. Keys a person created for themselves keep working after they are changed to member, limited to what a member can do.
Deactivated keys stay in Org settings → API keys with the reason: revoked, the member it acts as left or was suspended, the admin who created it left, was changed to member or was suspended, or the organization was suspended. To keep a script running after its key's creator loses access, an org admin creates a new key for it.
Creating keys over the API#
POST /api/v2/organizations/{orgId}/api-keys needs the admin scope, and a key can only create keys whose scopes it holds itself. Asking for a scope the calling key lacks returns 403 insufficient_scope with meta.required listing the missing scopes. Pass acts_as_user_id to create a key that acts as another member; it must be a current member of the org (400 acts_as_not_member otherwise), and the admin scope needs that member to be an org admin. The response includes acts_as and created_by.
A write request made with a read-only key is rejected with 403 and meta.code = "insufficient_scope":
{
"data": null,
"error": "This action requires the 'write' scope. Granted: [read]",
"meta": { "code": "insufficient_scope", "required": "write", "granted": ["read"] }
}This applies to every mutating endpoint, including all payout writes (payout-methods, payout-structures, payout-payments, payout-accruals, their [id] sub-routes, and annotation writes).
Errors#
| Status | meta.code | Cause |
|---|---|---|
401 | invalid_api_key | Missing, malformed, invalid, revoked or expired key |
401 | key_member_removed | The member the key acts as is no longer in the org |
401 | key_creator_removed | The key was made for someone else, and the admin who created it is no longer in the org |
401 | key_creator_not_admin | The key was made for someone else, and the admin who created it is no longer an org admin |
401 | key_creator_banned | The key was made for someone else, and the account that created it is suspended |
403 | insufficient_scope | Key is valid but lacks the scope required for this endpoint (or admin was dropped because its member is no longer an org admin) |
403 | insufficient_role | Only org admins can do this in the app, and the key acts as a member who isn't one |
403 | None | Key is valid but the org or user is banned |
429 | rate_limit_exceeded | Per-key sliding-window (60 req/min) or daily quota exceeded |
{
"data": null,
"error": "Invalid or expired API key",
"meta": { "code": "invalid_api_key" }
}Revoking a key#
Go to Org settings → API keys and revoke the key. Revocation is immediate: requests with that key get 401 invalid_api_key. The key stays in the list, marked Revoked.
Removing a member from the org (or a member leaving) deactivates every key that acts as them and every key they created in that org. Changing an admin to member deactivates the keys they created for someone else. For integrations, have an admin who will stay in the org create the key, acting as a member who will stay too.
Limits#
- Number of keys: your plan sets
max_api_keys_per_org. Delete unused keys if you reach it. - Rate limit: 60 requests a minute per key (sliding window).
- Daily quota:
max_api_requests_per_dayper org, set by your plan.
See Plans and limits for current values and Errors and limits for the 402 and 429 responses.