Productboard and Jira Status Sync via Forge

In this article, you learn how to get started with Atlassian’s app development platform called Forge, create webhooks in your Forge app, send updates of issue status to Productboard, and deploy your app to production.

In this article

Getting Started

In order to get started it is recommended that you have:

  • Code editor i.e. Visual Studio Code.
  • Postman for potential debugging.
  • Admin access to your Jira Cloud & Productboard environments.
  • Basic knowledge of command line and Javascript.

Set up your Forge environment

Atlassian has created an amazing guide for getting started with Forge, go to their developer documentation to get your environment set up.

We recommend taking a look through the getting started section and the hello world app tutorial so you have an understanding of Forge. This will come in handy if troubleshooting is needed when developing your app.

Create your Forge app

After setting up your environment and looking through the Atlassian tutorials, go through these steps to set up your status sync app:

  1. In your terminal, navigate to the directory where you want to create the app.
  2. Create your app by running Forge create.
  3. Enter a name for your app. For example, PB-Jira-status-sync. A few more options will appear.
    1. Select the Triggers and Validators category.
    2. Select the product-triggers template.

Your Forge app is ready to work on, deploy, and install. We created three environments you can deploy to development, staging, and production. By the end of the tutorial, we will deploy it to production once it's working.

Open your Forge App

  1. Run cd <name of your app> to change to the app’s subdirectory
  2. Run npm install @forge/API
  3. Open the app’s directory in your code editor

Edit your Forge app

  1. Copy the code below into your manifest.yaml file. Replace everything except for the app section at the bottom of your file.


    - read:issue:jira

    - read:issue-type:jira

    - read:user:jira

    - read:project:jira

    - read:status:jira







    - key: status-sync-test-hello-world

    function: main


    - avi:jira:updated:issue


    - key: main

  2. Copy the code below into your src/index.jsx file:
    import { fetch } from '@forge/api';

    // Add Productboard API token below:
    const pbAPIToken = "Bearer <insert Bearer token here>";

    // Add Productboard Jira integration ID below:
    const pbJiraIntegrationId = '<insert Jira integration ID here>';

    // Function that runs for the webhooks we defined in manifest.yaml i.e. listening to issue updates
    export async function run(event, context) {
    // Grab the ID and status of the issue that has been updated
    const jiraIssueID =;
    const jiraIssueStatus =;
    let pbFeatureStatus = '';

    // Define Jira status to PB status mappings below:
    if (jiraIssueStatus === 'In Progress') {
    pbFeatureStatus = 'In Progress';
    } else if (jiraIssueStatus === 'Done') {
    pbFeatureStatus = 'Released';
    } else {
    pbFeatureStatus = 'Planned';

    // Build out the options to for the GET request to PB to match our Jira ID to a PB feature
    const optionsPBJiraID = {
    method: 'GET',
    headers: {
    "X-Version": "1",
    "Authorization": pbAPIToken
    redirect: 'follow'

    // Create the options for the payload to update the status of the PB feature
    const optionsPBStatusUpdate = {
    method: 'PUT',
    headers: {
    "X-Version": "1",
    "Authorization": pbAPIToken
    body: JSON.stringify({
    "data": {
    "name": null,
    "description": null,
    "archived": null,
    "status": {
    "name": pbFeatureStatus
    "timeframe": null
    redirect: 'follow'

    const pbBaseURL = '';
    let offset = 0;
    let featureResult = [];

    // Go through the results of our GET requests to match a Jira issue to a PB feature. If a result is not found, an offset of 100 is added to our request until we find a match.
    while (featureResult.length === 0) {
    try {
    const pbFeatures = await fetch(`${pbBaseURL}/jira-integrations/${pbJiraIntegrationId}/connections?pageLimit=100&pageOffset=${offset}`, optionsPBJiraID);
    const pbData = await pbFeatures.json();
    const pbDataIDs =;
    featureResult = pbDataIDs.filter(obj => {
    return obj.connection.issueId === jiraIssueID
    console.log('Page offset reached', offset);
    offset += 100;
    if ( === 0){
    } catch (err) {
    console.log('PB Jira connections GET call error:', err);

    // When a match between the Jira issue and PB feature is found, a status update is sent to the to the PB feature based on the status of the Jira issue
    if (featureResult.length === 1) {
    try {
    const pbFeatureID = await featureResult[0].featureId;
    const pbFeatureUpdate = await fetch(`${pbBaseURL}/features/${pbFeatureID}`, optionsPBStatusUpdate);
    const pbSync = await pbFeatureUpdate.json();
    console.log('Productboard feature status is now:',, '🚀');
    } catch (err) {
    console.log('PB Status PUT call error:', err);

Adding your Productboard information

Add your Productboard API token:

  1. Go into Productboard, click on your workspace name, and then Integrations.
  2. Scroll down to Public API and click on the [+] sign next to ‘Access token.’
  3. Name the token ‘Jira Status sync’ (up to you) and copy the key.
  4. Paste the API token into line 4 where it says <insert Bearer token here>.

Add your Jira integration ID:

  1. Go back to your Integrations page in Productboard.
  2. Click on your Jira integration. Copy the last section of the URL i.e
  3. Paste this ID into line 7 where it says <insert Jira integration ID here>.

Map your Productboard statuses to Jira statuses:

On line ~25, in the section under //Define Jira status to PB status mappings below, write out your status mappings and make sure the status names match up with their source. This is an if…else code block so you can set up one to one mappings between statuses or set it up to have many Jira statuses to one Productboard status:

if (jiraIssueStatus === 'In Progress' || jiraIssueStatus === 'Backlog') { pbFeatureStatus = 'In Progress';

Test your Forge app

  1. Run forge deploy
  2. Run forge install
    1. Select the Jira product
    2. Input Atlassian domain (if asked)
    3. Continue to finish the installation
  3. Run forge tunnel. Once you see “Listening to requests..” in your command line, make a status update to a Jira issue that is synced with Productboard. You should see a message in the command line saying: “Productboard feature status is now:...”

Deploy your Forge app to production

Atlassian has detailed documentation on how to deploy your app to production but the basic steps are:

  1. Navigate to the app's top-level directory in the terminal and deploy your app by running: forge deploy -e production
  2. Install your app by running: forge install -e production
    1. Select the product.
    2. Enter the URL for your Jira site (for example,
    3. Review the scopes your app is requesting then answer y.

You should now have a deployed application that syncs status between Jira and Productboard!

Was this article helpful?
1 out of 1 found this helpful



Article is closed for comments.

Articles in this section

See more
Our Support hours:
Monday to Friday from 9:00 am - 2:00 am CET. Monday to Friday from 0:00 am - 5:00 pm PST.
Productboard Academy
Become a Productboard expert with self-paced courses, quick tip videos, webinars and more.
Product Makers Community
Connect with product leaders, share and find product jobs, and learn how to approach similar challenges. Come join our Product Makers community.