Plano API

Read and change cards from your scripts and services, get events by webhooks and put your tasks in your calendar.

Access

Create a token in Settings → Integrations and send it in the Authorization header. Responses are JSON.

curl https://api.plano.team/users/me \
  -H "Authorization: Bearer <token>"

Quick start

Find a project and a column, then create a card:

# 1. list projects
curl https://api.plano.team/projects -H "Authorization: Bearer <token>"

# 2. the board: columns and cards
curl https://api.plano.team/projects/<projectId>/board -H "Authorization: Bearer <token>"

# 3. a new card in a column
curl -X POST https://api.plano.team/cards \
  -H "Authorization: Bearer <token>" -H "Content-Type: application/json" \
  -d '{"columnId": "<columnId>", "title": "Hello from the API", "priority": "HIGH", "dueDate": "2026-11-10"}'

Main endpoints

API address: https://api.plano.team. Dates are ISO 8601. These endpoints are stable; other endpoints the app uses may change.

GET/users/meYou: name, role, rights
GET/usersPeople in the workspace
GET/projectsList projects
POST/projectsCreate a project (title, optional templateId, startDate, deadline)
GET/projects/{id}/boardThe project board: columns with cards
GET/cards/search?q=Search cards by title, description or key
GET/cards/{id}A whole card: subtasks, comments, history
POST/cardsCreate a card (columnId and title are required)
PATCH/cards/{id}Change card fields
POST/cards/{id}/moveMove to a column (columnId, optional position)
DELETE/cards/{id}Delete a card (needs the delete right)
POST/cards/{id}/commentsAdd a comment
POST/cards/{id}/checklistAdd a subtask (text)
GET/labelsList labels
POST/labelsCreate a label (name, color)

Card fields for create and update: title, description, priority (LOW, MEDIUM, HIGH), startDate, dueDate, estimateHours, assigneeIds, labelIds. A comment takes text and optional mentionIds.

Webhooks

Add an address in Settings → Integrations and Plano will POST JSON to it when things happen. The address must be public and start with https://. Pick the events you need, or none to get them all.

Example request body:

{
  "event": "card.moved",
  "createdAt": "2026-11-03T09:15:00.000Z",
  "actor": { "id": "clx1…", "name": "Anna" },
  "card": {
    "id": "clx2…",
    "key": "TSK-12",
    "title": "Prepare the brief",
    "priority": "HIGH",
    "dueDate": "2026-11-10T00:00:00.000Z",
    "project": { "id": "clx3…", "title": "Website" },
    "column": { "id": "clx4…", "title": "In progress" },
    "assignees": [{ "id": "clx1…", "name": "Anna" }],
    "labels": [{ "id": "clx5…", "name": "Feature", "color": "blue" }],
    "url": "https://app.example.com/projects/clx3…?card=clx2…"
  },
  "from": "Backlog",
  "to": "In progress"
}

Headers:

import { createHmac, timingSafeEqual } from "crypto";

function isValid(rawBody, headers, secret) {
  const expected = createHmac("sha256", secret)
    .update(headers["x-plano-timestamp"] + "." + rawBody)
    .digest("hex");
  const got = headers["x-plano-signature"].replace("sha256=", "");
  return got.length === expected.length && timingSafeEqual(Buffer.from(got), Buffer.from(expected));
}

Answer with a 2xx within 8 seconds. Otherwise Plano retries twice more (after 5 and 30 seconds). The log of recent deliveries is in settings, where you can also send a test event and change the secret.

Task calendar

In your profile you can get a personal calendar link in iCal format. Add it to Google Calendar, Apple Calendar or Outlook as a subscription: it shows your unfinished cards that have a due date. The link is secret and can be replaced at any time.