PilotFoxDocs

Permissions and scopes

The permissions an API key can hold, the ones only API keys can have, and which endpoints need which.

PilotFox has one permission vocabulary for people, API keys, share links and MCP tokens. A permission is written resource:action, such as analytics:read. In API requests and responses, a set of permissions is an object of resource → actions:

{ "analytics": ["read"], "goals": ["read", "write"], "ingest": ["write"] }

Every endpoint under /api/v1 requires one permission, listed at the end of this page, except a few public, account and instance-administration endpoints. PilotFox checks it against what the caller holds on the site or organization of the request.

Roles and permissions

People get permissions from their role in the organization. Each role holds everything the role before it holds, and more. An API key holds exactly the permissions it was created with: any of those its creator's role holds, plus, for a key created by an owner or an admin, the key-only ones.

PermissionWhat it allowsViewerMemberEditorAdminOwner
site:readList the organization's sites, read a site's install snippet and proxy-secret status, verify an install.yesyesyesyesyes
analytics:readThe reports: overview, time series, breakdowns, pages, heatmap, event summaries, errors, geography, web vitals, retention, journeys, realtime counts, bots, annotations, the organization overview. Also a site's details and your own email report subscriptions.yesyesyesyesyes
sessions:readIndividual sessions and raw events: the session and event lists, a session's timeline, live visitors and their locations, the session map timeline, the sessions behind goals, funnels and journeys, error occurrences. Also needed to filter by some dimensions.yesyesyesyesyes
users:readIdentified users, their profiles, traits and sessions.yesyesyesyesyes
replay:readSession replays.yesyesyesyesyes
goals:read, funnels:read, segments:readThe saved goals, funnels and segments, and their reports.yesyesyesyesyes
annotations:readPrivate annotations, and who created each annotation (others see public ones only).yesyesyesyesyes
revenue:readRevenue reports, recorded payments, the status of payment provider connections.yesyesyesyesyes
affiliates:readAffiliates and their reports.yesyesyesyesyes
searchConsole:readGoogle Search Console reports of a linked site.yesyesyesyesyes
users:writeIdentify a visitor by hand, edit a user's traits.yesyesyesyes
goals:write, funnels:write, segments:write, annotations:writeCreate, change and delete goals, funnels, segments and annotations.yesyesyesyes
site:updateChange a site's settings, connect payment providers, Search Console and notifications, manage the proxy secret.yesyesyes
users:deleteErase a user and their data.yesyesyes
replay:deleteDelete a session replay.yesyesyes
imports:read, imports:writeSee and run data imports.yesyesyes
exports:readExport a site's raw events (also needs sessions:read).yesyesyes
shareLink:read, shareLink:writeList, create and revoke share links.yesyesyes
affiliates:writeCreate, change and delete affiliates, open and close their portal links.yesyesyes
site:create, site:deleteCreate and delete sites.yesyes
apiKey:create, apiKey:read, apiKey:deleteCreate, list and delete the organization's API keys.yesyes
organization:updateManage the organization's Google Search Console connections.yesyes
member:updateChoose which sites a restricted member sees.yesyes
team:updateChoose which sites a team sees.yesyes
organization:deleteDelete the organization (in the dashboard).yes

organization:delete and a few more permissions of the roles (member:create, member:delete, invitation:create, invitation:cancel, team:create, team:delete, ac:*), as well as apiKey:update, are used by no /api/v1 endpoint: the dashboard manages the organization, its members, invitations and teams through /api/auth, which takes a signed-in session only. On an API key they grant nothing.

Restricted members. A member whose access is limited to some sites sees only the sites granted to them (directly or through a team), with the role of that grant (viewer, member or editor; the highest when several reach a site); across the organization they count as a viewer. A member who sees every site holds, on each site, the higher of their role and any grant they have there. Owners and admins always see every site.

Key-only permissions

Two permissions belong to no role. Only API keys can hold them, and only owners and admins can grant them:

PermissionWhat it allows
ingest:writeSend events and identify users from your server: POST /api/v1/ingest/events and POST /api/v1/ingest/identify.
revenue:writeRecord payments from a billing system PilotFox does not connect to: POST /api/v1/sites/{siteId}/payments, and its refund and delete calls.

Their endpoints refuse every other credential with 401, whatever it holds: a signed-in owner, a share link or an MCP token cannot call them.

Give these permissions to dedicated keys: an ingest key needs nothing else, and a key that records payments needs nothing but revenue:write.

Site restrictions

A key created with a list of sites (siteIds) reaches only those sites:

EndpointWith a site outside the list
/api/v1/sites/{siteId}/…404 Site not found, as for a site that does not exist.
/api/v1/orgs/{orgId}/…403, except GET /orgs/{orgId}/sites and GET /orgs/{orgId}/overview, which list and sum up the key's own sites only.
POST /api/v1/ingest/eventsThe event is rejected with forbidden_site; the others in the batch are taken.
POST /api/v1/ingest/identify404 Site not found.

A key with a site list also gets 403 where an endpoint needs access to every site of the organization: saving, changing or deleting a segment or an annotation for the whole organization ("scope": "org"), and linking a Search Console property (see below).

Two kinds of caller read a site's data without belonging to its organization:

  • Share links. A share link's token (x-share-token header or ?share=) holds the scopes chosen when the link was made: analytics:read (the default), and optionally sessions:read, users:read and replay:read. Its creator must hold every scope on the site. A share link only reads, and only endpoints marked share links below accept it.
  • Public sites. A site whose settings make it public opens the endpoints marked public sites below to everyone for reading, with no credential needed: anyone gets analytics:read there, on top of what they already hold.

Neither can filter by the dimensions that need sessions:read unless a share link carries that scope.

Checks beyond the endpoint's permission

A few endpoints check more than the permission listed for them, and answer 403 when the check fails. Paths are relative to /api/v1:

  • Creating an API key (POST /orgs/{orgId}/api-keys) needs a signed-in person: API keys and MCP tokens are refused.
  • Starting a Search Console connection (POST /orgs/{orgId}/search-console/connect) needs a signed-in person: API keys and MCP tokens are refused.
  • Linking a Search Console property (PUT /sites/{siteId}/search-console), and listing the connections and properties to link from (GET /sites/{siteId}/search-console/connections and …/properties), need access to every site of the organization: a member who sees every site, or an API key without a site list.
  • Saving, changing or deleting a segment or an annotation for the whole organization ("scope": "org") needs access to every site of the organization, with segments:write or annotations:write in the member's own role (a site grant is not enough), or an API key without a site list. Through MCP, an annotation can be neither public nor for the whole organization.
  • Creating a share link (POST /sites/{siteId}/share-links) needs every scope of the link on the site; MCP tokens are refused.
  • Opening an affiliate's portal link (POST /sites/{siteId}/affiliates/{id}/share) also needs revenue:read; MCP tokens are refused.
  • Pointing a Slack or Discord notification at a URL, or switching it on (PUT /sites/{siteId}/notifications/slack or …/discord) also needs revenue:read, since the webhook then receives every sale. The webhook keeps receiving sales only while the member or API key that set its URL still has revenue:read on the site; see Slack and Discord webhooks.
  • Email report subscriptions (GET and PUT /sites/{siteId}/reports) belong to a person: a signed-in session or an MCP token acting for one; API keys are refused.
  • Exporting raw events (GET /sites/{siteId}/export) also needs sessions:read.
  • A payment's journey (GET /sites/{siteId}/payments/{paymentId}/journey) also needs sessions:read.
  • Making a site public (PATCH /sites/{siteId} with settings.public: true), or creating one public (POST /orgs/{orgId}/sites with settings.public: true), also needs analytics:read; a refused creation creates nothing.
  • Filtering by an identity dimension or another sessions-only dimension needs sessions:read (a 400); see Query parameters.
  • MCP OAuth tokens act as their user: everywhere they hold the user's current permissions, limited to the scopes the user approved, in one organization. See MCP with OAuth.

Some answers also leave fields out for a caller without a second permission:

  • Payments (GET /sites/{siteId}/payments): customer_email, session_id, visitor_id, user_id and credited_session_id are null without sessions:read.
  • Affiliates (GET /sites/{siteId}/affiliates/stats and …/{id}/report): payments, revenue, commission and conversion_rate are null, and a report's recent_payments empty, without revenue:read.
  • Annotations (GET /sites/{siteId}/annotations): without annotations:read, only the public annotations, with createdBy set to null.

Permission per endpoint

The tables below follow the sections of the API reference, and each endpoint links to its reference page. They are generated from the same OpenAPI document, which the API builds from each route's access rule, so they say exactly what the API enforces:

  • Permission is what the caller must hold on the site (/api/v1/sites/{siteId}/…) or in the organization (/api/v1/orgs/{orgId}/…). A signed-in session or an API key holding it is accepted, unless the notes say otherwise.
  • API keys limited to some sites are refused (403) on the organization endpoints, except where the notes say keys limited to some sites: their sites only.
  • Share links and public sites mean those callers are accepted too (see above). Checked by the endpoint marks a public endpoint that reads a credential itself.
  • Endpoints outside /api/v1 (the tracker's, the map tiles, MCP and the sign-in endpoints under /api/auth) need no permission; their notes say which credential they take. Each MCP tool needs the permission of the endpoint it calls.

Each GET under /api/v1 also answers HEAD with the same permission, except the export, the realtime stream and favicons.

System

EndpointPermissionNotes
GET /api/v1/config—public: no credential needed
GET /api/v1/health—public: no credential needed
GET /api/v1/ready—public: no credential needed

Account

EndpointPermissionNotes
GET /api/v1/me—signed-in session only
GET /api/v1/me/deletion—signed-in session only
GET /api/v1/me/reports—signed-in session only

Organizations

API keys

Sites

EndpointPermissionNotes
GET /api/v1/share—share link token, checked by the endpoint
GET /api/v1/sites/{siteId}/share-linksshareLink:read
POST /api/v1/sites/{siteId}/share-linksshareLink:write
DELETE /api/v1/sites/{siteId}/share-links/{id}shareLink:write

Analytics

EndpointPermissionNotes
GET /api/v1/sites/{siteId}/breakdownanalytics:readshare links, public sites
GET /api/v1/sites/{siteId}/favicons/{domain}analytics:readshare links, public sites
GET /api/v1/sites/{siteId}/heatmapanalytics:readshare links, public sites
GET /api/v1/sites/{siteId}/overviewanalytics:readshare links, public sites
GET /api/v1/sites/{siteId}/pagesanalytics:readshare links, public sites
GET /api/v1/sites/{siteId}/pages/trendsanalytics:readshare links, public sites
GET /api/v1/sites/{siteId}/timeseriesanalytics:readshare links, public sites
GET /api/v1/sites/{siteId}/vitalsanalytics:readshare links, public sites
GET /api/v1/sites/{siteId}/vitals/breakdownanalytics:readshare links, public sites
GET /api/v1/sites/{siteId}/vitals/timeseriesanalytics:readshare links, public sites

Events

EndpointPermissionNotes
GET /api/v1/sites/{siteId}/eventssessions:readshare links
GET /api/v1/sites/{siteId}/events/autocaptureanalytics:readshare links, public sites
GET /api/v1/sites/{siteId}/events/namesanalytics:readshare links, public sites
GET /api/v1/sites/{siteId}/events/propertiesanalytics:readshare links, public sites
GET /api/v1/sites/{siteId}/events/summaryanalytics:readshare links, public sites
GET /api/v1/sites/{siteId}/events/timeseriesanalytics:readshare links, public sites

Errors

EndpointPermissionNotes
GET /api/v1/sites/{siteId}/errorsanalytics:readshare links, public sites
GET /api/v1/sites/{siteId}/errors/summaryanalytics:readshare links, public sites
GET /api/v1/sites/{siteId}/errors/{fingerprint}analytics:readshare links, public sites
GET /api/v1/sites/{siteId}/errors/{fingerprint}/occurrencessessions:readshare links

Geography

EndpointPermissionNotes
GET /api/v1/sites/{siteId}/geo/citiesanalytics:readshare links, public sites
GET /api/v1/sites/{siteId}/geo/countriesanalytics:readshare links, public sites
GET /api/v1/sites/{siteId}/geo/pointsanalytics:readshare links, public sites
GET /api/v1/sites/{siteId}/geo/regionsanalytics:readshare links, public sites
GET /api/v1/sites/{siteId}/geo/timelinesessions:read
GET /maps/tiles/boundaries/{z}/{x}/{y}.mvt—public: no credential needed

Live

EndpointPermissionNotes
GET /api/v1/sites/{siteId}/geo/livesessions:read
GET /api/v1/sites/{siteId}/liveanalytics:readshare links, public sites
GET /api/v1/sites/{siteId}/live/streamanalytics:readshare links, public sites
GET /api/v1/sites/{siteId}/live/visitorssessions:read

Bots

People

Sessions

EndpointPermissionNotes
GET /api/v1/sites/{siteId}/sessionssessions:readshare links
GET /api/v1/sites/{siteId}/sessions/summarysessions:readshare links
GET /api/v1/sites/{siteId}/sessions/{sessionId}sessions:readshare links

Goals

Funnels

Journeys

EndpointPermissionNotes
GET /api/v1/sites/{siteId}/journeysanalytics:readshare links, public sites
GET /api/v1/sites/{siteId}/journeys/sessionssessions:readshare links
GET /api/v1/sites/{siteId}/retentionanalytics:readshare links, public sites

Segments

Annotations

EndpointPermissionNotes
GET /api/v1/sites/{siteId}/annotationsanalytics:readshare links, public sites
POST /api/v1/sites/{siteId}/annotationsannotations:write
PATCH /api/v1/sites/{siteId}/annotations/{id}annotations:write
DELETE /api/v1/sites/{siteId}/annotations/{id}annotations:write

Replays

Revenue

Payment providers

Affiliates

Search Console

Notifications

Imports

Exports

EndpointPermissionNotes
GET /api/v1/sites/{siteId}/exportexports:read

Ingest

EndpointPermissionNotes
POST /api/v1/ingest/eventsingest:writeAPI keys only
POST /api/v1/ingest/identifyingest:writeAPI keys only

Tracker

EndpointPermissionNotes
GET /api/c/{publicId}—public: no credential needed
POST /api/e—public: no credential needed
POST /api/i—public: no credential needed
GET /api/r.js—public: no credential needed
POST /api/rec/{publicId}—public: no credential needed
GET /api/s.js—public: no credential needed

MCP

EndpointPermissionNotes
GET /.well-known/{*}—public: no credential needed
GET /api/mcp—public: no credential needed
POST /api/mcp—API key or MCP OAuth token
DELETE /api/mcp—public: no credential needed

Auth

EndpointPermissionNotes
GET /api/auth/{*}—signed-in session or no credential
POST /api/auth/{*}—signed-in session or no credential
PATCH /api/auth/{*}—signed-in session or no credential
DELETE /api/auth/{*}—signed-in session or no credential

Admin

EndpointPermissionNotes
GET /api/v1/admin/backups—system administrators only (signed-in session)
DELETE /api/v1/admin/backups/copies/{name}—system administrators only (signed-in session)
GET /api/v1/admin/backups/remote—system administrators only (signed-in session)
POST /api/v1/admin/backups/restore—system administrators only (signed-in session)
GET /api/v1/admin/backups/runs—system administrators only (signed-in session)
POST /api/v1/admin/backups/runs—system administrators only (signed-in session)
PUT /api/v1/admin/backups/schedule—system administrators only (signed-in session)
GET /api/v1/admin/jobs—system administrators only (signed-in session)
GET /api/v1/admin/orgs—system administrators only (signed-in session)
GET /api/v1/admin/sites—system administrators only (signed-in session)
GET /api/v1/admin/stats—system administrators only (signed-in session)

On this page