References

Snap-in scopes

Snap-ins support scopes, a permissions framework for controlling access during execution. Declare the permissions needed by the snap-in's own service account separately from the permissions requested by each operation when a workflow or agent uses it. This lets each component request only the access it needs.

Declare both service_account.scopes and operations[].static_scopes in the manifest if your snap-in defines operations. The snap-in service account receives its declared permissions at installation; an operation's requested permissions come from its own scope declaration, not from the snap-in service account.

During installation, users review and grant the permissions requested for the snap-in service account. An operation requests its own permissions when a workflow or agent uses it. Installation proceeds only after the required snap-in permissions have been accepted.


Scope format

Each scope follows an object:permission syntax. You specify the object type you need access to, followed by a colon, followed by the permission level.

Permission levels

Most objects support three standard permission levels:

ScopeWhat it grants
object:readRead-only access (get, list, count)
object:writeRead, create, and update access
object:allFull access — read, create, update, and delete

Some objects use more granular permissions like object:update (grants create and update but not broader write access). When in doubt, refer to the API-to-scope reference.

Examples

ScopeMeaning
ticket:readRead-only access to tickets
ticket:writeRead, create, and update tickets
rev_user:writeRead, create, and update customer details
article:updateRead and update articles
conversation:readRead access to conversations
command:writeCreate and update commands
tag:writeCreate or modify tags

Add scopes to a snap-in

1. Identify the APIs your snap-in uses

Review your snap-in's code and identify all DevRev API calls it makes. For example, if your snap-in creates timeline entries and updates customers, note the endpoints: timeline-entries.create, rev-users.get, rev-users.update.

2. Determine the required scopes

Map each API endpoint to its corresponding scope using these general rules:

  • GET/list operations → object:read
  • Create and update operations → object:write
  • Delete operations → object:all

For timeline-entries.create and timeline-entries.update, the required scope is the parent object's read permission — if the timeline entry belongs to an issue, you need issue:read; if it belongs to a ticket, you need ticket:read.

Referenced DON IDs require read scope. Any DevRev object reference (DON ID) passed in a request payload requires the corresponding :read scope on that object type, in addition to the scope required for the operation itself.

For example, calling works.create to create an issue with a tags field that references existing tag DON IDs requires both:

  • issue:write — to create the issue
  • tag:read — to resolve and validate each tag DON ID passed in the payload

This applies to every endpoint and every field that accepts a DON ID — owners, parts, accounts, custom object references, and so on. Audit each request payload for DON ID fields and add a :read scope for every referenced object type.

Refer to the API-to-scope reference for the complete mapping.

3. Add scopes to the manifest

Declare the scopes in the service_account section of your snap-in's manifest file:

service_account:
  display_name: DevRev Bot
  scopes:
    self:
      - scope: conversation:read
        optional: false
        reason: "Allow read access to conversations."
      - scope: rev_user:write
        optional: false
        reason: "Allow read and update customer details."
      - scope: comment:write
        optional: false
        reason: "Allow creation and updating of timeline entries."

Each scope entry includes:

FieldDescription
scopeThe permission being requested, in object:permission format
optionalWhether the scope is required (false) or optional (true) for installation
reasonA human-readable explanation shown to users during installation

If the snap-in defines operations, declare the permissions each one requests separately under operations[].static_scopes. These are the permissions requested for the workflow or agent using the operation, not additional permissions granted to the snap-in service account. For example, a snap-in that reads tickets in its own automation and exposes an operation that reads issues declares ticket:read under service_account.scopes and issue:read under that operation's static_scopes. If both need issue:read, declare it in both places.

Each operation declares its own static_scopes. Use static_scopes.impersonation if the operation needs to act on behalf of a user; the corresponding field under service_account.scopes is named impersonate. See Snap-in operations for the operation format and a handler example.

4. Publish your snap-in

The snap-in creation and draft process remains the same. In the UI, installers grant the service account's required permissions. Operation scopes are requested separately when a workflow or agent uses the operation.

5. Upgrade an existing snap-in

For existing snap-ins, add the scopes to the manifest and republish. The upgrade flow remains the same. For DevRev snap-ins, ensure the marketplace.yaml file is present alongside manifest.yaml.


Scope types: self vs. impersonate

Scopes are organized into two categories under the service_account section.

Self scopes

Self scopes define the permissions the service account has when operating on its own behalf. This is the most common type.

service_account:
  scopes:
    self:
      - scope: ticket:read
        optional: false
        reason: "Read ticket details."

Impersonate scopes

Impersonate scopes define the permissions the service account has when acting on behalf of another entity (a customer or user). The effective permissions are the intersection of the service account's impersonate scopes and the impersonated user's own permissions—so the snap-in can never exceed what the user themselves could do.

service_account:
  scopes:
    impersonate:
      - act_as: all_devusers
        scopes:
          - scope: ticket:read
            optional: false
            reason: "Read tickets on behalf of the user."

Scopes for manifest-defined objects

If your snap-in's manifest creates objects like commands, tags, imports, event sources, or dashboards, include the corresponding scopes as well, since these objects are created via the service account.

For example, if your manifest defines tags and commands:

service_account:
  display_name: Example Snap-in
  scopes:
    self:
      - scope: command:write
        reason: "For command creation."
      - scope: tag:write
        reason: "For tag creation."
      - scope: event_source:write
        reason: "For event source creation."

tags:
  - name: exampleTag
    description: Example description

commands:
  - name: exampleCommand
    namespace: devrev
    description: Example description
    surfaces:
      - surface: discussions
        object_types:
          - snap_in
    usage_hint: ""
    function: init_category_import

event_sources:
  organization:
    - name: devrev-webhook
      description: Event coming from DevRev
      display_name: DevRev
      type: devrev-webhook
      config:
        event_types:
          - work_created

Custom object scopes

For snap-ins that work with custom objects, scopes follow this format:

custom_object:<leaf_type>:<permission>

Example: custom_object:asset:read grants read access to the custom object type asset.

Custom object scopes are created automatically when a custom object is defined via the consumer.

For certain cases, you might need to allowlist a snap-in to bypass the custom object scopes requirement. Check the Manage allowlist exceptions section for more details.


Empty scopes

If your snap-in does not call any DevRev APIs and needs no permissions, declare empty scopes to indicate this explicitly:

service_account:
  display_name: DevRev Bot
  scopes:
    self:

This tells the platform that the service account intentionally requires no permissions. If the snap-in defines operations, also declare static_scopes on each operation, even when an operation requests no permissions:

static_scopes:
  self: []

An empty service-account scope declaration does not make an operation's scope declaration optional, and an empty operation scope declaration does not grant it the snap-in service account's permissions.


Best practices

Know the default self-permissions. The snap-in service account has default permission to read and update itself. Any API calls targeting the snap-in itself work without explicitly setting scopes.

Do not add required scopes after the initial release. Adding new required scopes on an update can break the snap-in for users who haven't granted the new permission. If you need additional scopes later, add them as optional: true. Optional scopes are granted automatically, but this behavior may change—plan your scopes from the start.

Remove scopes on updates without restriction. Removing scopes on subsequent updates is supported.

Request only what you need. Follow the principle of least privilege. Requesting fewer permissions makes it easier for admins to approve your snap-in and reduces security risk.

Include clear reasons. The reason field is shown to users during installation. Write descriptions that explain why each permission is needed in plain language.


Allowlist exceptions

In some cases, the scopes framework cannot fully support a snap-in's requirements. For these, the snap-in can be added to the allowlist to bypass scopes and use the older systems group permissions.

Custom objects created during activation

If a snap-in creates a custom object during its activation hooks and also needs custom_object:<leaf_type>:<permission> scopes for that same object, a circular dependency exists. Because the object doesn't exist yet when scopes are evaluated, these snap-ins need to be added to the allowlist.

Impersonation with agent authorization

If a snap-in uses impersonation scopes with act_as and expects permissions to be the intersection of the user's and service account's permissions, it may need to be added to the allowlist until agent impersonation is fully rolled out.

If your snap-in falls into either of these categories, raise a ticket to request allowlisting by snap-in version or package slug.


API-to-scope reference

The table below maps commonly used APIs to their required scopes. For the complete auto-generated reference covering every public endpoint, see the API-to-scope reference.

Work items (tickets, issues, opportunities)

The works.* APIs require scopes for each work item type your snap-in interacts with.

APIRequired scopes
works.get, works.list, works.count, works.group, works.exportticket:read, issue:read, opportunity:read
works.create, works.updateticket:write, issue:write, opportunity:write
works.deleteticket:all, issue:all, opportunity:all

Accounts and workspaces

APIRequired scope
accounts.get, accounts.listaccount:read
accounts.create, accounts.updateaccount:write
rev-orgs.get, rev-orgs.listrev_org:read
rev-orgs.create, rev-orgs.updaterev_org:write

Users

APIRequired scope
rev-users.get, rev-users.listrev_user:read
rev-users.create, rev-users.update, rev-users.mergerev_user:write
rev-users.deleterev_user:all
dev-users.get, dev-users.listdev_user:read
dev-users.create, dev-users.updatedev_user:write

Conversations

APIRequired scope
conversations.get, conversations.listconversation:read
conversations.create, conversations.updateconversation:write

Timeline entries

Timeline entries require the parent object's read scope. If the entry belongs to a ticket, you need ticket:read; if it belongs to an issue, you need issue:read.

APIRequired scope
timeline-entries.create, .update, .get, .list, .delete<parent>:read

Articles

APIRequired scope
articles.get, articles.listarticle:read
articles.create, articles.updatearticle:update
articles.deletearticle:all

Tags and commands

APIRequired scope
tags.get, tags.listtag:read
tags.createtag:write
commands.getcommand:read
APIRequired scope
links.listlink:read
links.createlink:write
links.deletelink:all

Engagements and meetings

APIRequired scope
engagements.listengagement:read
engagements.create, engagements.updateengagement:write
engagements.deleteengagement:all
meetings.get, meetings.listmeeting:read
meetings.create, meetings.updatemeeting:write

Incidents

APIRequired scope
incidents.get, incidents.listincident:read
incidents.create, incidents.updateincident:write

Surveys

APIRequired scope
surveys.get, surveys.listsurvey:read
surveys.create, surveys.update, surveys.send, surveys.submitsurvey:write

Groups and roles

APIRequired scope
groups.get, groups.listgroup:read
groups.updategroup:update
groups.members.listgroup_membership:read, group:read
groups.members.add, groups.members.removegroup_membership:update, group:read
roles.listrole:read
roles.create, roles.apply, roles.updaterole:update

Artifacts and dashboards

APIRequired scope
artifacts.get, artifacts.download, artifacts.locateartifact:read
artifacts.prepareartifact:create
dashboards.get, dashboards.listdashboard:read
dashboards.create, dashboards.updatedashboard:write

Workflows

APIRequired scope
workflows.getworkflow:read
workflows.create, workflows.templates.instantiateworkflow:write
workflows.deleteworkflow:all

Custom objects

APIRequired scope
custom-objects.get, custom-objects.list, custom-objects.countcustom_object:<leaf_type>:read
custom-objects.create, custom-objects.updatecustom_object:<leaf_type>:write
custom-objects.deletecustom_object:<leaf_type>:all

Snap widgets

APIRequired scope
snap-widgets.get, snap-widgets.countparent:read, snap_widget:read
snap-widgets.create, snap-widgets.updateparent:read, snap_widget:write

APIs that require no scope

The following APIs do not require explicit scopes: schemas.aggregated.get, schemas.custom.list, schemas.stock.list, schemas.subtypes.list, stage-diagrams.list, stages.custom.get, stages.custom.list, states.custom.get, states.custom.list, snap-ins.get, snap-ins.update, and recommendations.* endpoints.


FAQ

Does my existing snap-in stop working? No. Previously published snap-ins are not affected. Scopes are only required when publishing a new snap-in or republishing an updated version.

What happens if I don't define scopes? Publishing a scope-enforced snap-in is blocked if service_account.scopes is missing or any operation lacks static_scopes. Declare empty scopes explicitly if no permissions are needed.

Can I change scopes after publishing? You can remove scopes. You can add new scopes as optional: true. Adding new required scopes after the initial release is not supported—it can break the snap-in for existing users.

What if my snap-in doesn't need any permissions? Use empty scopes (self: with no entries) to explicitly declare that no permissions are required.

How do custom object scopes work? Use the format custom_object:<leaf_type>:<permission>. For example, custom_object:asset:read. These scopes are created automatically when a custom object is defined.

Where can I find the full API-to-scope mapping? See the API-to-scope reference—it is auto-generated from the public OpenAPI spec and stays up to date with every spec change.

Last updated on