The Teamwork Graph API is available through Forge's Preview release phase.
Preview features are available to all users and receive the same level of support as generally available features. Schemas, fields, and behavior may still change before general availability (GA), and breaking changes are subject to a minimum 1-month deprecation notice, announced in the Teamwork Graph changelog.
To review the current limitations, see Limitations and considerations.
To share feedback or report an issue, visit the Atlassian developer community.
Every object type in the Teamwork Graph API has its own scope. Your app can only read an object type if two things are true:
Scopes are how a customer decides which slice of their graph your app can see. An admin who is happy for your app to read Jira work items but not Confluence pages can grant one and withhold the other, and your queries keep working for the part they approved.
The scope reference on this page is the definitive list. If you built your app
during the Early Access Program against the broader read:graph:jira or read:graph:confluence
scopes, see Moving off the EAP scopes.
Teamwork Graph API scopes follow one pattern:
1 2read:graph:<object>:<product>
So for example ConfluencePage needs
read:graph:page:confluence, and
JiraWorkItem needs
read:graph:issue:jira. All Teamwork Graph API scopes are read-only — there is no write access to
the graph through this API.
The scope reference at the end of this page lists the scope for every object type.
Add the scopes your app needs to the permissions block of your manifest.yml:
1 2 3 4 5 6permissions: scopes: - 'read:graph:issue:jira' - 'read:graph:project:jira' - 'read:graph:user:atlassian'
When configuring Forge apps that interact with the Teamwork Graph, organization administrators can manage and restrict data access using granular Teamwork Graph scopes in Atlassian Administration. From the app's configuration page (Connected Apps > select your app > Permissions), Administrators can toggle individual scopes on or off to grant or revoke access to specific graph entities and relationship types, or use category-level Allow all / Block all bulk controls to manage permissions at scale. When a scope is toggled off, any queries targeting that entity or relationship are blocked server-side, giving organizations fine-grained control over their graph data access.
Apps built during the Early Access Program requested one of two product-wide scopes,
read:graph:jira or read:graph:confluence, each of which covered every object type in that
product. Those scopes are being retired in favour of the per-object-type scopes on this page.
To migrate:
manifest.yml with those scopes.Declare a scope only for the object types your queries actually touch. One product-wide EAP scope can expand into a long list of per-object-type scopes, and Forge currently has a scope cap of 50. See: Forge scopes.
Start from the data your app reads, not from the query you wrote.
For a Cypher query, list every object type the query touches, including types you traverse through but never return. This query needs three scopes, not one:
1 2 3 4MATCH (user:AtlassianUser {ari: $userId})-[:atlassian_user_assigned_jira_work_item]->(item:JiraWorkItem) MATCH (item)<-[:jira_space_has_jira_work_item]-(space:JiraSpace) RETURN space
It returns only JiraSpace, but it reads AtlassianUser and JiraWorkItem on the way there, so it
needs read:graph:user:atlassian, read:graph:issue:jira, and read:graph:project:jira.
For a curated query, look at the types the field can
return. A field like atlassianUserAssignedJiraWorkItems returns JiraWorkItem, so it needs
read:graph:issue:jira plus read:graph:user:atlassian for the user it starts from. The two broad
fields, atlassianUserRecentlyViewed and atlassianUserWorkQuery, return a wide union of types —
request scopes for the members you want to handle, and the rest are simply left out of the results.
For a persisted Cypher query, the same rule applies as for any Cypher query. Scopes are checked when the query runs, not when you register it, so registering a query successfully doesn't mean your app can execute it against every site.
This is the most important thing to understand about scopes:
A missing scope doesn't produce an error. The object type is treated as unreadable, so the rows that would have contained it are not returned. A query that reads an object type you weren't granted comes back successful and empty.
This is deliberate — the API fails closed rather than leaking data — but it means an empty result set is ambiguous. It can mean "no matching data" or "your app wasn't granted this scope".
Three consequences follow from it.
A missing scope anywhere in the traversal empties the whole result. Both objects and the relationships between them are checked, so in a query of the form A → B → C, lacking the scope for the middle object type B breaks the path even if you hold scopes for A and C.
Mixed traversals return partial results. If a relationship can return several object types and
you only hold some of those scopes, you get the types you were granted and silently miss the others.
For example, a traversal that can return ConfluencePage, ConfluenceBlogPost, and
ConfluenceDatabase returns only pages if read:graph:page:confluence is the only one of the three
you were granted.
Scope changes take up to a minute. After an admin enables or disables a scope, allow about a minute before the change is reflected in query results.
Work through these in order when a query returns nothing and you expect data:
One scope per object type, grouped by where the data comes from.
| Object type | Scope |
|---|---|
| JiraWorkItem | read:graph:issue:jira |
| JiraWorkItemComment | read:graph:issue-comment:jira |
| JiraWorkItemStatus | read:graph:issue-status:jira |
| JiraWorkItemPriority | read:graph:priority:jira |
| JiraWorkItemRemoteLink | read:graph:issue-remote-link:jira |
| JiraWorklog | read:graph:issue-worklog:jira |
| JiraSpace | read:graph:project:jira |
| JiraBoard | read:graph:board:jira |
| JiraSprint | read:graph:sprint:jira |
| JiraVersion | read:graph:version:jira |
| Object type | Scope |
|---|---|
| ConfluencePage | read:graph:page:confluence |
| ConfluenceBlogPost | read:graph:blogpost:confluence |
| ConfluenceComment | read:graph:comment:confluence |
| ConfluenceDatabase | read:graph:database:confluence |
| ConfluenceFolder | read:graph:folder:confluence |
| ConfluenceSpace | read:graph:space:confluence |
| ConfluenceWhiteboard | read:graph:whiteboard:confluence |
| Object type | Scope |
|---|---|
| AtlassianUser | read:graph:user:atlassian |
| AtlassianTeam | read:graph:team:atlassian |
| AtlassianTeamType | read:graph:team-type:atlassian |
| AtlassianGoal | read:graph:goal:atlassian |
| AtlassianGoalUpdate | read:graph:goal-update:atlassian |
| AtlassianProject | read:graph:project:atlassian |
| AtlassianProjectUpdate | read:graph:project-update:atlassian |
| AtlassianHomeTag | read:graph:tag:atlassian |
| AtlassianHomeComment | read:graph:comment:atlassian |
| AssetsObject | read:graph:assets-object:atlassian |
| Object type | Scope |
|---|---|
| LoomVideo | read:graph:video:loom |
| LoomComment | read:graph:comment:loom |
| LoomMeeting | read:graph:meeting:loom |
| LoomMeetingRecurrence | read:graph:meeting-recurrence:loom |
| LoomSpace | read:graph:space:loom |
| Object type | Scope |
|---|---|
| CompassComponent | read:graph:component:compass |
| CompassComponentLink | read:graph:component-link:compass |
| CompassScorecard | read:graph:scorecard:compass |
| OpsgenieTeam | read:graph:team:opsgenie |
| FocusFocusArea | read:graph:focus-area:focus |
| FocusFocusAreaStatusUpdate | read:graph:focus-area-status-update:focus |
| FocusChangeProposal | read:graph:change-proposal:focus |
| TalentPosition | read:graph:position:talent |
| TalentWorker | read:graph:worker:talent |
These object types hold data that reached the graph through a
connector, such as GitHub, Google Drive, or
Slack. The scope covers the object type across every connected tool, so
read:graph:pull-request:external covers pull requests from any source.
| Object type | Scope |
|---|---|
| ExternalWorkItem | read:graph:work-item:external |
| ExternalDocument | read:graph:document:external |
| ExternalSpace | read:graph:space:external |
| ExternalProject | read:graph:project:external |
| ExternalComment | read:graph:comment:external |
| ExternalMessage | read:graph:message:external |
| ExternalConversation | read:graph:conversation:external |
| ExternalRepository | read:graph:repository:external |
| ExternalBranch | read:graph:branch:external |
| ExternalCommit | read:graph:commit:external |
| ExternalPullRequest | read:graph:pull-request:external |
| ExternalBuild | read:graph:build:external |
| ExternalDeployment | read:graph:deployment:external |
| ExternalFeatureFlag | read:graph:feature-flag:external |
| ExternalService | read:graph:service:external |
| ExternalVulnerability | read:graph:vulnerability:external |
| ExternalDesign | read:graph:design:external |
| ExternalVideo | read:graph:video:external |
| ExternalCalendarEvent | read:graph:calendar-event:external |
| ExternalDashboard | read:graph:dashboard:external |
| ExternalDataTable | read:graph:data-table:external |
| ExternalRemoteLink | read:graph:remote-link:external |
| ExternalDeal | read:graph:deal:external |
| ExternalCustomerOrg | read:graph:customer-org:external |
| ExternalCustomerOrgCategory | read:graph:customer-org-category:external |
| ExternalCustomerContact | read:graph:customer-contact:external |
| ExternalOrganisation | read:graph:organisation:external |
| ExternalPosition | read:graph:position:external |
| ExternalWorker | read:graph:worker:external |
If you need a scope that isn't listed, or a query returns nothing and you've ruled out the causes above, ask in the Atlassian developer community or raise a ticket in the Atlassian Ecosystem Help Center.
Rate this page: