Skip to content
LogoLogo

Authorization and scopes

The Picked API controls access with scopes. Every authenticated caller carries a set of scopes, and those scopes decide which operations the caller can do. A caller is either a user with a session or an API key. This guide covers the scopes, the roles, and how the API resolves a permission.

The format of a scope name

A scope has the form resource/action:

organization/read
organization_members/create
organization_projects/delete
  • resource — a lowercase name. It uses an underscore between words, as in organization_members and organization_api_keys.
  • action — one of create, read, update, or delete.

The GraphQL schema holds the scopes in the Scope enum. There they are uppercase with an underscore between words, as in ORGANIZATION_READ and ORGANIZATION_MEMBERS_CREATE. The two forms name the same scope.

Full scope list

These are the scopes:

Organization

ScopeGraphQL EnumDescription
organization/createORGANIZATION_CREATECreate an organization
organization/readORGANIZATION_READRead the detail of an organization
organization/updateORGANIZATION_UPDATEUpdate the name, the slug, and the settings of an organization
organization/deleteORGANIZATION_DELETEDelete an organization

Organization members

ScopeGraphQL EnumDescription
organization_members/createORGANIZATION_MEMBERS_CREATEAdd a member to an organization
organization_members/readORGANIZATION_MEMBERS_READRead the member list of an organization
organization_members/updateORGANIZATION_MEMBERS_UPDATEUpdate the role of a member
organization_members/deleteORGANIZATION_MEMBERS_DELETERemove a member from an organization

Organization invitations

ScopeGraphQL EnumDescription
organization_invitations/createORGANIZATION_INVITATIONS_CREATESend an invitation to join an organization
organization_invitations/readORGANIZATION_INVITATIONS_READRead the invitations that wait for an answer
organization_invitations/deleteORGANIZATION_INVITATIONS_DELETERevoke an invitation that waits for an answer

Organization projects

ScopeGraphQL EnumDescription
organization_projects/createORGANIZATION_PROJECTS_CREATECreate a project
organization_projects/readORGANIZATION_PROJECTS_READRead the detail of a project
organization_projects/updateORGANIZATION_PROJECTS_UPDATEUpdate the settings of a project
organization_projects/deleteORGANIZATION_PROJECTS_DELETEDelete a project

A scope on content inside a project also gives organization_projects/read. The workspace, integration, lead, action run, and report scopes all give it. They do not give organization_projects/create, organization_projects/update, or organization_projects/delete.

Organization API keys

ScopeGraphQL EnumDescription
organization_api_keys/createORGANIZATION_API_KEYS_CREATECreate an API key
organization_api_keys/readORGANIZATION_API_KEYS_READRead the API keys. This gives the prefix only, and not the full key.
organization_api_keys/deleteORGANIZATION_API_KEYS_DELETERevoke an API key

Organization integrations

ScopeGraphQL EnumDescription
organization_integrations/createORGANIZATION_INTEGRATIONS_CREATESet up an integration
organization_integrations/readORGANIZATION_INTEGRATIONS_READRead the options of an integration
organization_integrations/updateORGANIZATION_INTEGRATIONS_UPDATEChange the settings of an integration
organization_integrations/deleteORGANIZATION_INTEGRATIONS_DELETERemove an integration

Organization reports

ScopeGraphQL EnumDescription
organization_reports/createORGANIZATION_REPORTS_CREATECreate a report
organization_reports/readORGANIZATION_REPORTS_READRead a report
organization_reports/updateORGANIZATION_REPORTS_UPDATEUpdate the settings of a report
organization_reports/deleteORGANIZATION_REPORTS_DELETEDelete a report

Roles

Each member of an organization holds one of two roles:

Owner

An owner has full control inside the organization. These are the default scopes of an owner:

  • All organization/* scopes (read, update, delete)
  • All organization_members/* scopes
  • All organization_invitations/* scopes
  • organization_projects/read, organization_projects/update, organization_projects/delete
  • All organization_api_keys/* scopes
  • All organization_integrations/* scopes
  • organization_reports/read

Member

A member can reach most things, but cannot delete the organization and cannot control another member. These are the default scopes of a member:

  • organization/read, organization/update
  • organization_members/read
  • organization_invitations/read
  • organization_projects/read, organization_projects/update, organization_projects/delete
  • All organization_api_keys/* scopes
  • All organization_integrations/* scopes
  • organization_reports/read

These are the differences between an owner and a member:

CapabilityOwnerMember
Delete the organizationYesNo
Invite new membersYesNo
Remove membersYesNo
Update member rolesYesNo
Revoke invitationsYesNo
Control projects and integrationsYesYes
Control API keysYesYes
Read reportsYesYes

How scopes are resolved

When an authenticated request reaches the API, the API resolves the scopes like this:

  1. A user with a session — the API finds the role of that caller in the target organization. It then gives the caller the default scopes of that role.
  2. A request with an API key — the API uses the scopes that the key received when somebody created it. Those scopes are always scopes of the user who created the key.

Most queries and mutations point at one organization. For those, the caller must hold the scope inside that organization. For a root-level operation such as organizationCreate, the API resolves the scope at the account level.

When the caller does not hold the scope that an operation needs, the API returns an authorization error with the code FORBIDDEN. See Errors.

Operations and required scopes

This table gives the scope that each common operation needs:

Queries

QueryRequired Scope
organizationorganization/read
organizationsorganization/read
projectorganization_projects/read
apiKeysorganization_api_keys/read
shopifyWebhooksorganization_integrations/read
shopifyMetafieldConfigsorganization_integrations/read
reportorganization_reports/read

Mutations

MutationRequired Scope
organizationCreateorganization/create
organizationUpdateorganization/update
organizationDeleteorganization/delete
organizationMemberInviteorganization_invitations/create
organizationInvitationRevokeorganization_invitations/delete
organizationMemberRemoveorganization_members/delete
organizationMemberRoleUpdateorganization_members/update
projectCreateorganization_projects/create
apiKeyCreateorganization_api_keys/create
apiKeyRevokeorganization_api_keys/delete
shopifyWebhookCreateorganization_integrations/create
shopifyWebhookUpdateorganization_integrations/update
shopifyWebhookDeleteorganization_integrations/delete
shopifyMetafieldConfigCreateorganization_integrations/create
shopifyMetafieldConfigUpdateorganization_integrations/update
shopifyMetafieldConfigDeleteorganization_integrations/delete
reportCreateorganization_reports/create
reportUpdateorganization_reports/update
reportDeleteorganization_reports/delete

Some mutations do not require organization-level scopes because they operate on the caller's own data:

MutationRequirement
sessionStart / sessionCreate / sessionRefreshNo authentication required
accountCreate / accountVerifyEmail / accountResendVerificationNo authentication required
oauthAuthorize / oauthCallbackNo authentication required
magicLinkSend / magicLinkVerifyNo authentication required
passwordResetSendNo authentication required
passwordUpdateAuthenticated session (no specific scope). Exempt from the MFA requirement, so a user can set a password before they add a factor. A user with a verified factor needs an AAL2 session.
organizationInvitationAccept / organizationInvitationDeclineAuthenticated session (no specific scope)
mfaFactorEnroll / mfaChallengeCreate / mfaChallengeVerify / mfaFactorUnenrollAuthenticated session (no specific scope). Exempt from the MFA requirement, so a user can add a factor and verify it.

userMfaReset needs the root-level scope users/reset_mfa (USERS_RESET_MFA). The mutation removes every authenticator of a user and signs the user out everywhere, so their next sign-in starts at the setup.

Read your scopes

Root-level scopes

The viewerScopes query returns the root-level scopes for the authenticated caller:

query {
  viewerScopes
}

Response:

{
  "data": {
    "viewerScopes": ["ORGANIZATION_CREATE"]
  }
}

Organization-level scopes

Each Organization object exposes a viewerScopes field that returns the scopes the caller has within that specific organization:

query {
  organization(input: { slug: "my-company" }) {
    id
    name
    viewerScopes
  }
}

Response:

{
  "data": {
    "organization": {
      "id": "org_abc123",
      "name": "My Company",
      "viewerScopes": [
        "ORGANIZATION_READ",
        "ORGANIZATION_UPDATE",
        "ORGANIZATION_MEMBERS_READ",
        "ORGANIZATION_PROJECTS_READ",
        "ORGANIZATION_PROJECTS_UPDATE",
        "ORGANIZATION_PROJECTS_DELETE",
        "ORGANIZATION_API_KEYS_CREATE",
        "ORGANIZATION_API_KEYS_READ",
        "ORGANIZATION_API_KEYS_DELETE",
        "ORGANIZATION_INTEGRATIONS_CREATE",
        "ORGANIZATION_INTEGRATIONS_READ",
        "ORGANIZATION_INTEGRATIONS_UPDATE",
        "ORGANIZATION_INTEGRATIONS_DELETE",
        "ORGANIZATION_REPORTS_READ"
      ]
    }
  }
}

Use this to build a UI that changes with the permissions of the caller. An example is a Delete Organization button that the UI hides when the caller does not hold ORGANIZATION_DELETE.