Plane apps are currently in Beta. Please send any feedback to support@plane.so.

Introduction

Plane apps seamlessly integrate tools and services with Plane so you can use them without ever leaving your Workspace. Apps are conveniently available from our marketplace, helping you stay focused and productive.

Why Build a Plane App?

Stop doing manual work. Plane integrations eliminate repetitive tasks like copying updates between tools, creating work items from support tickets, and generating status reports. Instead of spending hours on administrative work, let your app handle it automatically. Connect everything you already use. Your team probably uses dozens of different tools. Plane apps create a unified workflow by connecting your favorite CRM, time tracking app, CI/CD pipelines, communication tools, and more, together into Plane. One change in Plane can trigger updates across your entire tech stack. Build exactly what you need. Unlike rigid SaaS platforms, Plane’s open core nature means you can create integrations that fit your specific workflow.

Prerequisites

  • A Plane workspace
  • Admin access to your workspace settings
  • Familiarity with OAuth 2.0 concepts (authorization code flow)
  • A backend server to handle OAuth token exchange

High-Level Workflow

  1. Register your app on Plane developer portal
  2. Implement OAuth flow
  3. Obtain and store access tokens securely
  4. Make authenticated API requests to Plane
  5. Handle token refresh

Registering Your App

To build an OAuth application with Plane:
  1. Navigate to https://app.plane.so/<workspace_slug>/settings/applications/.
  2. Click on the Build your own button.
  3. Fill out the form with the required details:
    • Redirect URIs: Provide the URIs where Plane will send the authorization code after the user consents to the app.
    • Contact Details: Add your email or other contact information.
    • Setup URL(Optional): Provide the URL that users will be redirected to when they click “Install App” from the marketplace. This URL should initiate the OAuth flow for your application.
    • Webhook URL Endpoint(Optional): Your service’s webhook endpoint. Plane will send an HTTP POST request to this endpoint upon every change to the workspace in which your app was installed.
    • Organization Details(Optional): Optionally include your contact email, privacy policy URL, terms of service URL, and any other relevant information. This helps Plane validate and approve your application should you choose to list in the marketplace.
  4. If you’re building an agent (with or without using Plane’s ADK) capable of performing operations when assigned or mentioned, enable the Is Mentionable checkbox during app creation.
  5. Once the app is created, securely store the generated Client ID and Client Secret. You will need these credentials to interact with Plane’s API during the OAuth flow and for making authenticated API requests.

Implement OAuth Flow

This step is optional. This is needed only if the app should be installed from outside Plane’s environment, the developer needs to generate the consent URL using the client ID generated during their app creation flow. If this flow needs to be triggered from Plane marketplace as well, then provide the URL in “Setup URL” field on application create screen to redirect the user from marketplace on clicking “Install App” button. Below are sample implementations:
import os
from urllib.parse import urlencode

params = {
    "client_id": os.getenv("PLANE_CLIENT_ID"),
    "response_type": "code",
    "redirect_uri": os.getenv("PLANE_REDIRECT_URI"),
    # Optional: include state if needed
}

consent_url = f"https://api.plane.so/auth/o/authorize-app/?{urlencode(params)}"
There are two types of authenticated actions your application can perform:
  1. User-authorized actions: Actions performed on behalf of a user after they grant permission to your app via OAuth.
  2. App-authorized actions: Actions that the app can perform independently within the workspace where it is installed (such as responding to webhooks or automation triggers).
For both these flows, Plane will make a GET request to the Redirect URI with parameters as mentioned in the following sections. We will describe how to configure and use each type in the following sections.

App-Authorized Actions (Client Credentials Flow)

When the app is installed, Plane will send an app_installation_id as part of the callback to the Redirect URI provided during consent URL generation. You can use this app_installation_id to request a bot token for your app. Plane will make a GET request to the Redirect URI with below parameters:
ParameterDescription
app_installation_idThe unique identifier for the app installation in the workspace

Examples

import base64
import requests

# Prepare basic auth header using client_id and client_secret
client_id = "your_client_id"
client_secret = "your_client_secret"
basic_auth = base64.b64encode(f"{client_id}:{client_secret}".encode()).decode()

# Prepare request data
payload = {
    "grant_type": "client_credentials",
    "app_installation_id": app_installation_id
}

# Make a POST request to fetch bot token
response = requests.post(
    url="https://api.plane.so/auth/o/token/",
    headers={"Authorization": f"Basic {basic_auth}",
             "Content-Type": "application/x-www-form-urlencoded"},
    data=payload
)

# Parse the response
response_data = response.json()
bot_token = response_data['access_token']
expires_in = response_data["expires_in"]

User-Authorized Actions (Authorization Code Flow)

In this flow, your app exchanges the code received as a query parameter on the callback (to your Redirect URI) for an access token and refresh token. The access token is short-lived and must be refreshed using the refresh token when it expires. Both tokens should be securely stored. Plane will make a GET request to the Redirect URI with below parameters:
ParameterDescriptionRequired
codeThe authorization code that can be exchanged for an access tokenYes
stateThe state parameter that was passed in the authorization requestNo

Examples

import requests

# Exchange authorization code for access and refresh tokens
code = "authorization_code_from_callback"
client_id = "your_client_id"
client_secret = "your_client_secret"
redirect_uri = "your_redirect_uri"

payload = {
    "grant_type": "authorization_code",
    "code": code,
    "client_id": client_id,
    "client_secret": client_secret,
    "redirect_uri": redirect_uri
}

response = requests.post(
    url="https://api.plane.so/auth/o/token/",
    headers={"Content-Type": "application/x-www-form-urlencoded"},
    data=payload
)

# Parse the response
response_data = response.json()
access_token = response_data["access_token"]
refresh_token = response_data["refresh_token"]
expires_in = response_data["expires_in"]

Fetching App Installation Details

In both user-authorized and app-authorized flows, the app_installation_id identifies the app’s installation within a specific workspace. It is recommended that developers fetch workspace details after OAuth is successfully completed. Plane provides an app-installation endpoint that works with both types of tokens.

Examples

import requests

# Set authorization header with either access token or bot token
headers = {
    "Authorization": f"Bearer {token}",
}

# Make GET request to fetch installation/workspace details
response = requests.get(
    url=f"https://api.plane.so/auth/o/app-installation/?id={app_installation_id}",
    headers=headers
)

workspace_details = response.data[0]

Sample Response

[
    {
        "id": "34b97361-8636-43dc-953e-90deedc8498f",
        "workspace_detail": {
            "name": "sandbox",
            "slug": "sandbox",
            "id": "7a2e5944-c117-4a7d-b5f4-058fe705d7d1",
            "logo_url": null
        },
        "created_at": "2025-05-16T13:50:27.865821Z",
        "updated_at": "2025-06-23T08:57:26.976742Z",
        "deleted_at": null,
        "status": "installed",
        "workspace": "7a2e5944-c117-4a7d-b5f4-058fe705d7d1",
        "application": "ab235529-388a-4f51-a55a-78272251f5f1",
        "installed_by": "63333ab1-c605-42fc-82f7-5cd86799eca1",
        "app_bot": "7286aaa7-9250-4851-a520-29c904fd7654", // app's bot user id in the workspace
        "webhook": "b1f4b7f1-51e8-4919-a84c-0b1143b51d2c"
    }
]

Obtain and store access tokens securely

Once you have obtained the access token, you can use it to make authenticated API requests to Plane. Store the access token and refresh token securely in your database.

Make authenticated API requests to Plane

For making authenticated API requests to Plane, you can use the access token obtained from the OAuth flow. API reference is available at https://docs.plane.so/api-reference. We have official SDKs for the following languages to simplify the OAuth flow and make it easier to call Plane’s API.
LanguagePackage LinkSource Code
Node.jsnpm i @makeplane/plane-node-sdkplane-node-sdk
Pythonpip install plane-sdkplane-python-sdk

Handle Token Refresh

When the access token expires, you can use the refresh token to get a new access token.

Examples

# When access token expires, use refresh token to get a new access token
refresh_payload = {
    "grant_type": "refresh_token",
    "refresh_token": refresh_token,
    "client_id": client_id,
    "client_secret": client_secret
}

refresh_response = requests.post(
    url="https://api.plane.so/auth/o/token/",
    headers={"Content-Type": "application/x-www-form-urlencoded"},
    data=refresh_payload
)

# Parse the refresh response
refresh_response_data = refresh_response.json()
access_token = refresh_response_data["access_token"]

Listing Your App on Plane Marketplace

Apps built using the OAuth flow can be listed on the Plane Marketplace: https://plane.so/marketplace/integrations To list your app, please contact the Plane team at support@plane.so.