Roles
Connections carry credentials to external systems, which is why creating or changing one is reserved to admins. Reading what a connection holds, from a sync or a transform, is a viewer right.
Scopes
Every operation of the API is gated on a scope, written<resource>:<action>: datasets:read, datasets:write, transforms:run, connections:read, members:manage, and so on. A role is a fixed set of scopes. You meet them in two places: in the 403 answered when a role lacks one, and when you narrow an API key.
API keys
An API key is created in a project and acts as the user who created it. Two things bound what it can do:- it never reaches outside its project, whatever its creator’s role elsewhere;
- it may carry a list of
scopes, a ceiling that only narrows: a key with["datasets:read", "sql:read"]is read-only, and a key can never do more than its creator’s role allows. Demote the creator and their keys lose what they lost.
401 from then on.
An OAuth2 session (an interactive login, or a client-credentials client) carries no ceiling: it does exactly what the user’s roles allow.
Inside a build
Code run by the platform acts as the credential that triggered the build, narrowed to what a build may need: it cannot manage members, keys, connections or the organization, whatever the trigger’s role. Just before running, the platform checks again that this identity may still read every input and run the transform, so a right withdrawn after a schedule was set stops the schedule’s builds rather than let them read on.Plans
An organization is on a plan that may withhold a feature or cap a resource count. A request refused for that reason alone answers402 rather than 403, so a client can tell “not allowed” from “not included”. The same status, with insufficient_quota, is answered by the inference models when the organization’s monthly budget is spent.