RFCs are a way for Atlassian to share what we’re working on with our valued developer community.
It’s a document for building shared understanding of a topic. It expresses a technical solution, but can also communicate how it should be built or even document standards. The most important aspect of an RFC is that a written specification facilitates feedback and drives consensus. It is not a tool for approving or committing to ideas, but more so a collaborative practice to shape an idea and to find serious flaws early.
Please respect our community guidelines: keep it welcoming and safe by commenting on the idea not the people (especially the author); keep it tidy by keeping on topic; empower the community by keeping comments constructive. Thanks!
Project summary
We’re currently developing a capability that will enable Forge apps to expose REST APIs. This will include two new Forge modules, apiScope
and apiRoute
. Such APIs can be used to allow authorized external systems to securely invoke functions from an installed app. This project aims to address the limitations of current web triggers by providing a more secure and readable API solution.
- Publish: 9 June 2025
- Discuss: 30 June 2025
- Resolve: 11 July 2025
Problem
Some apps need to support inbound integrations from external systems (that is, from outside the customer’s site or UI). Example integrations might be from an external app, a cron job, a plugin, or even direct API calls. For now, the only way to accomplish this in Forge is via web triggers. However, this poses several challenges:
- Forge doesn’t authenticate web trigger URLs by default.
- Web trigger URLs aren’t human-readable, and can’t be defined.
- Web trigger functions can only call Atlassian APIs using
asApp()
. There is no way to pass in user context by default. - Site admins can’t control any data egress or other functions exposed by web triggers.
- Apps that use dynamic web triggers are not eligible for Runs on Atlassian.
Proposed solution
The proposed Forge REST API module will be declared in the manifest file, where you’ll also be able to define:
- Part of the URL path.
- Scopes for the API.
- HTTP method for the call.
Manifest changes
The following sample manifest declaration shows the manifest shape we’re currently considering:
modules:
apiScope:
- key: get-payroll
actions:
- 'read'
noun: 'payroll'
- key: edit-payroll
actions:
- 'write'
- 'delete'
noun: 'payroll'
apiRoute:
- key: get-emp-payroll
path: /payroll
method: GET
function: getPayrollFunction
accept:
- application/json
scopes:
- get-payroll
app:
name: 'Business Financials'
id: ari:cloud:ecosystem::app/4fea1a3a-76d3-46b2-8410-fa66c59744e7
The properties for the apiScope and apiRoute modules are as follows:apiScope
key
- Name of the scope.actions
- Actions (read, write, etc) that can be performed under this scope.noun
- Name signifying the app entity/object that the scope covers.
apiRoute
key
- Name of the API route.path
- Developer-defined path that will appear in the final URL.method
- HTTP methods like GET, PUT, etc.function
- Forge function that the route is mapping to.accept
- Payload type that can be accepted. For now, only json will be accepted.scopes
- Scope (keys as declared in “apiScope“) that the API uses.
URL and paths
For the production environment, the resulting GET API URL will look something like:
https://<site-name>/gateway/api/svc/<product>/<appid>/payroll
For example, a Jira app exposes a /payroll
REST API endpoint and has an app ID (from the manifest) of ari:cloud:ecosystem::app/4fea1a3a-76d3-46b2-8410-fa66c59744e7
. If the app is installed on client site abc.atlassian.net
, the endpoint’s full URL would be
https://abc.atlassian.net/gateway/api/svc/jira/4fea1a3a-76d3-46b2-8410-fa66c59744e7/payroll
The same function maps to different URLs in staging and development environments. We’re proposing environment recognition via URL to avoid possible mistakes in usage (for example, to prevent a developer from accidentally accessing production data while testing in development):
For the staging environment, the URL would be:
https://<site-name>/gateway/api/svc/<product>/<appid>-staging/payroll
For the development environment, the URL would be:
https://<site-name>/gateway/api/svc/<product>/<appid>-<env-id>/payroll
Query and path parameters, and custom headers, will be supported.
Wildcards & routing patterns
Forge REST APIs will support a routing and wildcard structure similar to Ant Pattern. In any given path, you can use *
for single-segment matching and **
for multi-segment matching. For example:
Forge will use the following logic for sub-routes between <app-id>/
(the start of the sub-path) and ?
(end of path):
- IF an exact path match is found, route to the exact-match handler
- ELSE if single segment
*
match is found, route to the single-segment-match handler - ELSE if generic
**
route match is found, route to this handler - ELSE call fails with
Invalid route
message.
Developer-defined scopes
Partners will be required to define scopes for the declared REST API. These scopes will be used to restrict the API’s access. For now, we’re proposing two levels of developer-defined scopes:
noun
: objects or entities within an app. For example,custom-field
for an app like Issue Picker for Jira.actions
:read
,write
, ordelete
for everynoun
.
Admin controls
We also plan to let admins enable or disable REST API functionality exposed by the app. This would be toggle in Atlassian Administration to enable/disable the app’s API for that particular installation.
Authentication
Once the manifest file changes are made and deployed by the developer, the REST API can be invoked. We currently plan to prioritize Three Legged OAuth (3LO), with 2LO (or API key) support likely to come in a future milestone.
Runs on Atlassian
Apps adopting this new module will be eligible for the Runs on Atlassian Marketplace badge as long as all other Runs on Atlassian criteria is also met.
FAQs
Is there support for different versions of the same API?
No, we are not planning to support versioning as part of the API definition. However, you will be able to include version numbers in your path
s if you choose to, and you will be able to create different apiRoute
s that map to different functions.
What happens if I delete the function or the module from manifest?
Removing any function from manifest will be treated as a DELETE
action. This will be a minor update and the API will stop working for all customers post deployment. Hence, we advise that this action be handled very carefully.
Will there be rate-limiting for these APIs?
As with other Atlassian apps, the current rate limits will be applicable for these APIs. Developer-defined rate-limits can be considered in the future if there is sufficient demand.
Are there any limitations on usage of the APIs or declaration of the new module?
Some general limits are mentioned in the platform quotas and limits documentation. In addition:
- There will be restrictions on the length of the defined URL path (250 chars) and type of characters allowed in its definition (alphanumeric allowed with special char “/”).
- Since Forge offers support for JSON formatting in the request body, the same capability will also be offered for this module. As such, requests in the form of XML or CSV will not be supported and will have to be transformed to a JSON object.
- Payload size limits will be same as web triggers currently. For web triggers, request payload size is limited to 800 kB. Response payloads of size less than 5 MB can be handled. Changes may be introduced in future phases.
Asks
Thank you for taking the time to read this RFC. We’re especially interested in learning more from you about:
- Are there use cases that the current solution will not solve for?
- What guidelines would be needed by partners for them to be able to define concise scopes for their apps and map them to individual APIs?
- What is the approximate number of actions/nouns that partners think they would need to define?