Skip to content

Authentication & Tokens

Every request carries a personal access token that belongs to exactly one property. There is no account-wide token and no property id in the URL: the token is the property.

Terminal window
curl https://api.snipform.io/v2/property/signals/analytics/metrics \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{"period":"last_7"}'
  1. Open the property in the dashboard and go to API (https://app.snipform.io/property/{property}/api).

  2. Click New token and fill in:

    FieldOptions
    NameAnything that tells you later what uses it (warehouse-sync, looker)
    TypeAPI for a script or integration. MCP for an AI assistant (see below)
    Expires in7 days, 30 days, 90 days, 1 year, or never
    ScopesAPI tokens only. Pick exactly what the integration needs
  3. Copy the token from the confirmation. It is shown once and never again. Store it like a password.

The token is bound to the property you created it on. It cannot reach sibling properties on the same account, and the property cannot be changed after creation; make a new token instead.

Pick the smallest set that does the job. A token without a required scope gets a 403 with the scope named:

{
"code": 403,
"status": "Forbidden",
"data": { "message": "Missing scope: signals:write", "error_code": "forbidden" }
}
ScopeDescription shown in the dashboard
signals:readRead analytics, sessions, channels
signals:writeRecord events and acquisition data on sessions
conversions:readRead conversion definitions, funnels, segments
conversions:writeCreate and update conversions
forms:readRead forms and submissions (reserved, no endpoint uses it yet)
shortlinks:readRead short link groups, links, and clicks
shortlinks:writeCreate and update short links
contacts:readRead identified contacts and their sessions
contacts:writeIdentify, update, and delete contacts

Scopes are fixed at creation. To change them, create a new token and revoke the old one.

  • An expired token is refused with 401. Nothing warns you ahead of time, so put the expiry in your own calendar or pick never for long-lived server integrations and rotate on your own schedule.
  • Revoke on the API page takes effect immediately. Revoked tokens are gone from the list and every request with one returns 401.
  • The list shows the tokens that are still live for the property, newest first.
HTTPMessageCause
401Unauthenticated.Header missing, token malformed, expired or revoked
403Token is not scoped to a property.The token was not issued through the property API page
403Missing scope: ...The route needs a scope the token does not carry
404Token property no longer exists.The property was deleted after the token was issued

The dashboard issues two kinds of token from the same screen. The type is derived from the scopes, not stored separately.

API tokenMCP token
ScopesThe read/write scopes you chooseExactly one: mcp:use, set automatically
CallsThe REST endpoints in this sectionOnly the MCP server at /mcp/{property}
AccessWhatever the scopes grant, including writesRead-only analytics, by contract
Rate limitNone published60 requests per minute

The two never cross over. An API token on the MCP endpoint is refused because it lacks mcp:use. An MCP token on a REST endpoint is refused because it lacks every REST scope; the one exception is GET /v2/property/overview, which checks no scope and answers any valid token.

  • One token per integration. When something leaks you revoke one thing, not everything.
  • Never ship a token in browser code. Browser-side work goes through the tracker and forms libraries, which are unauthenticated by design.
  • Treat the token like a database password: environment variables or a secrets manager, never source control.
  • Reads and writes should usually be separate tokens. A reporting job does not need contacts:write.