Skip to main content

Base URL and authentication

Every endpoint takes Authorization: Bearer <YOUR_API_KEY>. Create a key under Settings → API keys (details). Reads need stats:read; changes need config:write, and creating and deleting need more than that. Each section below says which. A site your key does not cover returns 404, not 403, so a key cannot be used to discover which sites exist.

How sites are identified

A site has two identifiers, and which one you see depends on the credential you used. On this page, and on events, sources, sessions, revenue, goals and funnels, an API key only ever sees the snippet key: ttid_ followed by 22 characters, the value your install snippet carries as data-site. It is what id holds in every response below, and it is what you pass back in any later call to those endpoints.
A few endpoints take the site’s internal UUID instead of the snippet key: the data deletion and access endpoints, plus POST /v1/ingest/conversions and POST /v1/consortium/fingerprints. No API endpoint returns that UUID, so read it from the dashboard URL once and keep it. See which site identifier those endpoints take.
The dashboard uses these same endpoints with its own session and sees an internal UUID instead. If you are reading this page, you want the snippet key. snippet_key is also returned as its own field, and it always holds that same ttid_ value.

GET /v1/sites

List the properties on your account, newest first.
If your key is scoped to a single site, this returns that one site rather than the whole account.

Query parameters

Sites you have scheduled for deletion are excluded by default. Pass include_deleted=true to see them; each one carries a non-null deleted_at and deletion_effective_at.

Response fields

GET /v1/sites/{siteId}

Fetch one site. siteId is the snippet key.
Returns a single site object with the same fields as the list rows above (not wrapped in a sites array). A site inside its deletion window returns 404 here. Use GET /v1/sites?include_deleted=true if you need to see it. Note that a site in its deletion window keeps collecting nothing new but keeps its data: ingestion is suspended when you schedule the deletion, while the read endpoints keep serving what is already there so you can export it during the 30 days. That is why this endpoint 404s a site the sources and events endpoints still answer for.

About region

region is the region you chose for the site, and we return it so you can read back what is on file. It does not yet control where data is stored: all event data currently lands in one region whichever value you pick. If you have GDPR obligations that require EU storage, read Data residency before relying on this field.

POST /v1/sites

Create a property. The response includes an API key for it, shown once.
api_key is the plaintext key for the new site, shown once and never recoverable. It carries stats:read and ingest:write, which is what the install instructions point the server SDKs at.
cookie_apex_domain comes back null here, because nothing is applied automatically. suggested_cookie_apex_domain carries what domain derives to; render it as a pre-filled, unconfirmed suggestion, and PATCH /v1/sites/{siteId} with it to actually scope the snippet’s identity cookies across subdomains as data-cookie-domain. Broadening cookies to an apex is a real security tradeoff, not a free upgrade: two sites that happen to resolve to the same registrable domain (including two different accounts, on a platform domain not on the Public Suffix List) can otherwise collide on one visitor identity, which is why this is confirm-not-derive. suggested_cookie_apex_domain is null when the domain has no registrable apex (localhost, an IP address). See Subdomains and cross-domain. This endpoint needs three permissions: credentials:write, stats:read and ingest:write. It hands you a credential carrying the last two, and a key can never mint a key more capable than itself. If yours is missing one, you get 403 and required_scope names it. See minting credentials with a key. It also requires that the person who created your key is still an account-wide admin, and it refuses a key scoped to a single site. See who is behind a key. A domain another account tracks is not a conflict. Two accounts pointing at the same hostname collect entirely separate data.

PATCH /v1/sites/{siteId}

Change a site’s settings. Send only the fields you are changing. Needs config:write.
Returns the full updated site, in the same shape as GET /v1/sites/{siteId}. At least one field is required. Setting currency explicitly also stops a later Stripe or Shopify connection from overriding it, including when you set it to USD. Unlike creating and deleting, this is not admin-only. Any member can change settings. A site inside its deletion window returns 404. Restore it first.

DELETE /v1/sites/{siteId}

Schedule a site for deletion, 30 days out. Needs config:write and an account-wide admin behind the key.
Nothing is destroyed yet. For 30 days the site, its data and its snippet key all survive, and POST /v1/sites/{siteId}/restore cancels the whole thing. After effective_at the erasure runs and is not reversible. What happens straight away:
  • Collection stops. The snippet is still on your pages, but we no longer accept its events.
  • The site disappears from GET /v1/sites unless you pass include_deleted=true.
  • It stops counting against your plan’s site cap.
confirm_domain must match the site’s own domain, case-insensitively. It is the domain rather than a fixed phrase because on a multi-site account the mistake that actually happens is deleting the wrong property, and a constant phrase cannot catch that. Re-issuing on a site that is already scheduled reports the existing effective_at and does not push the deadline out.

POST /v1/sites/{siteId}/restore

Cancel a scheduled deletion and resume collection. Needs config:write and an account-wide admin.
Calling this on a site that is not scheduled is a 200 no-op.

Next