RFC-97:REST APIs in Forge

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, or delete for every noun.

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 paths if you choose to, and you will be able to create different apiRoutes 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?
3 Likes

Hey Rashi,

I’m slightly confused by this RFC, or rather, by the implications regarding RoA that emerge from this RFC.

I see that response payloads up to 5MB are allowed, which implies that responses will be dynamic (i.e. not like static web triggers), by definition this enables data egress.
It’s hard to come up with a rational justification that would allow REST APIs with Runs on Atlassian, but that disqualifies you if you are using optional/configurable egress (RFC-94) and the current proposals would force people to implement weird workarounds to get data out of their app – in this case, using a REST API and some kind of integration that runs outside of Atlassian, but for some reason that would qualify for RoA.

Lastly, there is significant overlap with dynamic webtriggers, are they going to be deprecated? I can hardly think about use cases in which I’d use those instead of this proposed feature.

5 Likes

This RFC is great. I’d like to suggest that we use a standard way of describing APIs though, like an Open API specification, rather than listing all endpoints in the manifest. That would make it much easier to migrate existing APIs to Forge, and would easily connect with other API management/design tools as well.

7 Likes

This is a welcome improvement.
Can you provide more information on the developer-defined scopes? What restrictions and where will they be applied?

5 Likes

How will this work with Cross Context apps?

Will there be any requirements on the custom header names, like has to start with X-?

Is the write scope a combination in effect of create and update?
My use-case is not limited by this, but I have seen other apps that would benefit from having create and update separate.

  • Is there a way for the app to verify if an admin disabled the API?
    Either within the app itself, or through a response code from the API?
  • What is the API is critical to the functionality of the app?
    Will there be a way for developers to show a message to warn administrators if they which to disable the API.

Being able to use a custom authentication provider implementation to support JWT in different implementation is a requirement for me to be able to use the Rest API module.
My current APIs use JWT based authentication, using both the shared secret method like Connect as the key-pair method of Forge Invocation Token.

Sorry but this makes no sense. The use of Forge Remotes disqualifies an app for Runs on Atlassian because of data egress, but this API with a 5MB response limit is qualified (as long as it doesn’t use Forge Remotes) to egress as much data as it likes in 5MB chunks?

And what happens if I add the API modules to my manifest? Is that a major of minor update?

2 Likes

Completely agree with @VitorPelizza : Please use the standard OpenAPI description.

2 Likes

This is great! I can use custom analytics events to any remote that I like (using permissions.external[].category: 'analytics') to trigger a Forge API REST call that will allow me to fetch 5MB of data from the host product for external processing and post back the results using that same Forge API and my app will still qualify for Runs on Atlassian :tada:

I only need to adjust my EULA to enforce that analytics has to be enabled if they want to use my app and I’m all set!

9 Likes

This is a great addition. We have multiple feature requests from customers to provide APIs. We tried to use web trigger to do this in the past, which was really awkward.

Developer-defined scopes

Will this affect the app permissions and whether the new version will be considered minor or major?

1 Like

I think this RFC is too focused on a specific idea, too opinionated, and overcomplicated. The cited problem that this RFC wants to solve is:

Some apps need to support inbound integrations from external systems

In my opinion, Atlassian should focus on implementing an authentication mechanism to call into a Forge app and provide users with egress controls if that’s required. The rest should be left to the developer because

  • if we want to implement a REST API, we can
  • if we want to implement a GraphQL API, we can
  • if we want to implement an RPC API, we can
  • if we want to implement a Websocket API, we probably can
  • for all of the above, we can use industry-standard tools, e.g., define an API as an OpenAPI spec and generate a client and server implementation

Instead of implementing an opinionated form of REST API, why not focus on implementing 2LO and 3LO OAuth that can work with any of the above-mentioned API patterns?

Everything with routing patterns, API definitions in the manifest, and clean URLs are unnecessary complications. Clean or configureable URLs are a nice to have but APIs are meant to be used by programs not humans, so I really don’t think it matters all that much.

The point made by others about RoA is an obvious flaw, and it seems Atlassian is getting confused themselves about what RoA should actually represent.

11 Likes

Hello @PaoloCampanelli

We understand why this might be confusing with respect to Runs on Atlassian, but the definition of Runs on Atlassian includes that customers have control over data egress, such as analytics and logs, and can fully block data egress at any time.

We view this as similar to how Jira and Confluence offer REST APIs, which are secure by default and can be disabled by administrators if desired.

cc @tbinna @remie

1 Like

Hello @VitorPelizza

We have explored the idea of supporting API definitions via an Open API spec but it would be difficult to support at the moment given our current infrastructure.

It is possible that we might be able to support it in future.

cc @tbinna @marc

1 Like

Hello @jmort

The developer defined scopes will restrict the resources (i.e. apiRoutes) that will accept requests. These will be enforced at the Atlassian gateway level, so requests without the required scopes won’t make it through to your app.

Changing the scopes that your REST API supports would be considered a minor version change for your Forge app. Any external clients using your REST API would need to reauthorize to use the new scopes and associated routes.

Adding the REST API module for the first time would trigger a major version upgrade because admins will need to decide it they want it enabled.

cc @chhantyal

Marketplace signals and program eligibility
Configurable egress / remotes enable partners to deliver more flexible apps which increase customer trust by enabling them to better understand and control how their data is managed. With that said, the ability to share data remotely would preclude these apps from being eligible for Runs on Atlassian in the program’s current definition and state.
This RFC will not explore the impacts of the utilisation of this capability on RoA or other marketplace signals at this time.

Quoting from here.

If this inconsistency isn’t addressed before these features become available to customers, the whole point of RoA will be lost: an app with REST APIs can share data remotely. For sure, it will be on the customer to decide who and what can call those APIs, but isn’t it exactly the same with optional/configurable egress?

REST API Optional egress
Customer decides who uses it Yes Yes
Customer can disable it Yes Yes
Can send data out to 3rd parties Yes Yes
Guarantees data residency No No
On by default Yes Yes
RoA Yes No

Make it make sense, because I can’t

5 Likes

The point we are trying to make is that these definitions are being stretched as Atlassian is navigating the Atlassian <> Customer <> Partner love triangle minefield.

Also, please do not try to rewrite history: analytics & logs egress was not possible in RoA until Marketplace Partners explicitly started to ask for it. Adding data egress control for external egress of analytics data was the compromise between Atlassian and partners.

Which was fine, because analytics should always be considered optional features, and customers should always be able to disable them (not in the least because of regulatory requirements).

However, Forge API (as well as user-defined Forge Remotes) are bound to become non-optional features of apps: disabling them means the app won’t work. Which means data egress control becomes meaningless.

By allowing Forge API in the RoA program, Atlassian is eroding the RoA trust signal, making it just another bullshit marketing gimmick like previously happened to Cloud Security and Cloud Fortified programs.

As soon as Risk & Compliance / procurement departments find out RoA does not mean no-data-egress we are back at square one.

3 Likes

Thanks for the RFC. A REST API module as described here will unblock many aspects of our apps as we transition to Forge.

Here are some initial thoughts:

Thanks for keeping environment identifiers out of the production URLs :slight_smile:
While REST APIs are in the end typically used by automations, IMO it’s still preferable to keep the URLs as human-readable as possible, because it makes it easier for customers writing their own scripts, and for our support staff to review them.
I’d even wish for something more readable than the APP IDs but I don’t have high hopes :smiley:

For us it’s imperative that end users can call these APIs with their Atlassian account’s API tokens, because we’d use this module for offering REST APIs for customers so they can call them from custom scripts.

Aside of this, could you describe how 3LO could be used by two forge apps to use REST APIs for inter-app communication? We’d need this for building larger solutions from individual apps and for this they would naturally need to communicate with each other. A REST API module forwarding the user context would be a great fit for this.

Could you please confirm if these are per site? We’d definitely want to prevent a single customer’s misbehaving python script from blocking REST API access to other sites for unrelated customers.

We have a use case where we need to respond with larger payloads (essentially unbounded file downloads). In our connect apps we currently handle this via S3 downloads and will do the same as long as we are using Forge Remotes. We will however require some sort of solution for this later on when transitioning away from Forge Remotes to Forge containers for RoA. IMO this could be solved in many ways, for example higher limits in the REST API or by offering an authenticated download endpoint in Forge Object Storage, etc.

1 Like

Hi,
You can define a maximum of 100 modules in forge manifest. As far as I can see, you need to define at least two modules for each end-point (end-point and it’s function). You will also need to add modules for storage. If you don’t increase this limit, number of end-points that can be defined will be very limited. Of course you can reuse the same function for each end-point end implement switch inside the function, but this is not ideal and makes the forge metrics mostly useless.

2 Likes

For those within Atlassian who want to track how Forge power users have experienced the Runs on Atlassian marketing messages with regard to data egress:

Use it to your benefit with regard to a unified approach to Runs on Atlassian and data egress.

1 Like

Hi Remie,

Also, please do not try to rewrite history: analytics & logs egress was not possible in RoA until Marketplace Partners explicitly started to ask for it. Adding data egress control for external egress of analytics data was the compromise between Atlassian and partners.

Not sure what point you are trying to make - no one is trying to rewrite history regarding logs and analytics. Some, not all, customers recognised the value in giving partners access to this data so partners could better support and improve their app and partners certainly wanted it for the same reason as well. This is us consulting and listening to both audiences which reflects the product that we shipped two weeks ago.

However, Forge API (as well as user-defined Forge Remotes) are bound to become non-optional features of apps: disabling them means the app won’t work.

I will say this quite clearly: While your app holds Runs On Atlassian, the use of this feature or any other must never be used for exfiltrating customer data off of our platform to partner managed infrastructure. It is not a method for partners to continue business as usual as they have done on Connect. This is for customers to get their data from our platform. We will be vigilantly policing and enforcing this.

As soon as Risk & Compliance / procurement departments find out RoA does not mean no-data-egress we are back at square one.

Our research with customers shows that not all egress is inherently risky or undesirable. However, customers are used to a model where Atlassian Cloud apps must egress to the app developer and other external services to function. From their perspective, this type of egress isn’t really controlled. It’s mandated. There is no choice. This is a show stopper from their perspective unless they are committed to deep vetting of the partner.

With Runs On Atlassian apps, their data is stored and processed on our platform and the data doesn’t leave unless they consent. For us to keep Runs On Atlassian a true signal of trust, if egress must occur, it must occur with controls in place that protect the customer from risk and match the way they think about trust and risk.

REST APIs for Forge are managed with the same controls we have for our own product APIs. You must have a valid Atlassian Identity, scoped tokens, etc to use the API and the customer must consent. We can expire tokens or block access if we believe the customers data is being exfiltrated without their knowledge.

If you wish your app to remain Runs On Atlassian, your app must function if the customer disables API access or chooses not to give you a scoped token.

This is great! I can use custom analytics events to any remote that I like (using permissions.external[].category: 'analytics') to trigger a Forge API REST call that will allow me to fetch 5MB of data from the host product for external processing and post back the results using that same Forge API and my app will still qualify for Runs on Atlassian :tada:
I only need to adjust my EULA to enforce that analytics has to be enabled if they want to use my app and I’m all set!

You would certainly be getting a call from us in that scenario… but you’ve just described the exact problem we are worried when it comes to Dynamic Egress. How do we control partners using it to create apps that are Runs On Atlassian but do not function until the customer permits “dynamic egress” to their API? How can we provide the right governance and controls in this scenario? Great questions and ones we are working through, and why Sean has stated on that RFC that we don’t have an answer for it yet.

Thanks,
James Dumay
Group Product Manager

1 Like

Hey James,

I get your point, and I think the logic makes sense in theory, but it’s being applied in a way that is hard to understand.

I guess we can all agree that REST endpoints will be used to retrieve customer data, what else would we use them for? Those are on by default (as far as I can see from this post) and qualify for RoA.
Configurable egress can also be used to send customer data to third parties, it’s on by default and does not qualify for RoA.

My understanding of RoA is “This app can run without ever sending any data outside of Atlassian, the customer has the option to potentially allow data egress on their own terms”.

Any weird workaround such as what Remie was suggesting would obviously be disqualified since the app wouldn’t be able to function without egress, however I don’t understand why an app with progressive enhancement that uses configurable egress wouldn’t be allowed.

Let’s have an example: pretend that I work on a timetracker app (I don’t) in which a manager has to approve the timesheets entered by their underlings, my app can easily work well within the perimeter of Jira, so I can happily deploy as RoA and sell it to my Big Serious Enterprise Customers.
Now my PM comes to me with a feature request: a customer would like to also notify managers on Slack when there’s a new timesheet to be approved, this would be a completely optional feature, the app can still work without it.

My choices are:

  • Implement a (nonsensical) workaround using REST APIs and an external server that periodically polls data from my app – by the way since my external service won’t know whether that feature is enabled, it will have to poll every single instance
  • Hardcode an egress in my app and lose RoA even for people who aren’t going to use it
  • Declare a configurable egress, that the customer can point to Slack, their Kafka broker, or anywhere they want (or… simply disable it) and still lose RoA

My imaginary app isn’t doing anything weird or bad, it still lets the customer decide what they want to do, but I can’t properly implement it within RoA: this is what people are complaining about in these threads.

We want to give people the power to decide what to do with their own data, however there are features that customers want and require data egress, and we shouldn’t be penalized for providing optional features.

4 Likes

There is a reason Atlassian is having trouble figuring this out… it is because Atlassian wants two things that can’t co-exist.

The initial premise of Runs on Atlassian has always been that all data and processing remains within the Atlassian platform.

Step by step, Atlassian is finding out that this really narrows down the type of apps that qualify for Runs on Atlassian. Many apps require data egress to function. In addition, customers may want/need a way to access app data from the Forge platform.

So there are now three initiatives that are exploring amending the Runs on Atlassian program, allowing data egress:

  • Analytics & logs to external remotes
  • Forge REST API
  • Configurable egress & remotes

The first one is easy. Analytics should always be optional, the app continues to work, all is well. We accept that Atlassian cannot control the outbound payload so in theory analytics &
logs might contain user data from the platform. Atlassian acknowledges this by saying that we should act in the spirit of RoA when implementing analytics

In the context of Runs on Atlassian, you must not mark tools that don’t capture analytics data as analytics egress .

The configurable egress & remotes are causing headaches as this basically means unlimited outbound data egress. Sure, customers can enable/disable it, but typically these types of egress will be used for non-optional product features. Disabling egress means the app won’t work anymore. This is probably also why it is currently considered incompatible with RoA (and rightfully so!).

Now let’s look at the current RFC at hand, Forge REST API.

This RFC basically covers two scenario’s:

Inbound data

Inbound data is when the Forge REST API is used to trigger function execution, as a replacement for the current Forge web triggers:

Example integrations might be from an external app, a cron job, a plugin, or even direct API calls.

This is a valid scenario, but interestingly, the current specs do not really work well for this scenario: the request limit is 800kb, while the response limit is 5MB. So the external integration triggering the API can hardly sent any data for processing. It remains to be seen whether or not this is useful for integrations. In addition, one could argue that this scenario does not require a 5MB response, as a 204 No Content response code should be enough to acknowledge the trigger.

Outbound data

Outbound data is when the Forge REST API is used to extract app data. This is what @JamesDumay is referring to:

This is for customers to get their data from our platform.

This is another valid scenario, and this matches the request/response limit. The customer scripts or cron job hit the Forge REST API to get their data from the Atlassian platform. This should not require a large payload, so 800Kb is fine. The Forge REST API function has a 5MB response limit, which makes sense for offloading app data.

However, from the context of Runs on Atlassian, what makes this weird is that the app can intertwine app data and product data in the response. One could argue that the customer can just use the product REST API to get product data and that the Forge REST API should only be able to respond with app data (that is not accessible from the product API).

By allowing the Forge app to respond with product data in the Forge REST API, it negates the proposed (very valid) scenario of allowing customers to retrieve their app data.

Alternative solution 1

As we have seen with Connect, Atlassian Marketplace Partners are very resourceful in finding ways to use platform features in unexpected ways. We are already seeing with Analytics that Atlassian is now relying on partners to “do the right thing :trade_mark:” with data egress.

Let’s make sure that we do not make the same mistake again.

I would like to propose that Atlassian changes this RFC to allow 2 different types of Forge REST API endpoints: inbound & outbound.

The inbound REST API endpoints should allow for a large request body (5MB) and only support a response code (i.e. 200, 204, 400, 500, etc). This will allow integrations to send data to the Forge app, but ensures that there is no data egress. Inbound endpoints should have asApp and asUser access to product APIs in order to process the data for the app.

The outbound REST API endpoints should allow for a small request body (800kb) and a large response body (5MB) as this is meant to egress app data. However, the outbound API endpoints should NOT have asApp or asUser access to product REST APIs. It should only have access to Forge storage types (KV, SQL, etc).

This way, we can ensure that product data does not (accidentally) leak from the Forge REST API. It also means that Forge REST API can be qualified for Runs on Atlassian. Both inbound and outbound REST API endpoints can be considered optional.

Alternative solution 2

If the goal is to only support allowing customers to retrieve app data, Atlassian could also decide to take full control over this. It could expose product API endpoints that allow customers to retrieve forge app data from KV, SQL or Object storage (or any other support Forge storage solution).

Atlassian could provide Forge developers with “transformers”, which would allow the app vendor to add logic to the data extraction. This could be a simple IO where the transformer does not have access to any internal/external system. It would only be used to re-shape the data in a more logical and understandable way.

Proper stewardship
Whatever solution Atlassian choses, I would really like to urge Atlassian to be a more careful guardian of the Runs on Atlassian program and embrace the No Data Egress promise of this trust signal.

Atlassian can’t have her cake and eat it.

Atlassian can’t expect Atlassian Marketplace Partners to not find creative ways to work with the platform features and somehow appeal to the “spirit” of Runs on Atlassian. People will get burned by this, especially because it seems like Atlassian doesn’t always fully grasp what that spirit means.

Being a good steward of the Atlassian Ecosystem also means that Atlassian prevents setting partners up for failure. By making Runs on Atlassian requirements opaque Atlassian is harming the ecosystem.

4 Likes