Developer
Bangun dengan Planitude
REST API, webhook bertanda tangan, dan server MCP: jaga sistem Anda tetap sinkron dengan rencana, tanggapi setiap perubahan, dan biarkan asisten AI mengerjakan proyek Anda.
Kode, nama field, dan referensi teknis dalam bahasa Inggris, seperti kebanyakan dokumentasi API.
- Sinkronkan tugas dengan sistem AndaBuat proyek dan tugas dari CRM, ERP, atau skrip, temukan kembali dengan id Anda sendiri melalui
externalId, dan biarkan mesin penjadwalan menghitung tanggalnya. - Tanggapi setiap perubahanTerima permintaan HTTPS bertanda tangan saat tugas dibuat, diselesaikan, atau dipindahkan, baik perubahan berasal dari aplikasi, API, impor, maupun asisten AI.
- Hubungkan asisten AIChatGPT, Claude, Gemini, Cursor, dan VS Code membaca rencana Anda dan mengusulkan perubahan melalui server MCP, dengan izin Anda dan tidak lebih.
URL dasar: https://planitude.app
Permintaan dan respons berupa JSON melalui HTTPS. Durasi dan lag dalam menit kerja (hari kerja 8 jam adalah 480), waktu berupa ISO 8601 dalam UTC, tanggal tanpa waktu berformat YYYY-MM-DD.
curl https://planitude.app/api/auth/me \
-H "Authorization: Bearer $PLANITUDE_API_KEY"const res = await fetch("https://planitude.app/api/auth/me", {
headers: {
Authorization: `Bearer ${process.env.PLANITUDE_API_KEY}`,
},
});
if (!res.ok) throw new Error(`${res.status} ${await res.text()}`);
console.log(await res.json());import os
import requests
res = requests.get(
"https://planitude.app/api/auth/me",
headers={"Authorization": f"Bearer {os.environ['PLANITUDE_API_KEY']}"},
)
res.raise_for_status()
print(res.json()){
"user": {
"id": "b1666432-132a-4ea9-b1ae-76ea69e226c5",
"email": "[email protected]",
"name": "Anna Rossi",
"avatarUrl": null,
"locale": "en",
"emailVerified": true
}
}Mulai cepat
Dari nol hingga webhook pertama Anda dalam tiga langkah. Anda hanya memerlukan terminal.
Buat kunci API
Buka Profil → Kunci API, pilih Baca dan tulis, lalu salin kuncinya: diawali
gnt_dan hanya ditampilkan sekali. Simpan di variabel lingkungan.Lakukan panggilan pertama Anda
Daftarkan proyek yang dapat Anda lihat. Kunci bertindak sebagai Anda: proyek dan peran yang sama.
Terima webhook
Langganankan endpoint HTTPS publik ke event yang Anda butuhkan, lalu kirim event uji segera dan verifikasi tanda tangannya.
export PLANITUDE_API_KEY="gnt_…"curl https://planitude.app/api/projects \
-H "Authorization: Bearer $PLANITUDE_API_KEY"const res = await fetch("https://planitude.app/api/projects", {
headers: {
Authorization: `Bearer ${process.env.PLANITUDE_API_KEY}`,
},
});
if (!res.ok) throw new Error(`${res.status} ${await res.text()}`);
console.log(await res.json());import os
import requests
res = requests.get(
"https://planitude.app/api/projects",
headers={"Authorization": f"Bearer {os.environ['PLANITUDE_API_KEY']}"},
)
res.raise_for_status()
print(res.json()){
"projects": [
{
"id": "40be00e0-7e34-4f7a-864b-5cc986f575b8",
"workspaceId": "824650d2-d0b3-4cac-8df8-5743ae9ff65a",
"key": "WHX",
"keyLocked": false,
"name": "Warehouse expansion",
"description": null,
"startDate": "2026-10-05",
"calendarId": null,
"currency": "EUR",
"scheduleFrom": "forward",
"deadline": null,
"color": null,
"settings": {},
"archivedAt": null,
"createdBy": "b1666432-132a-4ea9-b1ae-76ea69e226c5",
"createdAt": "2026-10-01T08:30:12.418Z",
"updatedAt": "2026-10-01T08:30:12.418Z",
"workspaceName": "Acme Construction",
"role": "owner",
"taskCount": 12,
"finishAt": "2026-10-07T15:00:00.000Z"
}
]
}curl -X POST https://planitude.app/api/webhooks \
-H "Authorization: Bearer $PLANITUDE_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"url": "https://example.com/hooks/planitude",
"events": [
"task.created",
"task.completed"
],
"projectId": "40be00e0-7e34-4f7a-864b-5cc986f575b8"
}'const res = await fetch("https://planitude.app/api/webhooks", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.PLANITUDE_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
url: "https://example.com/hooks/planitude",
events: ["task.created", "task.completed"],
projectId: "40be00e0-7e34-4f7a-864b-5cc986f575b8",
}),
});
if (!res.ok) throw new Error(`${res.status} ${await res.text()}`);
console.log(await res.json());import os
import requests
res = requests.post(
"https://planitude.app/api/webhooks",
headers={"Authorization": f"Bearer {os.environ['PLANITUDE_API_KEY']}"},
json={
"url": "https://example.com/hooks/planitude",
"events": ["task.created", "task.completed"],
"projectId": "40be00e0-7e34-4f7a-864b-5cc986f575b8",
},
)
res.raise_for_status()
print(res.json()){
"id": "6f1c1d1e-2f4b-4d0a-9a77-2a3c5b1e9f10",
"type": "webhook.ping",
"apiVersion": "2026-10-01",
"createdAt": "2026-10-01T08:30:12.418Z",
"workspaceId": "824650d2-d0b3-4cac-8df8-5743ae9ff65a",
"projectId": "40be00e0-7e34-4f7a-864b-5cc986f575b8",
"actor": {
"id": "b1666432-132a-4ea9-b1ae-76ea69e226c5",
"name": "Anna Rossi"
},
"data": {
"message": "Planitude webhook test",
"webhook": {
"id": "1747ee7f-a395-4d3c-94b0-54b513d71d88",
"name": "Warehouse sync",
"events": [
"task.created",
"task.completed"
]
}
}
}Autentikasi
Autentikasi setiap permintaan dengan kunci API pribadi di header Authorization, sebagai bearer token. Kunci bersifat pribadi: bertindak sebagai Anda, dengan peran Anda pada setiap proyek, tidak pernah lebih. Anda dapat membatasi kunci pada satu workspace, memberinya masa berlaku, dan mencabutnya kapan saja; setiap panggilan dicatat di samping kunci.
Scope
| Scope | Mengizinkan |
|---|---|
| readplanitude:read | Membaca proyek, tugas, dependensi, anggota, komentar, baseline, dan webhook. |
| writeplanitude:write | Semua yang ada pada akses baca, ditambah membuat dan mengubah proyek, tugas, dependensi, komentar, baseline, dan webhook. |
Kunci dan aplikasi OAuth tidak dapat menghapus proyek atau tugas: penghapusan hanya dilakukan di aplikasi web, tempat seseorang mengonfirmasinya. Skrip yang menargetkan id yang salah tidak dapat menghapus rencana.
OAuth 2.1 untuk aplikasi pihak ketiga
Aplikasi yang bertindak atas nama orang lain menggunakan OAuth 2.1: authorization code dengan PKCE (S256), refresh token yang dirotasi pada setiap penggunaan, dynamic client registration (RFC 7591). Minta resource https://planitude.app/api dan scope planitude:read atau planitude:write.
Endpoint dipublikasikan dalam dokumen discovery standar, sehingga pustaka OAuth mengonfigurasi dirinya sendiri.
https://planitude.app/.well-known/oauth-authorization-serverhttps://planitude.app/.well-known/oauth-protected-resource
Praktik yang baik
- Simpan kunci di variabel lingkungan atau secret manager, jangan pernah di kode atau repositori. Kunci diawali
gnt_, sehingga pemindai rahasia dapat mendeteksinya. - Gunakan kunci hanya-baca jika Anda hanya membaca, dan satu kunci per integrasi: Anda dapat mencabut satu kunci tanpa menghentikan yang lain.
- Beri masa berlaku pada kunci yang digunakan skrip dan rotasikan secara berkala.
- Panggil API dari server Anda, bukan dari browser: kunci di kode front-end sama dengan kunci publik.
curl https://planitude.app/api/projects \
-H "Authorization: Bearer $PLANITUDE_API_KEY"{
"issuer": "https://planitude.app",
"authorization_endpoint": "https://planitude.app/oauth/authorize",
"token_endpoint": "https://planitude.app/api/oauth/token",
"registration_endpoint": "https://planitude.app/api/oauth/register",
"revocation_endpoint": "https://planitude.app/api/oauth/revoke",
"scopes_supported": [
"planitude:read",
"planitude:write"
],
"grant_types_supported": [
"authorization_code",
"refresh_token"
],
"code_challenge_methods_supported": [
"S256"
]
}Kesalahan
Planitude menggunakan kode status HTTP standar. Galat selalu memiliki bentuk JSON yang sama: kode error yang stabil untuk percabangan logika dan, bila perlu, details berisi alasan atau kolom yang harus diperbaiki.
| Status | Arti |
|---|---|
| 400invalid_request | Permintaan tidak valid: details.fields mencantumkan setiap kolom beserta masalahnya. |
| 401unauthorized | Kunci tidak ada, tidak valid, dicabut, atau kedaluwarsa. |
| 403forbidden | Kunci atau peran Anda tidak mengizinkannya (details.reason), misalnya penulisan dengan kunci hanya-baca, atau penghapusan. |
| 404not_found | Tidak ditemukan, atau tidak terlihat oleh Anda. |
| 409dependency_cycle | Konflik dengan rencana, misalnya dependensi yang akan membentuk siklus (dependency_cycle). |
| 429rate_limited | Terlalu banyak permintaan: tunggu sesuai jumlah detik di Retry-After. |
| 500server_error | Terjadi kesalahan di sisi kami: coba lagi dengan exponential backoff. |
Error
| Field | Tipe | Deskripsi |
|---|---|---|
| error wajib | string | Stable error code: invalid_request, unauthorized, forbidden, not_found, conflict, dependency_cycle, limit_exceeded, rate_limited, server_error, ... |
| details | object |
{
"error": "invalid_request",
"details": {
"fields": [
{
"path": "name",
"message": "Invalid input: expected string, received undefined"
},
{
"path": "durationMin",
"message": "Too small: expected number to be >=0"
}
]
}
}{
"error": "forbidden",
"details": {
"reason": "destructive"
}
}{
"error": "dependency_cycle",
"details": {
"cycles": [
{
"path": "Foundations -> Walls -> Foundations",
"taskIds": [
"4dbd104a-00cd-4035-8955-255f52ea586a",
"a22fd799-c4dc-4869-a466-0dd6e96f71ce"
],
"taskNames": [
"Foundations",
"Walls"
]
}
]
}
}Batas laju
Batas berlaku per kunci, dalam jendela geser satu menit: 240 permintaan baca dan 60 permintaan tulis. Jika melebihi batas, Anda menerima 429 rate_limited dengan header Retry-After, dalam detik.
Tunggu Retry-After sebelum mencoba lagi, sebarkan pekerjaan massal dari waktu ke waktu, dan kelompokkan banyak perubahan dalam satu change set: hingga 1.000 perubahan dalam satu permintaan dan satu kali penghitungan ulang.
HTTP/1.1 429 Too Many Requests
Retry-After: 12
Content-Type: application/json
{
"error": "rate_limited",
"details": {
"retryAfterSec": 12
}
}Paginasi dan pencarian
Daftar tugas dipaginasi dengan kursor. Kirim limit (1–500, default 100) dan, untuk halaman berikutnya, nextCursor dari respons sebelumnya sebagai cursor. Jika nextCursor bernilai null, tidak ada halaman lagi.
Filter dengan externalId (kecocokan persis dengan id Anda sendiri), q (nama mengandung), updatedSince, dan completed; urutkan dengan sort=-number (terbaru dulu) atau -updatedAt. Daftar yang lebih pendek, seperti proyek, anggota, dan dependensi, dikembalikan utuh dalam satu respons.
curl "https://planitude.app/api/projects/40be00e0-7e34-4f7a-864b-5cc986f575b8/tasks?limit=500" \
-H "Authorization: Bearer $PLANITUDE_API_KEY"
# next page: pass the nextCursor of the previous response
curl "https://planitude.app/api/projects/40be00e0-7e34-4f7a-864b-5cc986f575b8/tasks?limit=500&cursor=$NEXT_CURSOR" \
-H "Authorization: Bearer $PLANITUDE_API_KEY"const tasks = [];
let cursor = null;
do {
const url = new URL("https://planitude.app/api/projects/40be00e0-7e34-4f7a-864b-5cc986f575b8/tasks");
url.searchParams.set("limit", "500");
if (cursor) url.searchParams.set("cursor", cursor);
const res = await fetch(url, {
headers: { Authorization: `Bearer ${process.env.PLANITUDE_API_KEY}` },
});
if (!res.ok) throw new Error(`${res.status} ${await res.text()}`);
const page = await res.json();
tasks.push(...page.tasks);
cursor = page.nextCursor;
} while (cursor);
console.log(tasks.length);import os
import requests
tasks, cursor = [], None
while True:
res = requests.get(
"https://planitude.app/api/projects/40be00e0-7e34-4f7a-864b-5cc986f575b8/tasks",
headers={"Authorization": f"Bearer {os.environ['PLANITUDE_API_KEY']}"},
params={"limit": 500, **({"cursor": cursor} if cursor else {})},
)
res.raise_for_status()
page = res.json()
tasks += page["tasks"]
cursor = page["nextCursor"]
if not cursor:
break
print(len(tasks))Versi
API dan payload webhook diberi versi berdasarkan tanggal. Versi saat ini adalah 2026-10-01: ini adalah kolom apiVersion pada setiap event dan info.version pada dokumen OpenAPI.
Dalam satu versi kami hanya menambah: endpoint baru, kolom opsional baru, tipe event baru. Kolom tidak pernah dihapus atau diubah tipenya tanpa versi baru, jadi abaikan kolom yang tidak Anda kenal.
curl https://planitude.app/api/webhooks/eventsconst res = await fetch("https://planitude.app/api/webhooks/events");
if (!res.ok) throw new Error(`${res.status} ${await res.text()}`);
console.log(await res.json());import requests
res = requests.get("https://planitude.app/api/webhooks/events")
res.raise_for_status()
print(res.json()){
"apiVersion": "2026-10-01",
"events": [
"project.created",
"project.updated",
"project.deleted",
"task.created",
"task.updated",
"task.deleted",
"task.completed",
"task.dates_changed",
"dependency.created",
"dependency.deleted",
"baseline.saved",
"member.invited",
"member.joined",
"comment.created"
]
}Referensi API
Account
Who is calling, and their workspaces.
User
Atribut
| Field | Tipe | Deskripsi |
|---|---|---|
| id | string (uuid) | |
| string (email) | ||
| name | stringnullable | |
| avatarUrl | stringnullable | |
| locale | string | |
| emailVerified | boolean |
{
"id": "b1666432-132a-4ea9-b1ae-76ea69e226c5",
"email": "[email protected]",
"name": "Anna Rossi",
"avatarUrl": null,
"locale": "en",
"emailVerified": true
}Workspace
Atribut
| Field | Tipe | Deskripsi |
|---|---|---|
| id | string (uuid) | |
| name | string | |
| role | string | Salah satu dari: |
{
"id": "824650d2-d0b3-4cac-8df8-5743ae9ff65a",
"name": "Acme Construction",
"role": "owner"
}Current user (connection test)
GET/api/auth/me
Kunci dengan akses baca
Mengembalikan
200 OK The user
| Field | Tipe | Deskripsi |
|---|---|---|
| user | User |
curl https://planitude.app/api/auth/me \
-H "Authorization: Bearer $PLANITUDE_API_KEY"const res = await fetch("https://planitude.app/api/auth/me", {
headers: {
Authorization: `Bearer ${process.env.PLANITUDE_API_KEY}`,
},
});
if (!res.ok) throw new Error(`${res.status} ${await res.text()}`);
console.log(await res.json());import os
import requests
res = requests.get(
"https://planitude.app/api/auth/me",
headers={"Authorization": f"Bearer {os.environ['PLANITUDE_API_KEY']}"},
)
res.raise_for_status()
print(res.json()){
"user": {
"id": "b1666432-132a-4ea9-b1ae-76ea69e226c5",
"email": "[email protected]",
"name": "Anna Rossi",
"avatarUrl": null,
"locale": "en",
"emailVerified": true
}
}Workspaces of the user, with role
GET/api/workspaces
Kunci dengan akses baca
Mengembalikan
200 OK Workspaces
| Field | Tipe | Deskripsi |
|---|---|---|
| workspaces | array of Workspace |
curl https://planitude.app/api/workspaces \
-H "Authorization: Bearer $PLANITUDE_API_KEY"const res = await fetch("https://planitude.app/api/workspaces", {
headers: {
Authorization: `Bearer ${process.env.PLANITUDE_API_KEY}`,
},
});
if (!res.ok) throw new Error(`${res.status} ${await res.text()}`);
console.log(await res.json());import os
import requests
res = requests.get(
"https://planitude.app/api/workspaces",
headers={"Authorization": f"Bearer {os.environ['PLANITUDE_API_KEY']}"},
)
res.raise_for_status()
print(res.json()){
"workspaces": [
{
"id": "824650d2-d0b3-4cac-8df8-5743ae9ff65a",
"name": "Acme Construction",
"role": "owner"
}
]
}Referensi API
Projects
Projects, templates and baselines.
Project
A project as returned by the write endpoints and project listings.
Atribut
| Field | Tipe | Deskripsi |
|---|---|---|
| id | string (uuid) | |
| workspaceId | string (uuid) | |
| key | string | Project key, e.g. CRON (task keys are CRON-12). |
| keyLocked | boolean | |
| name | string | |
| description | stringnullable | |
| startDate | string (date) | |
| calendarId | string (uuid)nullable | |
| currency | string | |
| scheduleFrom | string | Salah satu dari: |
| deadline | string (date)nullable | |
| color | stringnullable | |
| settings | object | |
| archivedAt | string (date-time)nullable | |
| createdBy | string (uuid)nullable | |
| createdAt | string (date-time) | |
| updatedAt | string (date-time) |
{
"id": "40be00e0-7e34-4f7a-864b-5cc986f575b8",
"workspaceId": "824650d2-d0b3-4cac-8df8-5743ae9ff65a",
"key": "WHX",
"keyLocked": false,
"name": "Warehouse expansion",
"description": null,
"startDate": "2026-10-05",
"calendarId": null,
"currency": "EUR",
"scheduleFrom": "forward",
"deadline": null,
"color": null,
"settings": {},
"archivedAt": null,
"createdBy": "b1666432-132a-4ea9-b1ae-76ea69e226c5",
"createdAt": "2026-10-01T08:30:12.418Z",
"updatedAt": "2026-10-01T08:30:12.418Z"
}Template
Atribut
| Field | Tipe | Deskripsi |
|---|---|---|
| id | string | builtin:<slug> or the id of a template saved by you. |
| kind | string | Salah satu dari: |
| name | string | |
| description | stringnullable | |
| taskCount | integer | |
| durationDays | integer | Working days from start to finish. |
{
"id": "builtin:website-launch",
"kind": "builtin",
"name": "Website launch",
"description": "From discovery to go-live: design, content, development, testing and launch.",
"taskCount": 12,
"durationDays": 43
}Baseline
Atribut
| Field | Tipe | Deskripsi |
|---|---|---|
| id | string (uuid) | |
| name | string | |
| index | integernullable | Numbered MS Project baseline (1-10); null for the main baseline and the ones you name. |
| capturedAt | string (date-time) | |
| capturedBy | string (uuid)nullable | |
| taskCount | integer |
{
"id": "b5d68d05-0640-48f9-8eeb-ed7804f4a116",
"name": "Plan v1",
"index": null,
"capturedAt": "2026-10-01T08:30:12.418Z",
"capturedBy": "b1666432-132a-4ea9-b1ae-76ea69e226c5",
"taskCount": 12
}List projects
GET/api/projects
Kunci dengan akses baca
All projects visible to the user (not paginated). ?archived=1 includes archived ones.
Parameter query
| Field | Tipe | Deskripsi |
|---|---|---|
| archived | string | Salah satu dari: |
Mengembalikan
200 OK Projects
| Field | Tipe | Deskripsi |
|---|---|---|
| projects | array of Project |
curl https://planitude.app/api/projects \
-H "Authorization: Bearer $PLANITUDE_API_KEY"const res = await fetch("https://planitude.app/api/projects", {
headers: {
Authorization: `Bearer ${process.env.PLANITUDE_API_KEY}`,
},
});
if (!res.ok) throw new Error(`${res.status} ${await res.text()}`);
console.log(await res.json());import os
import requests
res = requests.get(
"https://planitude.app/api/projects",
headers={"Authorization": f"Bearer {os.environ['PLANITUDE_API_KEY']}"},
)
res.raise_for_status()
print(res.json()){
"projects": [
{
"id": "40be00e0-7e34-4f7a-864b-5cc986f575b8",
"workspaceId": "824650d2-d0b3-4cac-8df8-5743ae9ff65a",
"key": "WHX",
"keyLocked": false,
"name": "Warehouse expansion",
"description": null,
"startDate": "2026-10-05",
"calendarId": null,
"currency": "EUR",
"scheduleFrom": "forward",
"deadline": null,
"color": null,
"settings": {},
"archivedAt": null,
"createdBy": "b1666432-132a-4ea9-b1ae-76ea69e226c5",
"createdAt": "2026-10-01T08:30:12.418Z",
"updatedAt": "2026-10-01T08:30:12.418Z",
"workspaceName": "Acme Construction",
"role": "owner",
"taskCount": 12,
"finishAt": "2026-10-07T15:00:00.000Z"
}
]
}Create a project
POST/api/projects
Kunci dengan akses tulis
Isi permintaan
| Field | Tipe | Deskripsi |
|---|---|---|
| name wajib | string | |
| workspaceId | string (uuid) | Defaults to your personal workspace. |
| key | string | 2-5 letters/digits, starts with a letter. Derived from the name if omitted. |
| description | stringnullable | |
| startDate | string (date) | |
| deadline | string (date)nullable | |
| currency | string | |
| scheduleFrom | string | Salah satu dari: |
| color | stringnullable |
Mengembalikan
201 Created Created
| Field | Tipe | Deskripsi |
|---|---|---|
| project | Project |
curl -X POST https://planitude.app/api/projects \
-H "Authorization: Bearer $PLANITUDE_API_KEY" \
-H "Content-Type: application/json" \
-d '{"name":"Warehouse expansion","startDate":"2026-10-05","currency":"EUR"}'const res = await fetch("https://planitude.app/api/projects", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.PLANITUDE_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
name: "Warehouse expansion",
startDate: "2026-10-05",
currency: "EUR",
}),
});
if (!res.ok) throw new Error(`${res.status} ${await res.text()}`);
console.log(await res.json());import os
import requests
res = requests.post(
"https://planitude.app/api/projects",
headers={"Authorization": f"Bearer {os.environ['PLANITUDE_API_KEY']}"},
json={
"name": "Warehouse expansion",
"startDate": "2026-10-05",
"currency": "EUR",
},
)
res.raise_for_status()
print(res.json()){
"project": {
"id": "40be00e0-7e34-4f7a-864b-5cc986f575b8",
"workspaceId": "824650d2-d0b3-4cac-8df8-5743ae9ff65a",
"key": "WHX",
"keyLocked": false,
"name": "Warehouse expansion",
"description": null,
"startDate": "2026-10-05",
"calendarId": null,
"currency": "EUR",
"scheduleFrom": "forward",
"deadline": null,
"color": null,
"settings": {},
"archivedAt": null,
"createdBy": "b1666432-132a-4ea9-b1ae-76ea69e226c5",
"createdAt": "2026-10-01T08:30:12.418Z",
"updatedAt": "2026-10-01T08:30:12.418Z"
}
}Create a project from a template
POST/api/projects/from-template
Kunci dengan akses tulis
Isi permintaan
| Field | Tipe | Deskripsi |
|---|---|---|
| templateId wajib | string | Id from GET /api/templates. |
| startDate wajib | string (date) | |
| name | string | |
| key | string | |
| locale | string | Language of the template texts (en, it, es, fr, de, pt, nl, pl, ja, zh, sv, da, no, fi, cs, ro, uk, tr, ar, he, hi, id, vi, ko). |
| tz | string | IANA time zone of the project calendar. |
| workspaceId | string (uuid) |
Mengembalikan
201 Created Created
| Field | Tipe | Deskripsi |
|---|---|---|
| project | Project | |
| taskCount | integer | |
| conflicts | array of Conflict |
curl -X POST https://planitude.app/api/projects/from-template \
-H "Authorization: Bearer $PLANITUDE_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"templateId": "builtin:website-launch",
"startDate": "2026-10-05",
"name": "Website relaunch",
"locale": "en"
}'const res = await fetch("https://planitude.app/api/projects/from-template", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.PLANITUDE_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
templateId: "builtin:website-launch",
startDate: "2026-10-05",
name: "Website relaunch",
locale: "en",
}),
});
if (!res.ok) throw new Error(`${res.status} ${await res.text()}`);
console.log(await res.json());import os
import requests
res = requests.post(
"https://planitude.app/api/projects/from-template",
headers={"Authorization": f"Bearer {os.environ['PLANITUDE_API_KEY']}"},
json={
"templateId": "builtin:website-launch",
"startDate": "2026-10-05",
"name": "Website relaunch",
"locale": "en",
},
)
res.raise_for_status()
print(res.json()){
"project": {
"id": "40be00e0-7e34-4f7a-864b-5cc986f575b8",
"workspaceId": "824650d2-d0b3-4cac-8df8-5743ae9ff65a",
"key": "WHX",
"keyLocked": false,
"name": "Warehouse expansion",
"description": null,
"startDate": "2026-10-05",
"calendarId": null,
"currency": "EUR",
"scheduleFrom": "forward",
"deadline": null,
"color": null,
"settings": {},
"archivedAt": null,
"createdBy": "b1666432-132a-4ea9-b1ae-76ea69e226c5",
"createdAt": "2026-10-01T08:30:12.418Z",
"updatedAt": "2026-10-01T08:30:12.418Z"
},
"taskCount": 12,
"conflicts": []
}List project templates
GET/api/templates
Kunci dengan akses baca
Parameter query
| Field | Tipe | Deskripsi |
|---|---|---|
| locale | string |
Mengembalikan
200 OK Templates
| Field | Tipe | Deskripsi |
|---|---|---|
| templates | array of Template |
curl https://planitude.app/api/templates \
-H "Authorization: Bearer $PLANITUDE_API_KEY"const res = await fetch("https://planitude.app/api/templates", {
headers: {
Authorization: `Bearer ${process.env.PLANITUDE_API_KEY}`,
},
});
if (!res.ok) throw new Error(`${res.status} ${await res.text()}`);
console.log(await res.json());import os
import requests
res = requests.get(
"https://planitude.app/api/templates",
headers={"Authorization": f"Bearer {os.environ['PLANITUDE_API_KEY']}"},
)
res.raise_for_status()
print(res.json()){
"templates": [
{
"id": "builtin:website-launch",
"kind": "builtin",
"name": "Website launch",
"description": "From discovery to go-live: design, content, development, testing and launch.",
"taskCount": 12,
"durationDays": 43
}
]
}Full project (tasks tree, dependencies, resources, members, baselines)
GET/api/projects/{projectId}
Kunci dengan akses baca
Parameter path
| Field | Tipe | Deskripsi |
|---|---|---|
| projectId wajib | string (uuid) | Project id. |
Mengembalikan
200 OK Project
| Field | Tipe | Deskripsi |
|---|---|---|
| project | Project | |
| tasks | array of Task | |
| dependencies | array of Dependency |
curl https://planitude.app/api/projects/40be00e0-7e34-4f7a-864b-5cc986f575b8 \
-H "Authorization: Bearer $PLANITUDE_API_KEY"const res = await fetch("https://planitude.app/api/projects/40be00e0-7e34-4f7a-864b-5cc986f575b8", {
headers: {
Authorization: `Bearer ${process.env.PLANITUDE_API_KEY}`,
},
});
if (!res.ok) throw new Error(`${res.status} ${await res.text()}`);
console.log(await res.json());import os
import requests
res = requests.get(
"https://planitude.app/api/projects/40be00e0-7e34-4f7a-864b-5cc986f575b8",
headers={"Authorization": f"Bearer {os.environ['PLANITUDE_API_KEY']}"},
)
res.raise_for_status()
print(res.json()){
"project": {
"id": "40be00e0-7e34-4f7a-864b-5cc986f575b8",
"workspaceId": "824650d2-d0b3-4cac-8df8-5743ae9ff65a",
"key": "WHX",
"keyLocked": false,
"name": "Warehouse expansion",
"description": null,
"startDate": "2026-10-05",
"calendarId": null,
"currency": "EUR",
"scheduleFrom": "forward",
"deadline": null,
"color": null,
"settings": {},
"archivedAt": null,
"createdBy": "b1666432-132a-4ea9-b1ae-76ea69e226c5",
"createdAt": "2026-10-01T08:30:12.418Z",
"updatedAt": "2026-10-01T08:30:12.418Z"
},
"tasks": [
{
"id": "4dbd104a-00cd-4035-8955-255f52ea586a",
"number": 1,
"key": "WHX-1",
"parentId": null,
"sortKey": "i",
"name": "Foundations",
"type": "task",
"durationMin": 1440,
"workMin": 0,
"progressPct": 0,
"constraintKind": "asap",
"constraintDate": null,
"deadline": null,
"calendarId": null,
"costFixed": 0,
"notes": null,
"color": null,
"wbs": null,
"externalId": "crm-4711",
"startAt": "2026-10-05T06:00:00.000Z",
"finishAt": "2026-10-07T15:00:00.000Z",
"isCritical": true,
"totalFloatMin": 0,
"earlyStartAt": "2026-10-05T06:00:00.000Z",
"lateFinishAt": "2026-10-07T15:00:00.000Z",
"actualStartAt": null,
"actualFinishAt": null,
"actualDurationMin": null,
"remainingDurationMin": null,
"manuallyScheduled": false,
"levelingDelayMin": 0,
"taskType": "fixed_units",
"effortDriven": false,
"durationOptimisticMin": null,
"durationPessimisticMin": null
}
],
"dependencies": [
{
"id": "9ba5faf8-923d-4ecc-86f0-f245c5d179db",
"predecessorId": "4dbd104a-00cd-4035-8955-255f52ea586a",
"successorId": "a22fd799-c4dc-4869-a466-0dd6e96f71ce",
"type": "FS",
"lagMin": 0
}
]
}Update a project
PATCH/api/projects/{projectId}
Kunci dengan akses tulis
Parameter path
| Field | Tipe | Deskripsi |
|---|---|---|
| projectId wajib | string (uuid) | Project id. |
Isi permintaan
| Field | Tipe | Deskripsi |
|---|---|---|
| name | string | |
| description | stringnullable | |
| startDate | string (date) | |
| deadline | string (date)nullable | |
| currency | string | |
| scheduleFrom | string | Salah satu dari: |
| color | stringnullable | |
| archived | boolean |
Mengembalikan
200 OK Updated
| Field | Tipe | Deskripsi |
|---|---|---|
| project | Project | |
| conflicts | array of Conflict | |
| rescheduled | boolean | The schedule was recalculated (start date, calendar or direction changed). |
curl -X PATCH https://planitude.app/api/projects/40be00e0-7e34-4f7a-864b-5cc986f575b8 \
-H "Authorization: Bearer $PLANITUDE_API_KEY" \
-H "Content-Type: application/json" \
-d '{"deadline":"2026-12-18"}'const res = await fetch("https://planitude.app/api/projects/40be00e0-7e34-4f7a-864b-5cc986f575b8", {
method: "PATCH",
headers: {
Authorization: `Bearer ${process.env.PLANITUDE_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
deadline: "2026-12-18",
}),
});
if (!res.ok) throw new Error(`${res.status} ${await res.text()}`);
console.log(await res.json());import os
import requests
res = requests.patch(
"https://planitude.app/api/projects/40be00e0-7e34-4f7a-864b-5cc986f575b8",
headers={"Authorization": f"Bearer {os.environ['PLANITUDE_API_KEY']}"},
json={
"deadline": "2026-12-18",
},
)
res.raise_for_status()
print(res.json()){
"project": {
"id": "40be00e0-7e34-4f7a-864b-5cc986f575b8",
"workspaceId": "824650d2-d0b3-4cac-8df8-5743ae9ff65a",
"key": "WHX",
"keyLocked": false,
"name": "Warehouse expansion",
"description": null,
"startDate": "2026-10-05",
"calendarId": null,
"currency": "EUR",
"scheduleFrom": "forward",
"deadline": null,
"color": null,
"settings": {},
"archivedAt": null,
"createdBy": "b1666432-132a-4ea9-b1ae-76ea69e226c5",
"createdAt": "2026-10-01T08:30:12.418Z",
"updatedAt": "2026-10-01T08:30:12.418Z"
},
"conflicts": [],
"rescheduled": false
}List baselines
GET/api/projects/{projectId}/baseline
Kunci dengan akses baca
Parameter path
| Field | Tipe | Deskripsi |
|---|---|---|
| projectId wajib | string (uuid) | Project id. |
Mengembalikan
200 OK Baselines
| Field | Tipe | Deskripsi |
|---|---|---|
| baselines | array of Baseline |
curl https://planitude.app/api/projects/40be00e0-7e34-4f7a-864b-5cc986f575b8/baseline \
-H "Authorization: Bearer $PLANITUDE_API_KEY"const res = await fetch("https://planitude.app/api/projects/40be00e0-7e34-4f7a-864b-5cc986f575b8/baseline", {
headers: {
Authorization: `Bearer ${process.env.PLANITUDE_API_KEY}`,
},
});
if (!res.ok) throw new Error(`${res.status} ${await res.text()}`);
console.log(await res.json());import os
import requests
res = requests.get(
"https://planitude.app/api/projects/40be00e0-7e34-4f7a-864b-5cc986f575b8/baseline",
headers={"Authorization": f"Bearer {os.environ['PLANITUDE_API_KEY']}"},
)
res.raise_for_status()
print(res.json()){
"baselines": [
{
"id": "b5d68d05-0640-48f9-8eeb-ed7804f4a116",
"name": "Plan v1",
"index": null,
"capturedAt": "2026-10-01T08:30:12.418Z",
"capturedBy": "b1666432-132a-4ea9-b1ae-76ea69e226c5",
"taskCount": 12
}
]
}Save a baseline
POST/api/projects/{projectId}/baseline
Kunci dengan akses tulis
Parameter path
| Field | Tipe | Deskripsi |
|---|---|---|
| projectId wajib | string (uuid) | Project id. |
Isi permintaan
| Field | Tipe | Deskripsi |
|---|---|---|
| name | string |
Mengembalikan
201 Created Saved
| Field | Tipe | Deskripsi |
|---|---|---|
| baseline | Baseline |
curl -X POST https://planitude.app/api/projects/40be00e0-7e34-4f7a-864b-5cc986f575b8/baseline \
-H "Authorization: Bearer $PLANITUDE_API_KEY" \
-H "Content-Type: application/json" \
-d '{"name":"Plan v1"}'const res = await fetch("https://planitude.app/api/projects/40be00e0-7e34-4f7a-864b-5cc986f575b8/baseline", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.PLANITUDE_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
name: "Plan v1",
}),
});
if (!res.ok) throw new Error(`${res.status} ${await res.text()}`);
console.log(await res.json());import os
import requests
res = requests.post(
"https://planitude.app/api/projects/40be00e0-7e34-4f7a-864b-5cc986f575b8/baseline",
headers={"Authorization": f"Bearer {os.environ['PLANITUDE_API_KEY']}"},
json={
"name": "Plan v1",
},
)
res.raise_for_status()
print(res.json()){
"baseline": {
"id": "b5d68d05-0640-48f9-8eeb-ed7804f4a116",
"name": "Plan v1",
"index": null,
"capturedAt": "2026-10-01T08:30:12.418Z",
"capturedBy": "b1666432-132a-4ea9-b1ae-76ea69e226c5",
"taskCount": 12
}
}Referensi API
Tasks
Tasks, search by external id, comments.
Task
Task representation of GET /tasks and webhook payloads: the stored task (without sortKey) plus project, assignees and link.
Atribut
| Field | Tipe | Deskripsi |
|---|---|---|
| id | string (uuid) | |
| number | integer | Sequential number in the project, never reused. |
| key | string | Human key, e.g. CRON-12. |
| parentId | string (uuid)nullable | |
| name | string | |
| type | string | Salah satu dari: |
| durationMin | integer | Duration in working minutes (8h day = 480). |
| workMin | integer | |
| progressPct | number | |
| constraintKind | string | Salah satu dari: |
| constraintDate | string (date-time)nullable | |
| deadline | string (date-time)nullable | |
| calendarId | string (uuid)nullable | |
| costFixed | number | |
| notes | stringnullable | |
| color | stringnullable | |
| wbs | stringnullable | |
| externalId | stringnullable | Your identifier for this task in another system. Searchable with GET /tasks?externalId=. |
| startAt | string (date-time)nullable | Computed start. |
| finishAt | string (date-time)nullable | Computed finish. |
| isCritical | boolean | On the critical path. |
| totalFloatMin | integernullable | Total float (slack) in working minutes. |
| earlyStartAt | string (date-time)nullable | |
| lateFinishAt | string (date-time)nullable | |
| actualStartAt | string (date-time)nullable | |
| actualFinishAt | string (date-time)nullable | |
| actualDurationMin | integernullable | |
| remainingDurationMin | integernullable | |
| manuallyScheduled | boolean | |
| levelingDelayMin | integer | |
| taskType | string | Salah satu dari: |
| effortDriven | boolean | |
| durationOptimisticMin | integernullable | |
| durationPessimisticMin | integernullable | |
| projectId | string (uuid) | |
| completed | boolean | progressPct = 100. |
| assignees | array of Assignee | |
| url | string (uri) | Page of the task in the web app. |
{
"id": "4dbd104a-00cd-4035-8955-255f52ea586a",
"number": 1,
"key": "WHX-1",
"parentId": null,
"name": "Foundations",
"type": "task",
"durationMin": 1440,
"workMin": 0,
"progressPct": 0,
"constraintKind": "asap",
"constraintDate": null,
"deadline": null,
"calendarId": null,
"costFixed": 0,
"notes": null,
"color": null,
"wbs": null,
"externalId": "crm-4711",
"startAt": "2026-10-05T06:00:00.000Z",
"finishAt": "2026-10-07T15:00:00.000Z",
"isCritical": true,
"totalFloatMin": 0,
"earlyStartAt": "2026-10-05T06:00:00.000Z",
"lateFinishAt": "2026-10-07T15:00:00.000Z",
"actualStartAt": null,
"actualFinishAt": null,
"actualDurationMin": null,
"remainingDurationMin": null,
"manuallyScheduled": false,
"levelingDelayMin": 0,
"taskType": "fixed_units",
"effortDriven": false,
"durationOptimisticMin": null,
"durationPessimisticMin": null,
"projectId": "40be00e0-7e34-4f7a-864b-5cc986f575b8",
"completed": false,
"assignees": [
{
"resourceId": "0c6a8f52-3d7e-4b19-9a4e-6f1d2c8b7e30",
"userId": "b1666432-132a-4ea9-b1ae-76ea69e226c5",
"name": "Anna Rossi",
"unitsPct": 100
}
],
"url": "https://planitude.app/app/t/WHX-1"
}WriteResult
Atribut
| Field | Tipe | Deskripsi | |||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| tasks | array of Task | Created/updated tasks plus the ones the recalculation moved. | |||||||||||||||
| deletedTaskIds | array of string | ||||||||||||||||
| dependencies | array of Dependency | ||||||||||||||||
| deletedDependencyIds | array of string | ||||||||||||||||
| conflicts | array of Conflict | ||||||||||||||||
| projectStartAt | string (date-time) | ||||||||||||||||
| projectFinishAt | string (date-time) | ||||||||||||||||
| stats | object | Tampilkan field stats
|
{
"tasks": [
{
"id": "4dbd104a-00cd-4035-8955-255f52ea586a",
"number": 1,
"key": "WHX-1",
"parentId": null,
"sortKey": "i",
"name": "Foundations",
"type": "task",
"durationMin": 1440,
"workMin": 0,
"progressPct": 0,
"constraintKind": "asap",
"constraintDate": null,
"deadline": null,
"calendarId": null,
"costFixed": 0,
"notes": null,
"color": null,
"wbs": null,
"externalId": "crm-4711",
"startAt": "2026-10-05T06:00:00.000Z",
"finishAt": "2026-10-07T15:00:00.000Z",
"isCritical": true,
"totalFloatMin": 0,
"earlyStartAt": "2026-10-05T06:00:00.000Z",
"lateFinishAt": "2026-10-07T15:00:00.000Z",
"actualStartAt": null,
"actualFinishAt": null,
"actualDurationMin": null,
"remainingDurationMin": null,
"manuallyScheduled": false,
"levelingDelayMin": 0,
"taskType": "fixed_units",
"effortDriven": false,
"durationOptimisticMin": null,
"durationPessimisticMin": null
}
],
"deletedTaskIds": [],
"dependencies": [
{
"id": "9ba5faf8-923d-4ecc-86f0-f245c5d179db",
"predecessorId": "4dbd104a-00cd-4035-8955-255f52ea586a",
"successorId": "a22fd799-c4dc-4869-a466-0dd6e96f71ce",
"type": "FS",
"lagMin": 0
}
],
"deletedDependencyIds": [],
"conflicts": [],
"projectStartAt": "2026-10-05T06:00:00.000Z",
"projectFinishAt": "2026-10-07T15:00:00.000Z",
"stats": {
"taskCount": 12,
"recomputedCount": 3,
"savedCount": 2,
"durationMs": 39
}
}Comment
Atribut
| Field | Tipe | Deskripsi |
|---|---|---|
| id | string (uuid) | |
| taskId | string (uuid) | |
| userId | string (uuid) | |
| authorName | string | |
| authorAvatarUrl | stringnullable | |
| body | string | |
| mentions | array of string | |
| createdAt | string (date-time) | |
| editedAt | string (date-time)nullable |
{
"id": "0fc2dec5-a409-47c9-9c6e-0663e8f8bcf3",
"taskId": "4dbd104a-00cd-4035-8955-255f52ea586a",
"userId": "b1666432-132a-4ea9-b1ae-76ea69e226c5",
"authorName": "Anna Rossi",
"authorAvatarUrl": null,
"body": "Concrete delivered, we can start the walls.",
"mentions": [],
"createdAt": "2026-10-01T08:30:12.418Z",
"editedAt": null
}List or search tasks (paginated)
GET/api/projects/{projectId}/tasks
Kunci dengan akses baca
Parameter path
| Field | Tipe | Deskripsi |
|---|---|---|
| projectId wajib | string (uuid) | Project id. |
Parameter query
| Field | Tipe | Deskripsi |
|---|---|---|
| limit | integer | 1-500. Default: |
| cursor | string | nextCursor of the previous page. |
| sort | string | -number = newest first (polling triggers). -updatedAt returns the first page only.Salah satu dari: Default: |
| externalId | string | Exact match on externalId. |
| q | string | Name contains (case-insensitive). |
| updatedSince | string (date-time) | |
| completed | string | Salah satu dari: |
Mengembalikan
200 OK A page of tasks
| Field | Tipe | Deskripsi |
|---|---|---|
| tasks | array of Task | |
| nextCursor | stringnullable |
curl "https://planitude.app/api/projects/40be00e0-7e34-4f7a-864b-5cc986f575b8/tasks?externalId=crm-4711" \
-H "Authorization: Bearer $PLANITUDE_API_KEY"const res = await fetch("https://planitude.app/api/projects/40be00e0-7e34-4f7a-864b-5cc986f575b8/tasks?externalId=crm-4711", {
headers: {
Authorization: `Bearer ${process.env.PLANITUDE_API_KEY}`,
},
});
if (!res.ok) throw new Error(`${res.status} ${await res.text()}`);
console.log(await res.json());import os
import requests
res = requests.get(
"https://planitude.app/api/projects/40be00e0-7e34-4f7a-864b-5cc986f575b8/tasks",
headers={"Authorization": f"Bearer {os.environ['PLANITUDE_API_KEY']}"},
params={
"externalId": "crm-4711",
},
)
res.raise_for_status()
print(res.json()){
"tasks": [
{
"id": "4dbd104a-00cd-4035-8955-255f52ea586a",
"number": 1,
"key": "WHX-1",
"parentId": null,
"name": "Foundations",
"type": "task",
"durationMin": 1440,
"workMin": 0,
"progressPct": 0,
"constraintKind": "asap",
"constraintDate": null,
"deadline": null,
"calendarId": null,
"costFixed": 0,
"notes": null,
"color": null,
"wbs": null,
"externalId": "crm-4711",
"startAt": "2026-10-05T06:00:00.000Z",
"finishAt": "2026-10-07T15:00:00.000Z",
"isCritical": true,
"totalFloatMin": 0,
"earlyStartAt": "2026-10-05T06:00:00.000Z",
"lateFinishAt": "2026-10-07T15:00:00.000Z",
"actualStartAt": null,
"actualFinishAt": null,
"actualDurationMin": null,
"remainingDurationMin": null,
"manuallyScheduled": false,
"levelingDelayMin": 0,
"taskType": "fixed_units",
"effortDriven": false,
"durationOptimisticMin": null,
"durationPessimisticMin": null,
"projectId": "40be00e0-7e34-4f7a-864b-5cc986f575b8",
"completed": false,
"assignees": [
{
"resourceId": "0c6a8f52-3d7e-4b19-9a4e-6f1d2c8b7e30",
"userId": "b1666432-132a-4ea9-b1ae-76ea69e226c5",
"name": "Anna Rossi",
"unitsPct": 100
}
],
"url": "https://planitude.app/app/t/WHX-1"
}
],
"nextCursor": null
}Create a task, or apply a change set
POST/api/projects/{projectId}/tasks
Kunci dengan akses tulis
Send a TaskCreate to create one task (201), or a ChangeSet to apply several changes in one transaction (200). Dates are recalculated by the scheduling engine.
Parameter path
| Field | Tipe | Deskripsi |
|---|---|---|
| projectId wajib | string (uuid) | Project id. |
Isi permintaan
TaskCreate
| Field | Tipe | Deskripsi |
|---|---|---|
| name wajib | string | |
| parentId | string (uuid)nullable | Parent (summary) task; null = top level. |
| afterTaskId | string (uuid)nullable | Insert after this sibling. |
| beforeTaskId | string (uuid)nullable | Insert before this sibling. |
| type | string | Salah satu dari: |
| durationMin | integer | Duration in working minutes (8h day = 480). |
| workMin | integer | |
| progressPct | number | |
| constraintKind | string | Salah satu dari: |
| constraintDate | string (date-time)nullable | |
| deadline | string (date-time)nullable | |
| calendarId | string (uuid)nullable | |
| costFixed | number | |
| notes | stringnullable | |
| color | stringnullable | |
| wbs | stringnullable | |
| externalId | stringnullable | Your identifier for this task in another system. Searchable with GET /tasks?externalId=. |
atau ChangeSet
| Field | Tipe | Deskripsi |
|---|---|---|
| createTasks | array of TaskCreate | |
| updateTasks | array of any | |
| createDependencies | array of DependencyCreate | |
| deleteDependencyIds | array of string | |
| fullReschedule | boolean |
Mengembalikan
201 Created Task created
| Field | Tipe | Deskripsi | |||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| tasks | array of Task | Created/updated tasks plus the ones the recalculation moved. | |||||||||||||||
| deletedTaskIds | array of string | ||||||||||||||||
| dependencies | array of Dependency | ||||||||||||||||
| deletedDependencyIds | array of string | ||||||||||||||||
| conflicts | array of Conflict | ||||||||||||||||
| projectStartAt | string (date-time) | ||||||||||||||||
| projectFinishAt | string (date-time) | ||||||||||||||||
| stats | object | Tampilkan field stats
|
curl -X POST https://planitude.app/api/projects/40be00e0-7e34-4f7a-864b-5cc986f575b8/tasks \
-H "Authorization: Bearer $PLANITUDE_API_KEY" \
-H "Content-Type: application/json" \
-d '{"name":"Foundations","durationMin":1440,"externalId":"crm-4711"}'const res = await fetch("https://planitude.app/api/projects/40be00e0-7e34-4f7a-864b-5cc986f575b8/tasks", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.PLANITUDE_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
name: "Foundations",
durationMin: 1440,
externalId: "crm-4711",
}),
});
if (!res.ok) throw new Error(`${res.status} ${await res.text()}`);
console.log(await res.json());import os
import requests
res = requests.post(
"https://planitude.app/api/projects/40be00e0-7e34-4f7a-864b-5cc986f575b8/tasks",
headers={"Authorization": f"Bearer {os.environ['PLANITUDE_API_KEY']}"},
json={
"name": "Foundations",
"durationMin": 1440,
"externalId": "crm-4711",
},
)
res.raise_for_status()
print(res.json()){
"tasks": [
{
"id": "4dbd104a-00cd-4035-8955-255f52ea586a",
"number": 1,
"key": "WHX-1",
"parentId": null,
"sortKey": "i",
"name": "Foundations",
"type": "task",
"durationMin": 1440,
"workMin": 0,
"progressPct": 0,
"constraintKind": "asap",
"constraintDate": null,
"deadline": null,
"calendarId": null,
"costFixed": 0,
"notes": null,
"color": null,
"wbs": null,
"externalId": "crm-4711",
"startAt": "2026-10-05T06:00:00.000Z",
"finishAt": "2026-10-07T15:00:00.000Z",
"isCritical": true,
"totalFloatMin": 0,
"earlyStartAt": "2026-10-05T06:00:00.000Z",
"lateFinishAt": "2026-10-07T15:00:00.000Z",
"actualStartAt": null,
"actualFinishAt": null,
"actualDurationMin": null,
"remainingDurationMin": null,
"manuallyScheduled": false,
"levelingDelayMin": 0,
"taskType": "fixed_units",
"effortDriven": false,
"durationOptimisticMin": null,
"durationPessimisticMin": null
}
],
"deletedTaskIds": [],
"dependencies": [
{
"id": "9ba5faf8-923d-4ecc-86f0-f245c5d179db",
"predecessorId": "4dbd104a-00cd-4035-8955-255f52ea586a",
"successorId": "a22fd799-c4dc-4869-a466-0dd6e96f71ce",
"type": "FS",
"lagMin": 0
}
],
"deletedDependencyIds": [],
"conflicts": [],
"projectStartAt": "2026-10-05T06:00:00.000Z",
"projectFinishAt": "2026-10-07T15:00:00.000Z",
"stats": {
"taskCount": 12,
"recomputedCount": 3,
"savedCount": 2,
"durationMs": 39
}
}Get a task
GET/api/projects/{projectId}/tasks/{taskId}
Kunci dengan akses baca
Parameter path
| Field | Tipe | Deskripsi |
|---|---|---|
| projectId wajib | string (uuid) | Project id. |
| taskId wajib | string (uuid) | Task id. |
Mengembalikan
200 OK The task
| Field | Tipe | Deskripsi |
|---|---|---|
| task | Task |
curl https://planitude.app/api/projects/40be00e0-7e34-4f7a-864b-5cc986f575b8/tasks/4dbd104a-00cd-4035-8955-255f52ea586a \
-H "Authorization: Bearer $PLANITUDE_API_KEY"const res = await fetch("https://planitude.app/api/projects/40be00e0-7e34-4f7a-864b-5cc986f575b8/tasks/4dbd104a-00cd-4035-8955-255f52ea586a", {
headers: {
Authorization: `Bearer ${process.env.PLANITUDE_API_KEY}`,
},
});
if (!res.ok) throw new Error(`${res.status} ${await res.text()}`);
console.log(await res.json());import os
import requests
res = requests.get(
"https://planitude.app/api/projects/40be00e0-7e34-4f7a-864b-5cc986f575b8/tasks/4dbd104a-00cd-4035-8955-255f52ea586a",
headers={"Authorization": f"Bearer {os.environ['PLANITUDE_API_KEY']}"},
)
res.raise_for_status()
print(res.json()){
"task": {
"id": "4dbd104a-00cd-4035-8955-255f52ea586a",
"number": 1,
"key": "WHX-1",
"parentId": null,
"name": "Foundations",
"type": "task",
"durationMin": 1440,
"workMin": 0,
"progressPct": 0,
"constraintKind": "asap",
"constraintDate": null,
"deadline": null,
"calendarId": null,
"costFixed": 0,
"notes": null,
"color": null,
"wbs": null,
"externalId": "crm-4711",
"startAt": "2026-10-05T06:00:00.000Z",
"finishAt": "2026-10-07T15:00:00.000Z",
"isCritical": true,
"totalFloatMin": 0,
"earlyStartAt": "2026-10-05T06:00:00.000Z",
"lateFinishAt": "2026-10-07T15:00:00.000Z",
"actualStartAt": null,
"actualFinishAt": null,
"actualDurationMin": null,
"remainingDurationMin": null,
"manuallyScheduled": false,
"levelingDelayMin": 0,
"taskType": "fixed_units",
"effortDriven": false,
"durationOptimisticMin": null,
"durationPessimisticMin": null,
"projectId": "40be00e0-7e34-4f7a-864b-5cc986f575b8",
"completed": false,
"assignees": [
{
"resourceId": "0c6a8f52-3d7e-4b19-9a4e-6f1d2c8b7e30",
"userId": "b1666432-132a-4ea9-b1ae-76ea69e226c5",
"name": "Anna Rossi",
"unitsPct": 100
}
],
"url": "https://planitude.app/app/t/WHX-1"
}
}Update a task
PATCH/api/projects/{projectId}/tasks/{taskId}
Kunci dengan akses tulis
Only the fields you send change; null clears a field.
Parameter path
| Field | Tipe | Deskripsi |
|---|---|---|
| projectId wajib | string (uuid) | Project id. |
| taskId wajib | string (uuid) | Task id. |
Isi permintaan
| Field | Tipe | Deskripsi | ||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| name | string | |||||||||||||
| type | string | Salah satu dari: | ||||||||||||
| durationMin | integer | Duration in working minutes (8h day = 480). | ||||||||||||
| workMin | integer | |||||||||||||
| progressPct | number | |||||||||||||
| constraintKind | string | Salah satu dari: | ||||||||||||
| constraintDate | string (date-time)nullable | |||||||||||||
| deadline | string (date-time)nullable | |||||||||||||
| calendarId | string (uuid)nullable | |||||||||||||
| costFixed | number | |||||||||||||
| notes | stringnullable | |||||||||||||
| color | stringnullable | |||||||||||||
| wbs | stringnullable | |||||||||||||
| externalId | stringnullable | Your identifier for this task in another system. Searchable with GET /tasks?externalId=. | ||||||||||||
| placement | object | Tampilkan field placement
|
Mengembalikan
200 OK Updated
| Field | Tipe | Deskripsi | |||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| tasks | array of Task | Created/updated tasks plus the ones the recalculation moved. | |||||||||||||||
| deletedTaskIds | array of string | ||||||||||||||||
| dependencies | array of Dependency | ||||||||||||||||
| deletedDependencyIds | array of string | ||||||||||||||||
| conflicts | array of Conflict | ||||||||||||||||
| projectStartAt | string (date-time) | ||||||||||||||||
| projectFinishAt | string (date-time) | ||||||||||||||||
| stats | object | Tampilkan field stats
|
curl -X PATCH https://planitude.app/api/projects/40be00e0-7e34-4f7a-864b-5cc986f575b8/tasks/4dbd104a-00cd-4035-8955-255f52ea586a \
-H "Authorization: Bearer $PLANITUDE_API_KEY" \
-H "Content-Type: application/json" \
-d '{"progressPct":100}'const res = await fetch("https://planitude.app/api/projects/40be00e0-7e34-4f7a-864b-5cc986f575b8/tasks/4dbd104a-00cd-4035-8955-255f52ea586a", {
method: "PATCH",
headers: {
Authorization: `Bearer ${process.env.PLANITUDE_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
progressPct: 100,
}),
});
if (!res.ok) throw new Error(`${res.status} ${await res.text()}`);
console.log(await res.json());import os
import requests
res = requests.patch(
"https://planitude.app/api/projects/40be00e0-7e34-4f7a-864b-5cc986f575b8/tasks/4dbd104a-00cd-4035-8955-255f52ea586a",
headers={"Authorization": f"Bearer {os.environ['PLANITUDE_API_KEY']}"},
json={
"progressPct": 100,
},
)
res.raise_for_status()
print(res.json()){
"tasks": [
{
"id": "4dbd104a-00cd-4035-8955-255f52ea586a",
"number": 1,
"key": "WHX-1",
"parentId": null,
"sortKey": "i",
"name": "Foundations",
"type": "task",
"durationMin": 1440,
"workMin": 0,
"progressPct": 0,
"constraintKind": "asap",
"constraintDate": null,
"deadline": null,
"calendarId": null,
"costFixed": 0,
"notes": null,
"color": null,
"wbs": null,
"externalId": "crm-4711",
"startAt": "2026-10-05T06:00:00.000Z",
"finishAt": "2026-10-07T15:00:00.000Z",
"isCritical": true,
"totalFloatMin": 0,
"earlyStartAt": "2026-10-05T06:00:00.000Z",
"lateFinishAt": "2026-10-07T15:00:00.000Z",
"actualStartAt": null,
"actualFinishAt": null,
"actualDurationMin": null,
"remainingDurationMin": null,
"manuallyScheduled": false,
"levelingDelayMin": 0,
"taskType": "fixed_units",
"effortDriven": false,
"durationOptimisticMin": null,
"durationPessimisticMin": null
}
],
"deletedTaskIds": [],
"dependencies": [
{
"id": "9ba5faf8-923d-4ecc-86f0-f245c5d179db",
"predecessorId": "4dbd104a-00cd-4035-8955-255f52ea586a",
"successorId": "a22fd799-c4dc-4869-a466-0dd6e96f71ce",
"type": "FS",
"lagMin": 0
}
],
"deletedDependencyIds": [],
"conflicts": [],
"projectStartAt": "2026-10-05T06:00:00.000Z",
"projectFinishAt": "2026-10-07T15:00:00.000Z",
"stats": {
"taskCount": 12,
"recomputedCount": 3,
"savedCount": 2,
"durationMs": 39
}
}Comments of a task
GET/api/projects/{projectId}/tasks/{taskId}/comments
Kunci dengan akses baca
Parameter path
| Field | Tipe | Deskripsi |
|---|---|---|
| projectId wajib | string (uuid) | Project id. |
| taskId wajib | string (uuid) | Task id. |
Mengembalikan
200 OK Comments
| Field | Tipe | Deskripsi |
|---|---|---|
| comments | array of Comment |
curl https://planitude.app/api/projects/40be00e0-7e34-4f7a-864b-5cc986f575b8/tasks/4dbd104a-00cd-4035-8955-255f52ea586a/comments \
-H "Authorization: Bearer $PLANITUDE_API_KEY"const res = await fetch("https://planitude.app/api/projects/40be00e0-7e34-4f7a-864b-5cc986f575b8/tasks/4dbd104a-00cd-4035-8955-255f52ea586a/comments", {
headers: {
Authorization: `Bearer ${process.env.PLANITUDE_API_KEY}`,
},
});
if (!res.ok) throw new Error(`${res.status} ${await res.text()}`);
console.log(await res.json());import os
import requests
res = requests.get(
"https://planitude.app/api/projects/40be00e0-7e34-4f7a-864b-5cc986f575b8/tasks/4dbd104a-00cd-4035-8955-255f52ea586a/comments",
headers={"Authorization": f"Bearer {os.environ['PLANITUDE_API_KEY']}"},
)
res.raise_for_status()
print(res.json()){
"comments": [
{
"id": "0fc2dec5-a409-47c9-9c6e-0663e8f8bcf3",
"taskId": "4dbd104a-00cd-4035-8955-255f52ea586a",
"userId": "b1666432-132a-4ea9-b1ae-76ea69e226c5",
"authorName": "Anna Rossi",
"authorAvatarUrl": null,
"body": "Concrete delivered, we can start the walls.",
"mentions": [],
"createdAt": "2026-10-01T08:30:12.418Z",
"editedAt": null
}
]
}Comment on a task
POST/api/projects/{projectId}/tasks/{taskId}/comments
Kunci dengan akses tulis
Parameter path
| Field | Tipe | Deskripsi |
|---|---|---|
| projectId wajib | string (uuid) | Project id. |
| taskId wajib | string (uuid) | Task id. |
Isi permintaan
| Field | Tipe | Deskripsi |
|---|---|---|
| body wajib | string | Plain text. |
| mentions | array of string | User ids to notify. |
Mengembalikan
201 Created Created
| Field | Tipe | Deskripsi |
|---|---|---|
| comment | Comment |
curl -X POST https://planitude.app/api/projects/40be00e0-7e34-4f7a-864b-5cc986f575b8/tasks/4dbd104a-00cd-4035-8955-255f52ea586a/comments \
-H "Authorization: Bearer $PLANITUDE_API_KEY" \
-H "Content-Type: application/json" \
-d '{"body":"Concrete delivered, we can start the walls."}'const res = await fetch("https://planitude.app/api/projects/40be00e0-7e34-4f7a-864b-5cc986f575b8/tasks/4dbd104a-00cd-4035-8955-255f52ea586a/comments", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.PLANITUDE_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
body: "Concrete delivered, we can start the walls.",
}),
});
if (!res.ok) throw new Error(`${res.status} ${await res.text()}`);
console.log(await res.json());import os
import requests
res = requests.post(
"https://planitude.app/api/projects/40be00e0-7e34-4f7a-864b-5cc986f575b8/tasks/4dbd104a-00cd-4035-8955-255f52ea586a/comments",
headers={"Authorization": f"Bearer {os.environ['PLANITUDE_API_KEY']}"},
json={
"body": "Concrete delivered, we can start the walls.",
},
)
res.raise_for_status()
print(res.json()){
"comment": {
"id": "0fc2dec5-a409-47c9-9c6e-0663e8f8bcf3",
"taskId": "4dbd104a-00cd-4035-8955-255f52ea586a",
"userId": "b1666432-132a-4ea9-b1ae-76ea69e226c5",
"authorName": "Anna Rossi",
"authorAvatarUrl": null,
"body": "Concrete delivered, we can start the walls.",
"mentions": [],
"createdAt": "2026-10-01T08:30:12.418Z",
"editedAt": null
}
}Referensi API
Dependencies
Links between tasks (FS, SS, FF, SF, with lag).
Dependency
Atribut
| Field | Tipe | Deskripsi |
|---|---|---|
| id | string (uuid) | |
| predecessorId | string (uuid) | |
| successorId | string (uuid) | |
| type | string | Salah satu dari: |
| lagMin | integer | Working minutes; negative = lead. |
{
"id": "9ba5faf8-923d-4ecc-86f0-f245c5d179db",
"predecessorId": "4dbd104a-00cd-4035-8955-255f52ea586a",
"successorId": "a22fd799-c4dc-4869-a466-0dd6e96f71ce",
"type": "FS",
"lagMin": 0
}List dependencies
GET/api/projects/{projectId}/dependencies
Kunci dengan akses baca
Parameter path
| Field | Tipe | Deskripsi |
|---|---|---|
| projectId wajib | string (uuid) | Project id. |
Mengembalikan
200 OK Dependencies
| Field | Tipe | Deskripsi |
|---|---|---|
| dependencies | array of Dependency |
curl https://planitude.app/api/projects/40be00e0-7e34-4f7a-864b-5cc986f575b8/dependencies \
-H "Authorization: Bearer $PLANITUDE_API_KEY"const res = await fetch("https://planitude.app/api/projects/40be00e0-7e34-4f7a-864b-5cc986f575b8/dependencies", {
headers: {
Authorization: `Bearer ${process.env.PLANITUDE_API_KEY}`,
},
});
if (!res.ok) throw new Error(`${res.status} ${await res.text()}`);
console.log(await res.json());import os
import requests
res = requests.get(
"https://planitude.app/api/projects/40be00e0-7e34-4f7a-864b-5cc986f575b8/dependencies",
headers={"Authorization": f"Bearer {os.environ['PLANITUDE_API_KEY']}"},
)
res.raise_for_status()
print(res.json()){
"dependencies": [
{
"id": "9ba5faf8-923d-4ecc-86f0-f245c5d179db",
"predecessorId": "4dbd104a-00cd-4035-8955-255f52ea586a",
"successorId": "a22fd799-c4dc-4869-a466-0dd6e96f71ce",
"type": "FS",
"lagMin": 0
}
]
}Create (or update) a dependency
POST/api/projects/{projectId}/dependencies
Kunci dengan akses tulis
A dependency that would close a cycle is refused with 409 dependency_cycle.
Parameter path
| Field | Tipe | Deskripsi |
|---|---|---|
| projectId wajib | string (uuid) | Project id. |
Isi permintaan
DependencyCreate
| Field | Tipe | Deskripsi |
|---|---|---|
| predecessorId wajib | string (uuid) | |
| successorId wajib | string (uuid) | |
| type | string | Salah satu dari: Default: |
| lagMin | integer | Default: |
atau dependencies
| Field | Tipe | Deskripsi |
|---|---|---|
| dependencies wajib | array of DependencyCreate |
Mengembalikan
201 Created Created
| Field | Tipe | Deskripsi | |||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| tasks | array of Task | Created/updated tasks plus the ones the recalculation moved. | |||||||||||||||
| deletedTaskIds | array of string | ||||||||||||||||
| dependencies | array of Dependency | ||||||||||||||||
| deletedDependencyIds | array of string | ||||||||||||||||
| conflicts | array of Conflict | ||||||||||||||||
| projectStartAt | string (date-time) | ||||||||||||||||
| projectFinishAt | string (date-time) | ||||||||||||||||
| stats | object | Tampilkan field stats
|
curl -X POST https://planitude.app/api/projects/40be00e0-7e34-4f7a-864b-5cc986f575b8/dependencies \
-H "Authorization: Bearer $PLANITUDE_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"predecessorId": "4dbd104a-00cd-4035-8955-255f52ea586a",
"successorId": "a22fd799-c4dc-4869-a466-0dd6e96f71ce",
"type": "FS",
"lagMin": 0
}'const res = await fetch("https://planitude.app/api/projects/40be00e0-7e34-4f7a-864b-5cc986f575b8/dependencies", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.PLANITUDE_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
predecessorId: "4dbd104a-00cd-4035-8955-255f52ea586a",
successorId: "a22fd799-c4dc-4869-a466-0dd6e96f71ce",
type: "FS",
lagMin: 0,
}),
});
if (!res.ok) throw new Error(`${res.status} ${await res.text()}`);
console.log(await res.json());import os
import requests
res = requests.post(
"https://planitude.app/api/projects/40be00e0-7e34-4f7a-864b-5cc986f575b8/dependencies",
headers={"Authorization": f"Bearer {os.environ['PLANITUDE_API_KEY']}"},
json={
"predecessorId": "4dbd104a-00cd-4035-8955-255f52ea586a",
"successorId": "a22fd799-c4dc-4869-a466-0dd6e96f71ce",
"type": "FS",
"lagMin": 0,
},
)
res.raise_for_status()
print(res.json()){
"tasks": [
{
"id": "4dbd104a-00cd-4035-8955-255f52ea586a",
"number": 1,
"key": "WHX-1",
"parentId": null,
"sortKey": "i",
"name": "Foundations",
"type": "task",
"durationMin": 1440,
"workMin": 0,
"progressPct": 0,
"constraintKind": "asap",
"constraintDate": null,
"deadline": null,
"calendarId": null,
"costFixed": 0,
"notes": null,
"color": null,
"wbs": null,
"externalId": "crm-4711",
"startAt": "2026-10-05T06:00:00.000Z",
"finishAt": "2026-10-07T15:00:00.000Z",
"isCritical": true,
"totalFloatMin": 0,
"earlyStartAt": "2026-10-05T06:00:00.000Z",
"lateFinishAt": "2026-10-07T15:00:00.000Z",
"actualStartAt": null,
"actualFinishAt": null,
"actualDurationMin": null,
"remainingDurationMin": null,
"manuallyScheduled": false,
"levelingDelayMin": 0,
"taskType": "fixed_units",
"effortDriven": false,
"durationOptimisticMin": null,
"durationPessimisticMin": null
}
],
"deletedTaskIds": [],
"dependencies": [
{
"id": "9ba5faf8-923d-4ecc-86f0-f245c5d179db",
"predecessorId": "4dbd104a-00cd-4035-8955-255f52ea586a",
"successorId": "a22fd799-c4dc-4869-a466-0dd6e96f71ce",
"type": "FS",
"lagMin": 0
}
],
"deletedDependencyIds": [],
"conflicts": [],
"projectStartAt": "2026-10-05T06:00:00.000Z",
"projectFinishAt": "2026-10-07T15:00:00.000Z",
"stats": {
"taskCount": 12,
"recomputedCount": 3,
"savedCount": 2,
"durationMs": 39
}
}Remove a dependency
DEL/api/projects/{projectId}/dependencies/{dependencyId}
Kunci dengan akses tulis
Parameter path
| Field | Tipe | Deskripsi |
|---|---|---|
| projectId wajib | string (uuid) | Project id. |
| dependencyId wajib | string (uuid) |
Mengembalikan
200 OK Removed
| Field | Tipe | Deskripsi | |||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| tasks | array of Task | Created/updated tasks plus the ones the recalculation moved. | |||||||||||||||
| deletedTaskIds | array of string | ||||||||||||||||
| dependencies | array of Dependency | ||||||||||||||||
| deletedDependencyIds | array of string | ||||||||||||||||
| conflicts | array of Conflict | ||||||||||||||||
| projectStartAt | string (date-time) | ||||||||||||||||
| projectFinishAt | string (date-time) | ||||||||||||||||
| stats | object | Tampilkan field stats
|
curl -X DELETE https://planitude.app/api/projects/40be00e0-7e34-4f7a-864b-5cc986f575b8/dependencies/9ba5faf8-923d-4ecc-86f0-f245c5d179db \
-H "Authorization: Bearer $PLANITUDE_API_KEY"const res = await fetch("https://planitude.app/api/projects/40be00e0-7e34-4f7a-864b-5cc986f575b8/dependencies/9ba5faf8-923d-4ecc-86f0-f245c5d179db", {
method: "DELETE",
headers: {
Authorization: `Bearer ${process.env.PLANITUDE_API_KEY}`,
},
});
if (!res.ok) throw new Error(`${res.status} ${await res.text()}`);
console.log(res.status); // 204import os
import requests
res = requests.delete(
"https://planitude.app/api/projects/40be00e0-7e34-4f7a-864b-5cc986f575b8/dependencies/9ba5faf8-923d-4ecc-86f0-f245c5d179db",
headers={"Authorization": f"Bearer {os.environ['PLANITUDE_API_KEY']}"},
)
res.raise_for_status()
print(res.status_code) # 204{
"tasks": [
{
"id": "4dbd104a-00cd-4035-8955-255f52ea586a",
"number": 1,
"key": "WHX-1",
"parentId": null,
"sortKey": "i",
"name": "Foundations",
"type": "task",
"durationMin": 1440,
"workMin": 0,
"progressPct": 0,
"constraintKind": "asap",
"constraintDate": null,
"deadline": null,
"calendarId": null,
"costFixed": 0,
"notes": null,
"color": null,
"wbs": null,
"externalId": "crm-4711",
"startAt": "2026-10-05T06:00:00.000Z",
"finishAt": "2026-10-07T15:00:00.000Z",
"isCritical": true,
"totalFloatMin": 0,
"earlyStartAt": "2026-10-05T06:00:00.000Z",
"lateFinishAt": "2026-10-07T15:00:00.000Z",
"actualStartAt": null,
"actualFinishAt": null,
"actualDurationMin": null,
"remainingDurationMin": null,
"manuallyScheduled": false,
"levelingDelayMin": 0,
"taskType": "fixed_units",
"effortDriven": false,
"durationOptimisticMin": null,
"durationPessimisticMin": null
}
],
"deletedTaskIds": [],
"dependencies": [
{
"id": "9ba5faf8-923d-4ecc-86f0-f245c5d179db",
"predecessorId": "4dbd104a-00cd-4035-8955-255f52ea586a",
"successorId": "a22fd799-c4dc-4869-a466-0dd6e96f71ce",
"type": "FS",
"lagMin": 0
}
],
"deletedDependencyIds": [],
"conflicts": [],
"projectStartAt": "2026-10-05T06:00:00.000Z",
"projectFinishAt": "2026-10-07T15:00:00.000Z",
"stats": {
"taskCount": 12,
"recomputedCount": 3,
"savedCount": 2,
"durationMs": 39
}
}Referensi API
People
Project members and task assignees.
Member
Atribut
| Field | Tipe | Deskripsi |
|---|---|---|
| userId | string (uuid) | |
| name | string | |
| string | ||
| role | string | Effective role on the project. Salah satu dari: |
| directRole | stringnullable | Role granted on the project itself (null = only through the workspace). Salah satu dari: |
| inherited | boolean | Access comes from the workspace. |
| resourceId | string (uuid)nullable | Resource used when the person is assigned to tasks. |
| addedAt | string (date-time) | |
| avatarUrl | stringnullable |
{
"userId": "b1666432-132a-4ea9-b1ae-76ea69e226c5",
"name": "Anna Rossi",
"email": "[email protected]",
"role": "owner",
"directRole": null,
"inherited": false,
"resourceId": "0c6a8f52-3d7e-4b19-9a4e-6f1d2c8b7e30",
"addedAt": "2026-10-01T08:30:12.418Z",
"avatarUrl": null
}Assignee
Atribut
| Field | Tipe | Deskripsi |
|---|---|---|
| resourceId | string (uuid) | |
| userId | string (uuid)nullable | |
| name | string | |
| unitsPct | integer |
{
"resourceId": "0c6a8f52-3d7e-4b19-9a4e-6f1d2c8b7e30",
"userId": "b1666432-132a-4ea9-b1ae-76ea69e226c5",
"name": "Anna Rossi",
"unitsPct": 100
}Replace the people assigned to a task
PUT/api/projects/{projectId}/tasks/{taskId}/assignees
Kunci dengan akses tulis
userIds must be members of the project (GET /members). An empty list removes everyone. Optional resourceIds replaces the people imported from a file (resources without an account) assigned to the task; omit it to leave them as they are.
Parameter path
| Field | Tipe | Deskripsi |
|---|---|---|
| projectId wajib | string (uuid) | Project id. |
| taskId wajib | string (uuid) | Task id. |
Isi permintaan
| Field | Tipe | Deskripsi |
|---|---|---|
| userIds wajib | array of string | |
| resourceIds | array of string |
Mengembalikan
200 OK Assignees saved
| Field | Tipe | Deskripsi | ||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| taskId | string (uuid) | |||||||||||||||||||||||||||||||||||||
| assignments | array of object | Tampilkan field assignments
| ||||||||||||||||||||||||||||||||||||
| resources | array of object | Tampilkan field resources
| ||||||||||||||||||||||||||||||||||||
| needsReschedule | boolean | |||||||||||||||||||||||||||||||||||||
| conflicts | array of Conflict |
curl -X PUT https://planitude.app/api/projects/40be00e0-7e34-4f7a-864b-5cc986f575b8/tasks/4dbd104a-00cd-4035-8955-255f52ea586a/assignees \
-H "Authorization: Bearer $PLANITUDE_API_KEY" \
-H "Content-Type: application/json" \
-d '{"userIds":["b1666432-132a-4ea9-b1ae-76ea69e226c5"]}'const res = await fetch("https://planitude.app/api/projects/40be00e0-7e34-4f7a-864b-5cc986f575b8/tasks/4dbd104a-00cd-4035-8955-255f52ea586a/assignees", {
method: "PUT",
headers: {
Authorization: `Bearer ${process.env.PLANITUDE_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
userIds: ["b1666432-132a-4ea9-b1ae-76ea69e226c5"],
}),
});
if (!res.ok) throw new Error(`${res.status} ${await res.text()}`);
console.log(await res.json());import os
import requests
res = requests.put(
"https://planitude.app/api/projects/40be00e0-7e34-4f7a-864b-5cc986f575b8/tasks/4dbd104a-00cd-4035-8955-255f52ea586a/assignees",
headers={"Authorization": f"Bearer {os.environ['PLANITUDE_API_KEY']}"},
json={
"userIds": ["b1666432-132a-4ea9-b1ae-76ea69e226c5"],
},
)
res.raise_for_status()
print(res.json()){
"taskId": "4dbd104a-00cd-4035-8955-255f52ea586a",
"assignments": [
{
"id": "e62ac96b-e68e-40d3-842e-335e27dfd099",
"taskId": "4dbd104a-00cd-4035-8955-255f52ea586a",
"resourceId": "0c6a8f52-3d7e-4b19-9a4e-6f1d2c8b7e30",
"unitsPct": 100,
"workMin": 0
}
],
"resources": [
{
"id": "0c6a8f52-3d7e-4b19-9a4e-6f1d2c8b7e30",
"userId": "b1666432-132a-4ea9-b1ae-76ea69e226c5",
"name": "Anna Rossi",
"kind": "builtin",
"email": "[email protected]",
"costPerHour": 0,
"costPerUse": 0,
"capacityPct": 0,
"calendarId": null,
"color": null,
"avatarUrl": null
}
],
"needsReschedule": false,
"conflicts": []
}People with access to the project (assignable)
GET/api/projects/{projectId}/members
Kunci dengan akses baca
Parameter path
| Field | Tipe | Deskripsi |
|---|---|---|
| projectId wajib | string (uuid) | Project id. |
Mengembalikan
200 OK Members
| Field | Tipe | Deskripsi |
|---|---|---|
| members | array of Member | |
| role | string |
curl https://planitude.app/api/projects/40be00e0-7e34-4f7a-864b-5cc986f575b8/members \
-H "Authorization: Bearer $PLANITUDE_API_KEY"const res = await fetch("https://planitude.app/api/projects/40be00e0-7e34-4f7a-864b-5cc986f575b8/members", {
headers: {
Authorization: `Bearer ${process.env.PLANITUDE_API_KEY}`,
},
});
if (!res.ok) throw new Error(`${res.status} ${await res.text()}`);
console.log(await res.json());import os
import requests
res = requests.get(
"https://planitude.app/api/projects/40be00e0-7e34-4f7a-864b-5cc986f575b8/members",
headers={"Authorization": f"Bearer {os.environ['PLANITUDE_API_KEY']}"},
)
res.raise_for_status()
print(res.json()){
"members": [
{
"userId": "b1666432-132a-4ea9-b1ae-76ea69e226c5",
"name": "Anna Rossi",
"email": "[email protected]",
"role": "owner",
"directRole": null,
"inherited": false,
"resourceId": "0c6a8f52-3d7e-4b19-9a4e-6f1d2c8b7e30",
"addedAt": "2026-10-01T08:30:12.418Z",
"avatarUrl": null
}
],
"role": "owner"
}Referensi API
Webhooks
Outgoing webhook subscriptions (REST hooks: subscribe/unsubscribe).
- GET/api/webhooks
- POST/api/webhooks
- GET/api/webhooks/events
- GET/api/webhooks/{webhookId}
- PATCH/api/webhooks/{webhookId}
- DELETE/api/webhooks/{webhookId}
- GET/api/webhooks/{webhookId}/deliveries
- GET/api/webhooks/{webhookId}/deliveries/{deliveryId}
- POST/api/webhooks/{webhookId}/deliveries/{deliveryId}/redeliver
- POST/api/webhooks/{webhookId}/test
- POST/api/webhooks/{webhookId}/rotate-secret
Webhook
Atribut
| Field | Tipe | Deskripsi | |||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|
| id | string (uuid) | ||||||||||
| workspaceId | string (uuid) | ||||||||||
| workspaceName | string | ||||||||||
| projectId | string (uuid)nullable | null = every project of the workspace. | |||||||||
| projectName | stringnullable | ||||||||||
| name | string | ||||||||||
| url | string (uri) | ||||||||||
| events | array of string | Salah satu dari: | |||||||||
| secretPrefix | string | First characters of the signing secret (not secret). | |||||||||
| active | boolean | ||||||||||
| disabledReason | stringnullable | Salah satu dari: | |||||||||
| disabledAt | string (date-time)nullable | ||||||||||
| consecutiveFailures | integer | ||||||||||
| viaApi | boolean | Created with the API (REST hook) rather than from the profile. | |||||||||
| createdBy | objectnullable | Tampilkan field createdBy
| |||||||||
| createdAt | string (date-time) | ||||||||||
| updatedAt | string (date-time) | ||||||||||
| lastDeliveryAt | string (date-time)nullable | ||||||||||
| lastSuccessAt | string (date-time)nullable |
{
"id": "1747ee7f-a395-4d3c-94b0-54b513d71d88",
"workspaceId": "824650d2-d0b3-4cac-8df8-5743ae9ff65a",
"workspaceName": "Acme Construction",
"projectId": "40be00e0-7e34-4f7a-864b-5cc986f575b8",
"projectName": "Warehouse expansion",
"name": "Warehouse sync",
"url": "https://example.com/hooks/planitude",
"events": [
"task.created",
"task.completed"
],
"secretPrefix": "whsec_Fdwl",
"active": true,
"disabledReason": null,
"disabledAt": null,
"consecutiveFailures": 0,
"viaApi": true,
"createdBy": {
"id": "b1666432-132a-4ea9-b1ae-76ea69e226c5",
"name": "Anna Rossi"
},
"createdAt": "2026-10-01T08:30:12.418Z",
"updatedAt": "2026-10-01T08:30:12.418Z",
"lastDeliveryAt": "2026-10-01T08:30:12.418Z",
"lastSuccessAt": "2026-10-01T08:30:12.418Z"
}Delivery
Atribut
| Field | Tipe | Deskripsi |
|---|---|---|
| id | string (uuid) | |
| eventId | string (uuid) | |
| eventType | string | |
| status | string | Salah satu dari: |
| attempts | integer | |
| nextAttemptAt | string (date-time)nullable | |
| lastAttemptAt | string (date-time)nullable | |
| responseStatus | integernullable | |
| responseExcerpt | stringnullable | |
| error | stringnullable | |
| durationMs | integernullable | |
| manual | boolean | |
| createdAt | string (date-time) |
{
"id": "4b207161-80f9-40bb-bc3f-d8f70315be00",
"eventId": "6f1c1d1e-2f4b-4d0a-9a77-2a3c5b1e9f10",
"eventType": "task.completed",
"status": "success",
"attempts": 1,
"nextAttemptAt": null,
"lastAttemptAt": "2026-10-01T08:30:12.418Z",
"responseStatus": 200,
"responseExcerpt": "{\"ok\":true}",
"error": null,
"durationMs": 39,
"manual": false,
"createdAt": "2026-10-01T08:30:12.418Z"
}Event
Atribut
| Field | Tipe | Deskripsi | |||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|
| id wajib | string (uuid) | Event id, also in the Planitude-Event-Id header: use it to deduplicate. | |||||||||
| type wajib | string | Salah satu dari: | |||||||||
| apiVersion wajib | string | Salah satu dari: | |||||||||
| createdAt wajib | string (date-time) | ||||||||||
| workspaceId wajib | string (uuid) | ||||||||||
| projectId | string (uuid)nullable | ||||||||||
| actor | objectnullable | Who made the change (null for system changes).Tampilkan field actor
| |||||||||
| data wajib | object |
{
"id": "6f1c1d1e-2f4b-4d0a-9a77-2a3c5b1e9f10",
"type": "project.created",
"apiVersion": "2026-10-01",
"createdAt": "2026-10-01T08:30:12.418Z",
"workspaceId": "824650d2-d0b3-4cac-8df8-5743ae9ff65a",
"projectId": "40be00e0-7e34-4f7a-864b-5cc986f575b8",
"actor": {
"id": "b1666432-132a-4ea9-b1ae-76ea69e226c5",
"name": "Anna Rossi"
},
"data": {}
}Project (event payload)
Compact project representation used in webhook payloads.
Atribut
| Field | Tipe | Deskripsi |
|---|---|---|
| id | string (uuid) | |
| workspaceId | string (uuid) | |
| key | string | |
| name | string | |
| description | stringnullable | |
| startDate | string (date) | |
| deadline | string (date)nullable | |
| currency | string | |
| scheduleFrom | string | Salah satu dari: |
| color | stringnullable | |
| archived | boolean | |
| createdAt | string (date-time) | |
| updatedAt | string (date-time) | |
| url | string (uri) |
{
"id": "40be00e0-7e34-4f7a-864b-5cc986f575b8",
"workspaceId": "824650d2-d0b3-4cac-8df8-5743ae9ff65a",
"key": "WHX",
"name": "Warehouse expansion",
"description": null,
"startDate": "2026-10-05",
"deadline": null,
"currency": "EUR",
"scheduleFrom": "forward",
"color": null,
"archived": false,
"createdAt": "2026-10-01T08:30:12.418Z",
"updatedAt": "2026-10-01T08:30:12.418Z",
"url": "https://planitude.app/app/projects/40be00e0-7e34-4f7a-864b-5cc986f575b8"
}List webhook subscriptions
GET/api/webhooks
Kunci dengan akses baca
Parameter query
| Field | Tipe | Deskripsi |
|---|---|---|
| workspaceId | string (uuid) | |
| projectId | string (uuid) |
Mengembalikan
200 OK Subscriptions
| Field | Tipe | Deskripsi |
|---|---|---|
| webhooks | array of Webhook |
curl https://planitude.app/api/webhooks \
-H "Authorization: Bearer $PLANITUDE_API_KEY"const res = await fetch("https://planitude.app/api/webhooks", {
headers: {
Authorization: `Bearer ${process.env.PLANITUDE_API_KEY}`,
},
});
if (!res.ok) throw new Error(`${res.status} ${await res.text()}`);
console.log(await res.json());import os
import requests
res = requests.get(
"https://planitude.app/api/webhooks",
headers={"Authorization": f"Bearer {os.environ['PLANITUDE_API_KEY']}"},
)
res.raise_for_status()
print(res.json()){
"webhooks": [
{
"id": "1747ee7f-a395-4d3c-94b0-54b513d71d88",
"workspaceId": "824650d2-d0b3-4cac-8df8-5743ae9ff65a",
"workspaceName": "Acme Construction",
"projectId": "40be00e0-7e34-4f7a-864b-5cc986f575b8",
"projectName": "Warehouse expansion",
"name": "Warehouse sync",
"url": "https://example.com/hooks/planitude",
"events": [
"task.created",
"task.completed"
],
"secretPrefix": "whsec_Fdwl",
"active": true,
"disabledReason": null,
"disabledAt": null,
"consecutiveFailures": 0,
"viaApi": true,
"createdBy": {
"id": "b1666432-132a-4ea9-b1ae-76ea69e226c5",
"name": "Anna Rossi"
},
"createdAt": "2026-10-01T08:30:12.418Z",
"updatedAt": "2026-10-01T08:30:12.418Z",
"lastDeliveryAt": "2026-10-01T08:30:12.418Z",
"lastSuccessAt": "2026-10-01T08:30:12.418Z"
}
]
}Subscribe (REST hook)
POST/api/webhooks
Kunci dengan akses tulis
Creates a subscription. The response contains the signing secret: it is shown only once. Aliases accepted for automation platforms: targetUrl for url, event for a single event.
Isi permintaan
| Field | Tipe | Deskripsi |
|---|---|---|
| url wajib | string (uri) | HTTPS endpoint that receives the events. Public addresses only. |
| events wajib | array of string | * = all events.Salah satu dari: |
| name | string | |
| projectId | string (uuid) | Limit to one project (editor role needed). Omit for the whole workspace (owner/admin). |
| workspaceId | string (uuid) |
Mengembalikan
201 Created Created
| Field | Tipe | Deskripsi |
|---|---|---|
| webhook | Webhook | |
| secret | string | whsec_... |
curl -X POST https://planitude.app/api/webhooks \
-H "Authorization: Bearer $PLANITUDE_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"url": "https://example.com/hooks/planitude",
"events": [
"task.created",
"task.completed"
],
"projectId": "40be00e0-7e34-4f7a-864b-5cc986f575b8"
}'const res = await fetch("https://planitude.app/api/webhooks", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.PLANITUDE_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
url: "https://example.com/hooks/planitude",
events: ["task.created", "task.completed"],
projectId: "40be00e0-7e34-4f7a-864b-5cc986f575b8",
}),
});
if (!res.ok) throw new Error(`${res.status} ${await res.text()}`);
console.log(await res.json());import os
import requests
res = requests.post(
"https://planitude.app/api/webhooks",
headers={"Authorization": f"Bearer {os.environ['PLANITUDE_API_KEY']}"},
json={
"url": "https://example.com/hooks/planitude",
"events": ["task.created", "task.completed"],
"projectId": "40be00e0-7e34-4f7a-864b-5cc986f575b8",
},
)
res.raise_for_status()
print(res.json()){
"webhook": {
"id": "1747ee7f-a395-4d3c-94b0-54b513d71d88",
"workspaceId": "824650d2-d0b3-4cac-8df8-5743ae9ff65a",
"workspaceName": "Acme Construction",
"projectId": "40be00e0-7e34-4f7a-864b-5cc986f575b8",
"projectName": "Warehouse expansion",
"name": "Warehouse sync",
"url": "https://example.com/hooks/planitude",
"events": [
"task.created",
"task.completed"
],
"secretPrefix": "whsec_Fdwl",
"active": true,
"disabledReason": null,
"disabledAt": null,
"consecutiveFailures": 0,
"viaApi": true,
"createdBy": {
"id": "b1666432-132a-4ea9-b1ae-76ea69e226c5",
"name": "Anna Rossi"
},
"createdAt": "2026-10-01T08:30:12.418Z",
"updatedAt": "2026-10-01T08:30:12.418Z",
"lastDeliveryAt": "2026-10-01T08:30:12.418Z",
"lastSuccessAt": "2026-10-01T08:30:12.418Z"
},
"secret": "whsec_3dvU0T1oaYlW4kH6m2Vb8nqXcR9eZpLsYw1QhGk"
}Event catalog (public)
GET/api/webhooks/events
Publik, tanpa kunci
Mengembalikan
200 OK Events
| Field | Tipe | Deskripsi |
|---|---|---|
| apiVersion | string | |
| events | array of string |
curl https://planitude.app/api/webhooks/eventsconst res = await fetch("https://planitude.app/api/webhooks/events");
if (!res.ok) throw new Error(`${res.status} ${await res.text()}`);
console.log(await res.json());import requests
res = requests.get("https://planitude.app/api/webhooks/events")
res.raise_for_status()
print(res.json()){
"apiVersion": "2026-10-01",
"events": [
"project.created",
"project.updated",
"project.deleted",
"task.created",
"task.updated",
"task.deleted",
"task.completed",
"task.dates_changed",
"dependency.created",
"dependency.deleted",
"baseline.saved",
"member.invited",
"member.joined",
"comment.created"
]
}Get a subscription
GET/api/webhooks/{webhookId}
Kunci dengan akses baca
Parameter path
| Field | Tipe | Deskripsi |
|---|---|---|
| webhookId wajib | string (uuid) | Webhook id. |
Mengembalikan
200 OK Subscription
| Field | Tipe | Deskripsi |
|---|---|---|
| webhook | Webhook |
curl https://planitude.app/api/webhooks/1747ee7f-a395-4d3c-94b0-54b513d71d88 \
-H "Authorization: Bearer $PLANITUDE_API_KEY"const res = await fetch("https://planitude.app/api/webhooks/1747ee7f-a395-4d3c-94b0-54b513d71d88", {
headers: {
Authorization: `Bearer ${process.env.PLANITUDE_API_KEY}`,
},
});
if (!res.ok) throw new Error(`${res.status} ${await res.text()}`);
console.log(await res.json());import os
import requests
res = requests.get(
"https://planitude.app/api/webhooks/1747ee7f-a395-4d3c-94b0-54b513d71d88",
headers={"Authorization": f"Bearer {os.environ['PLANITUDE_API_KEY']}"},
)
res.raise_for_status()
print(res.json()){
"webhook": {
"id": "1747ee7f-a395-4d3c-94b0-54b513d71d88",
"workspaceId": "824650d2-d0b3-4cac-8df8-5743ae9ff65a",
"workspaceName": "Acme Construction",
"projectId": "40be00e0-7e34-4f7a-864b-5cc986f575b8",
"projectName": "Warehouse expansion",
"name": "Warehouse sync",
"url": "https://example.com/hooks/planitude",
"events": [
"task.created",
"task.completed"
],
"secretPrefix": "whsec_Fdwl",
"active": true,
"disabledReason": null,
"disabledAt": null,
"consecutiveFailures": 0,
"viaApi": true,
"createdBy": {
"id": "b1666432-132a-4ea9-b1ae-76ea69e226c5",
"name": "Anna Rossi"
},
"createdAt": "2026-10-01T08:30:12.418Z",
"updatedAt": "2026-10-01T08:30:12.418Z",
"lastDeliveryAt": "2026-10-01T08:30:12.418Z",
"lastSuccessAt": "2026-10-01T08:30:12.418Z"
}
}Update, pause or resume a subscription
PATCH/api/webhooks/{webhookId}
Kunci dengan akses tulis
Parameter path
| Field | Tipe | Deskripsi |
|---|---|---|
| webhookId wajib | string (uuid) | Webhook id. |
Isi permintaan
| Field | Tipe | Deskripsi |
|---|---|---|
| name | string | |
| url | string (uri) | |
| events | array of string | |
| active | boolean | false = pause; true = resume (also resets the failure counter). |
Mengembalikan
200 OK Updated
| Field | Tipe | Deskripsi |
|---|---|---|
| webhook | Webhook |
curl -X PATCH https://planitude.app/api/webhooks/1747ee7f-a395-4d3c-94b0-54b513d71d88 \
-H "Authorization: Bearer $PLANITUDE_API_KEY" \
-H "Content-Type: application/json" \
-d '{"active":false}'const res = await fetch("https://planitude.app/api/webhooks/1747ee7f-a395-4d3c-94b0-54b513d71d88", {
method: "PATCH",
headers: {
Authorization: `Bearer ${process.env.PLANITUDE_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
active: false,
}),
});
if (!res.ok) throw new Error(`${res.status} ${await res.text()}`);
console.log(await res.json());import os
import requests
res = requests.patch(
"https://planitude.app/api/webhooks/1747ee7f-a395-4d3c-94b0-54b513d71d88",
headers={"Authorization": f"Bearer {os.environ['PLANITUDE_API_KEY']}"},
json={
"active": False,
},
)
res.raise_for_status()
print(res.json()){
"webhook": {
"id": "1747ee7f-a395-4d3c-94b0-54b513d71d88",
"workspaceId": "824650d2-d0b3-4cac-8df8-5743ae9ff65a",
"workspaceName": "Acme Construction",
"projectId": "40be00e0-7e34-4f7a-864b-5cc986f575b8",
"projectName": "Warehouse expansion",
"name": "Warehouse sync",
"url": "https://example.com/hooks/planitude",
"events": [
"task.created",
"task.completed"
],
"secretPrefix": "whsec_Fdwl",
"active": true,
"disabledReason": null,
"disabledAt": null,
"consecutiveFailures": 0,
"viaApi": true,
"createdBy": {
"id": "b1666432-132a-4ea9-b1ae-76ea69e226c5",
"name": "Anna Rossi"
},
"createdAt": "2026-10-01T08:30:12.418Z",
"updatedAt": "2026-10-01T08:30:12.418Z",
"lastDeliveryAt": "2026-10-01T08:30:12.418Z",
"lastSuccessAt": "2026-10-01T08:30:12.418Z"
}
}Unsubscribe (REST hook)
DEL/api/webhooks/{webhookId}
Kunci dengan akses tulis
Parameter path
| Field | Tipe | Deskripsi |
|---|---|---|
| webhookId wajib | string (uuid) | Webhook id. |
Mengembalikan
204 No Content Deleted
curl -X DELETE https://planitude.app/api/webhooks/1747ee7f-a395-4d3c-94b0-54b513d71d88 \
-H "Authorization: Bearer $PLANITUDE_API_KEY"const res = await fetch("https://planitude.app/api/webhooks/1747ee7f-a395-4d3c-94b0-54b513d71d88", {
method: "DELETE",
headers: {
Authorization: `Bearer ${process.env.PLANITUDE_API_KEY}`,
},
});
if (!res.ok) throw new Error(`${res.status} ${await res.text()}`);
console.log(res.status); // 204import os
import requests
res = requests.delete(
"https://planitude.app/api/webhooks/1747ee7f-a395-4d3c-94b0-54b513d71d88",
headers={"Authorization": f"Bearer {os.environ['PLANITUDE_API_KEY']}"},
)
res.raise_for_status()
print(res.status_code) # 204Delivery log (newest first, kept 30 days)
GET/api/webhooks/{webhookId}/deliveries
Kunci dengan akses baca
Parameter path
| Field | Tipe | Deskripsi |
|---|---|---|
| webhookId wajib | string (uuid) | Webhook id. |
Parameter query
| Field | Tipe | Deskripsi |
|---|---|---|
| limit | integer | 1-100. Default: |
| before | string (date-time) | nextCursor of the previous page. |
Mengembalikan
200 OK Deliveries
| Field | Tipe | Deskripsi |
|---|---|---|
| deliveries | array of Delivery | |
| nextCursor | stringnullable |
curl https://planitude.app/api/webhooks/1747ee7f-a395-4d3c-94b0-54b513d71d88/deliveries \
-H "Authorization: Bearer $PLANITUDE_API_KEY"const res = await fetch("https://planitude.app/api/webhooks/1747ee7f-a395-4d3c-94b0-54b513d71d88/deliveries", {
headers: {
Authorization: `Bearer ${process.env.PLANITUDE_API_KEY}`,
},
});
if (!res.ok) throw new Error(`${res.status} ${await res.text()}`);
console.log(await res.json());import os
import requests
res = requests.get(
"https://planitude.app/api/webhooks/1747ee7f-a395-4d3c-94b0-54b513d71d88/deliveries",
headers={"Authorization": f"Bearer {os.environ['PLANITUDE_API_KEY']}"},
)
res.raise_for_status()
print(res.json()){
"deliveries": [
{
"id": "4b207161-80f9-40bb-bc3f-d8f70315be00",
"eventId": "6f1c1d1e-2f4b-4d0a-9a77-2a3c5b1e9f10",
"eventType": "task.completed",
"status": "success",
"attempts": 1,
"nextAttemptAt": null,
"lastAttemptAt": "2026-10-01T08:30:12.418Z",
"responseStatus": 200,
"responseExcerpt": "{\"ok\":true}",
"error": null,
"durationMs": 39,
"manual": false,
"createdAt": "2026-10-01T08:30:12.418Z"
}
],
"nextCursor": null
}Body sent with a delivery
GET/api/webhooks/{webhookId}/deliveries/{deliveryId}
Kunci dengan akses baca
Parameter path
| Field | Tipe | Deskripsi |
|---|---|---|
| webhookId wajib | string (uuid) | Webhook id. |
| deliveryId wajib | string (uuid) |
Mengembalikan
200 OK Payload
| Field | Tipe | Deskripsi |
|---|---|---|
| payload | Event |
curl https://planitude.app/api/webhooks/1747ee7f-a395-4d3c-94b0-54b513d71d88/deliveries/4b207161-80f9-40bb-bc3f-d8f70315be00 \
-H "Authorization: Bearer $PLANITUDE_API_KEY"const res = await fetch("https://planitude.app/api/webhooks/1747ee7f-a395-4d3c-94b0-54b513d71d88/deliveries/4b207161-80f9-40bb-bc3f-d8f70315be00", {
headers: {
Authorization: `Bearer ${process.env.PLANITUDE_API_KEY}`,
},
});
if (!res.ok) throw new Error(`${res.status} ${await res.text()}`);
console.log(await res.json());import os
import requests
res = requests.get(
"https://planitude.app/api/webhooks/1747ee7f-a395-4d3c-94b0-54b513d71d88/deliveries/4b207161-80f9-40bb-bc3f-d8f70315be00",
headers={"Authorization": f"Bearer {os.environ['PLANITUDE_API_KEY']}"},
)
res.raise_for_status()
print(res.json()){
"payload": {
"id": "6f1c1d1e-2f4b-4d0a-9a77-2a3c5b1e9f10",
"type": "project.created",
"apiVersion": "2026-10-01",
"createdAt": "2026-10-01T08:30:12.418Z",
"workspaceId": "824650d2-d0b3-4cac-8df8-5743ae9ff65a",
"projectId": "40be00e0-7e34-4f7a-864b-5cc986f575b8",
"actor": {
"id": "b1666432-132a-4ea9-b1ae-76ea69e226c5",
"name": "Anna Rossi"
},
"data": {}
}
}Send the same event again
POST/api/webhooks/{webhookId}/deliveries/{deliveryId}/redeliver
Kunci dengan akses tulis
Parameter path
| Field | Tipe | Deskripsi |
|---|---|---|
| webhookId wajib | string (uuid) | Webhook id. |
| deliveryId wajib | string (uuid) |
Mengembalikan
202 Accepted Queued
| Field | Tipe | Deskripsi |
|---|---|---|
| delivery | Delivery |
curl -X POST https://planitude.app/api/webhooks/1747ee7f-a395-4d3c-94b0-54b513d71d88/deliveries/4b207161-80f9-40bb-bc3f-d8f70315be00/redeliver \
-H "Authorization: Bearer $PLANITUDE_API_KEY"const res = await fetch("https://planitude.app/api/webhooks/1747ee7f-a395-4d3c-94b0-54b513d71d88/deliveries/4b207161-80f9-40bb-bc3f-d8f70315be00/redeliver", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.PLANITUDE_API_KEY}`,
},
});
if (!res.ok) throw new Error(`${res.status} ${await res.text()}`);
console.log(await res.json());import os
import requests
res = requests.post(
"https://planitude.app/api/webhooks/1747ee7f-a395-4d3c-94b0-54b513d71d88/deliveries/4b207161-80f9-40bb-bc3f-d8f70315be00/redeliver",
headers={"Authorization": f"Bearer {os.environ['PLANITUDE_API_KEY']}"},
)
res.raise_for_status()
print(res.json()){
"delivery": {
"id": "4b207161-80f9-40bb-bc3f-d8f70315be00",
"eventId": "6f1c1d1e-2f4b-4d0a-9a77-2a3c5b1e9f10",
"eventType": "task.completed",
"status": "success",
"attempts": 1,
"nextAttemptAt": null,
"lastAttemptAt": "2026-10-01T08:30:12.418Z",
"responseStatus": 200,
"responseExcerpt": "{\"ok\":true}",
"error": null,
"durationMs": 39,
"manual": false,
"createdAt": "2026-10-01T08:30:12.418Z"
}
}Send a webhook.ping test event
POST/api/webhooks/{webhookId}/test
Kunci dengan akses tulis
Parameter path
| Field | Tipe | Deskripsi |
|---|---|---|
| webhookId wajib | string (uuid) | Webhook id. |
Mengembalikan
202 Accepted Queued
| Field | Tipe | Deskripsi |
|---|---|---|
| delivery | Delivery |
curl -X POST https://planitude.app/api/webhooks/1747ee7f-a395-4d3c-94b0-54b513d71d88/test \
-H "Authorization: Bearer $PLANITUDE_API_KEY"const res = await fetch("https://planitude.app/api/webhooks/1747ee7f-a395-4d3c-94b0-54b513d71d88/test", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.PLANITUDE_API_KEY}`,
},
});
if (!res.ok) throw new Error(`${res.status} ${await res.text()}`);
console.log(await res.json());import os
import requests
res = requests.post(
"https://planitude.app/api/webhooks/1747ee7f-a395-4d3c-94b0-54b513d71d88/test",
headers={"Authorization": f"Bearer {os.environ['PLANITUDE_API_KEY']}"},
)
res.raise_for_status()
print(res.json()){
"delivery": {
"id": "4b207161-80f9-40bb-bc3f-d8f70315be00",
"eventId": "6f1c1d1e-2f4b-4d0a-9a77-2a3c5b1e9f10",
"eventType": "task.completed",
"status": "success",
"attempts": 1,
"nextAttemptAt": null,
"lastAttemptAt": "2026-10-01T08:30:12.418Z",
"responseStatus": 200,
"responseExcerpt": "{\"ok\":true}",
"error": null,
"durationMs": 39,
"manual": false,
"createdAt": "2026-10-01T08:30:12.418Z"
}
}Generate a new signing secret
POST/api/webhooks/{webhookId}/rotate-secret
Kunci dengan akses tulis
Parameter path
| Field | Tipe | Deskripsi |
|---|---|---|
| webhookId wajib | string (uuid) | Webhook id. |
Mengembalikan
200 OK New secret (shown once)
| Field | Tipe | Deskripsi |
|---|---|---|
| webhook | Webhook | |
| secret | string |
curl -X POST https://planitude.app/api/webhooks/1747ee7f-a395-4d3c-94b0-54b513d71d88/rotate-secret \
-H "Authorization: Bearer $PLANITUDE_API_KEY"const res = await fetch("https://planitude.app/api/webhooks/1747ee7f-a395-4d3c-94b0-54b513d71d88/rotate-secret", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.PLANITUDE_API_KEY}`,
},
});
if (!res.ok) throw new Error(`${res.status} ${await res.text()}`);
console.log(await res.json());import os
import requests
res = requests.post(
"https://planitude.app/api/webhooks/1747ee7f-a395-4d3c-94b0-54b513d71d88/rotate-secret",
headers={"Authorization": f"Bearer {os.environ['PLANITUDE_API_KEY']}"},
)
res.raise_for_status()
print(res.json()){
"webhook": {
"id": "1747ee7f-a395-4d3c-94b0-54b513d71d88",
"workspaceId": "824650d2-d0b3-4cac-8df8-5743ae9ff65a",
"workspaceName": "Acme Construction",
"projectId": "40be00e0-7e34-4f7a-864b-5cc986f575b8",
"projectName": "Warehouse expansion",
"name": "Warehouse sync",
"url": "https://example.com/hooks/planitude",
"events": [
"task.created",
"task.completed"
],
"secretPrefix": "whsec_Fdwl",
"active": true,
"disabledReason": null,
"disabledAt": null,
"consecutiveFailures": 0,
"viaApi": true,
"createdBy": {
"id": "b1666432-132a-4ea9-b1ae-76ea69e226c5",
"name": "Anna Rossi"
},
"createdAt": "2026-10-01T08:30:12.418Z",
"updatedAt": "2026-10-01T08:30:12.418Z",
"lastDeliveryAt": "2026-10-01T08:30:12.418Z",
"lastSuccessAt": "2026-10-01T08:30:12.418Z"
},
"secret": "whsec_3dvU0T1oaYlW4kH6m2Vb8nqXcR9eZpLsYw1QhGk"
}Webhook
Webhook
Webhook mengirim POST HTTPS dengan isi JSON ke endpoint Anda segera setelah ada perubahan, baik perubahan itu berasal dari aplikasi web, API, server MCP, maupun impor. Satu webhook mencakup satu proyek, atau seluruh proyek dalam sebuah ruang kerja (pemilik dan admin).
Buat di Profil → Webhook atau lewat API, sebagai REST hook: berlangganan dengan POST /api/webhooks, berhenti berlangganan dengan DELETE. Rahasia penandatanganan hanya ditampilkan satu kali.
Setiap permintaan membawa header berikut:
| Header | Deskripsi |
|---|---|
| Planitude-Signature | t=<unix seconds>,v1=<hex HMAC-SHA256>: see Verify signatures. |
| Planitude-Event | Event type, e.g. task.completed. |
| Planitude-Event-Id | Event id, the same in every retry: use it to deduplicate. |
| Planitude-Delivery | Id of this delivery (changes with a manual resend). |
| User-Agent | Planitude-Webhooks/1.0 (+https://planitude.app/developers) |
| Content-Type | application/json |
curl -X POST https://planitude.app/api/webhooks \
-H "Authorization: Bearer $PLANITUDE_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"url": "https://example.com/hooks/planitude",
"events": [
"task.created",
"task.completed"
],
"projectId": "40be00e0-7e34-4f7a-864b-5cc986f575b8"
}'const res = await fetch("https://planitude.app/api/webhooks", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.PLANITUDE_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
url: "https://example.com/hooks/planitude",
events: ["task.created", "task.completed"],
projectId: "40be00e0-7e34-4f7a-864b-5cc986f575b8",
}),
});
if (!res.ok) throw new Error(`${res.status} ${await res.text()}`);
console.log(await res.json());import os
import requests
res = requests.post(
"https://planitude.app/api/webhooks",
headers={"Authorization": f"Bearer {os.environ['PLANITUDE_API_KEY']}"},
json={
"url": "https://example.com/hooks/planitude",
"events": ["task.created", "task.completed"],
"projectId": "40be00e0-7e34-4f7a-864b-5cc986f575b8",
},
)
res.raise_for_status()
print(res.json()){
"webhook": {
"id": "1747ee7f-a395-4d3c-94b0-54b513d71d88",
"workspaceId": "824650d2-d0b3-4cac-8df8-5743ae9ff65a",
"workspaceName": "Acme Construction",
"projectId": "40be00e0-7e34-4f7a-864b-5cc986f575b8",
"projectName": "Warehouse expansion",
"name": "Warehouse sync",
"url": "https://example.com/hooks/planitude",
"events": [
"task.created",
"task.completed"
],
"secretPrefix": "whsec_Fdwl",
"active": true,
"disabledReason": null,
"disabledAt": null,
"consecutiveFailures": 0,
"viaApi": true,
"createdBy": {
"id": "b1666432-132a-4ea9-b1ae-76ea69e226c5",
"name": "Anna Rossi"
},
"createdAt": "2026-10-01T08:30:12.418Z",
"updatedAt": "2026-10-01T08:30:12.418Z",
"lastDeliveryAt": "2026-10-01T08:30:12.418Z",
"lastSuccessAt": "2026-10-01T08:30:12.418Z"
},
"secret": "whsec_3dvU0T1oaYlW4kH6m2Vb8nqXcR9eZpLsYw1QhGk"
}Jenis event
Berlangganan event tertentu, atau * untuk semuanya. Setiap event memiliki amplop yang sama; data berubah menurut tipenya.
| Event | Deskripsi |
|---|---|
| project.created | A project was created (blank, from a template, duplicated or imported from MS Project). |
| project.updated | Project fields changed (name, dates, deadline, archive...), or a saved version was restored. |
| project.deleted | A project was deleted. |
| task.created | A task was created. |
| task.updated | Task fields or assignees changed. changes lists only the fields that changed. |
| task.deleted | A task was deleted (one event per task of a deleted branch). |
| task.completed | Task progress reached 100%. |
| task.dates_changed | Start or finish moved, because of an edit (cause: edit) or because the schedule was recalculated (cause: reschedule). |
| dependency.created | A dependency was created or changed. |
| dependency.deleted | A dependency was removed. |
| baseline.saved | A baseline was saved. |
| member.invited | An invite link was created for the project. |
| member.joined | A person joined the project. |
| comment.created | A comment was added to a task. |
{
"id": "6f1c1d1e-2f4b-4d0a-9a77-2a3c5b1e9f10",
"type": "project.created",
"apiVersion": "2026-10-01",
"createdAt": "2026-10-01T08:30:12.418Z",
"workspaceId": "824650d2-d0b3-4cac-8df8-5743ae9ff65a",
"projectId": "40be00e0-7e34-4f7a-864b-5cc986f575b8",
"actor": {
"id": "b1666432-132a-4ea9-b1ae-76ea69e226c5",
"name": "Anna Rossi"
},
"data": {
"project": {
"id": "40be00e0-7e34-4f7a-864b-5cc986f575b8",
"workspaceId": "824650d2-d0b3-4cac-8df8-5743ae9ff65a",
"key": "WHX",
"name": "Warehouse expansion",
"description": null,
"startDate": "2026-10-05",
"deadline": null,
"currency": "EUR",
"scheduleFrom": "forward",
"color": null,
"archived": false,
"createdAt": "2026-10-01T08:30:12.418Z",
"updatedAt": "2026-10-01T08:30:12.418Z",
"url": "https://planitude.app/app/projects/40be00e0-7e34-4f7a-864b-5cc986f575b8"
},
"source": "blank"
}
}{
"id": "6f1c1d1e-2f4b-4d0a-9a77-2a3c5b1e9f10",
"type": "project.updated",
"apiVersion": "2026-10-01",
"createdAt": "2026-10-01T08:30:12.418Z",
"workspaceId": "824650d2-d0b3-4cac-8df8-5743ae9ff65a",
"projectId": "40be00e0-7e34-4f7a-864b-5cc986f575b8",
"actor": {
"id": "b1666432-132a-4ea9-b1ae-76ea69e226c5",
"name": "Anna Rossi"
},
"data": {
"project": {
"id": "40be00e0-7e34-4f7a-864b-5cc986f575b8",
"workspaceId": "824650d2-d0b3-4cac-8df8-5743ae9ff65a",
"key": "WHX",
"name": "Warehouse expansion",
"description": null,
"startDate": "2026-10-05",
"deadline": null,
"currency": "EUR",
"scheduleFrom": "forward",
"color": null,
"archived": false,
"createdAt": "2026-10-01T08:30:12.418Z",
"updatedAt": "2026-10-01T08:30:12.418Z",
"url": "https://planitude.app/app/projects/40be00e0-7e34-4f7a-864b-5cc986f575b8"
},
"changes": {
"deadline": {
"from": null,
"to": "2026-12-18"
}
},
"reason": "version_restored"
}
}{
"id": "6f1c1d1e-2f4b-4d0a-9a77-2a3c5b1e9f10",
"type": "project.deleted",
"apiVersion": "2026-10-01",
"createdAt": "2026-10-01T08:30:12.418Z",
"workspaceId": "824650d2-d0b3-4cac-8df8-5743ae9ff65a",
"projectId": "40be00e0-7e34-4f7a-864b-5cc986f575b8",
"actor": {
"id": "b1666432-132a-4ea9-b1ae-76ea69e226c5",
"name": "Anna Rossi"
},
"data": {
"project": {
"id": "40be00e0-7e34-4f7a-864b-5cc986f575b8",
"workspaceId": "824650d2-d0b3-4cac-8df8-5743ae9ff65a",
"key": "WHX",
"name": "Warehouse expansion",
"description": null,
"startDate": "2026-10-05",
"deadline": null,
"currency": "EUR",
"scheduleFrom": "forward",
"color": null,
"archived": false,
"createdAt": "2026-10-01T08:30:12.418Z",
"updatedAt": "2026-10-01T08:30:12.418Z",
"url": "https://planitude.app/app/projects/40be00e0-7e34-4f7a-864b-5cc986f575b8"
}
}
}{
"id": "6f1c1d1e-2f4b-4d0a-9a77-2a3c5b1e9f10",
"type": "task.created",
"apiVersion": "2026-10-01",
"createdAt": "2026-10-01T08:30:12.418Z",
"workspaceId": "824650d2-d0b3-4cac-8df8-5743ae9ff65a",
"projectId": "40be00e0-7e34-4f7a-864b-5cc986f575b8",
"actor": {
"id": "b1666432-132a-4ea9-b1ae-76ea69e226c5",
"name": "Anna Rossi"
},
"data": {
"task": {
"id": "4dbd104a-00cd-4035-8955-255f52ea586a",
"number": 1,
"key": "WHX-1",
"parentId": null,
"name": "Foundations",
"type": "task",
"durationMin": 1440,
"workMin": 0,
"progressPct": 0,
"constraintKind": "asap",
"constraintDate": null,
"deadline": null,
"calendarId": null,
"costFixed": 0,
"notes": null,
"color": null,
"wbs": null,
"externalId": "crm-4711",
"startAt": "2026-10-05T06:00:00.000Z",
"finishAt": "2026-10-07T15:00:00.000Z",
"isCritical": true,
"totalFloatMin": 0,
"earlyStartAt": "2026-10-05T06:00:00.000Z",
"lateFinishAt": "2026-10-07T15:00:00.000Z",
"actualStartAt": null,
"actualFinishAt": null,
"actualDurationMin": null,
"remainingDurationMin": null,
"manuallyScheduled": false,
"levelingDelayMin": 0,
"taskType": "fixed_units",
"effortDriven": false,
"durationOptimisticMin": null,
"durationPessimisticMin": null,
"projectId": "40be00e0-7e34-4f7a-864b-5cc986f575b8",
"completed": false,
"assignees": [
{
"resourceId": "0c6a8f52-3d7e-4b19-9a4e-6f1d2c8b7e30",
"userId": "b1666432-132a-4ea9-b1ae-76ea69e226c5",
"name": "Anna Rossi",
"unitsPct": 100
}
],
"url": "https://planitude.app/app/t/WHX-1"
}
}
}{
"id": "6f1c1d1e-2f4b-4d0a-9a77-2a3c5b1e9f10",
"type": "task.updated",
"apiVersion": "2026-10-01",
"createdAt": "2026-10-01T08:30:12.418Z",
"workspaceId": "824650d2-d0b3-4cac-8df8-5743ae9ff65a",
"projectId": "40be00e0-7e34-4f7a-864b-5cc986f575b8",
"actor": {
"id": "b1666432-132a-4ea9-b1ae-76ea69e226c5",
"name": "Anna Rossi"
},
"data": {
"task": {
"id": "4dbd104a-00cd-4035-8955-255f52ea586a",
"number": 1,
"key": "WHX-1",
"parentId": null,
"name": "Foundations",
"type": "task",
"durationMin": 1440,
"workMin": 0,
"progressPct": 0,
"constraintKind": "asap",
"constraintDate": null,
"deadline": null,
"calendarId": null,
"costFixed": 0,
"notes": null,
"color": null,
"wbs": null,
"externalId": "crm-4711",
"startAt": "2026-10-05T06:00:00.000Z",
"finishAt": "2026-10-07T15:00:00.000Z",
"isCritical": true,
"totalFloatMin": 0,
"earlyStartAt": "2026-10-05T06:00:00.000Z",
"lateFinishAt": "2026-10-07T15:00:00.000Z",
"actualStartAt": null,
"actualFinishAt": null,
"actualDurationMin": null,
"remainingDurationMin": null,
"manuallyScheduled": false,
"levelingDelayMin": 0,
"taskType": "fixed_units",
"effortDriven": false,
"durationOptimisticMin": null,
"durationPessimisticMin": null,
"projectId": "40be00e0-7e34-4f7a-864b-5cc986f575b8",
"completed": false,
"assignees": [
{
"resourceId": "0c6a8f52-3d7e-4b19-9a4e-6f1d2c8b7e30",
"userId": "b1666432-132a-4ea9-b1ae-76ea69e226c5",
"name": "Anna Rossi",
"unitsPct": 100
}
],
"url": "https://planitude.app/app/t/WHX-1"
},
"changes": {
"progressPct": {
"from": 40,
"to": 60
}
}
}
}{
"id": "6f1c1d1e-2f4b-4d0a-9a77-2a3c5b1e9f10",
"type": "task.deleted",
"apiVersion": "2026-10-01",
"createdAt": "2026-10-01T08:30:12.418Z",
"workspaceId": "824650d2-d0b3-4cac-8df8-5743ae9ff65a",
"projectId": "40be00e0-7e34-4f7a-864b-5cc986f575b8",
"actor": {
"id": "b1666432-132a-4ea9-b1ae-76ea69e226c5",
"name": "Anna Rossi"
},
"data": {
"task": {
"id": "4dbd104a-00cd-4035-8955-255f52ea586a",
"number": 1,
"key": "WHX-1",
"parentId": null,
"name": "Foundations",
"type": "task",
"durationMin": 1440,
"workMin": 0,
"progressPct": 0,
"constraintKind": "asap",
"constraintDate": null,
"deadline": null,
"calendarId": null,
"costFixed": 0,
"notes": null,
"color": null,
"wbs": null,
"externalId": "crm-4711",
"startAt": "2026-10-05T06:00:00.000Z",
"finishAt": "2026-10-07T15:00:00.000Z",
"isCritical": true,
"totalFloatMin": 0,
"earlyStartAt": "2026-10-05T06:00:00.000Z",
"lateFinishAt": "2026-10-07T15:00:00.000Z",
"actualStartAt": null,
"actualFinishAt": null,
"actualDurationMin": null,
"remainingDurationMin": null,
"manuallyScheduled": false,
"levelingDelayMin": 0,
"taskType": "fixed_units",
"effortDriven": false,
"durationOptimisticMin": null,
"durationPessimisticMin": null,
"projectId": "40be00e0-7e34-4f7a-864b-5cc986f575b8",
"completed": false,
"assignees": [
{
"resourceId": "0c6a8f52-3d7e-4b19-9a4e-6f1d2c8b7e30",
"userId": "b1666432-132a-4ea9-b1ae-76ea69e226c5",
"name": "Anna Rossi",
"unitsPct": 100
}
],
"url": "https://planitude.app/app/t/WHX-1"
}
}
}{
"id": "6f1c1d1e-2f4b-4d0a-9a77-2a3c5b1e9f10",
"type": "task.completed",
"apiVersion": "2026-10-01",
"createdAt": "2026-10-01T08:30:12.418Z",
"workspaceId": "824650d2-d0b3-4cac-8df8-5743ae9ff65a",
"projectId": "40be00e0-7e34-4f7a-864b-5cc986f575b8",
"actor": {
"id": "b1666432-132a-4ea9-b1ae-76ea69e226c5",
"name": "Anna Rossi"
},
"data": {
"task": {
"id": "4dbd104a-00cd-4035-8955-255f52ea586a",
"number": 1,
"key": "WHX-1",
"parentId": null,
"name": "Foundations",
"type": "task",
"durationMin": 1440,
"workMin": 0,
"progressPct": 100,
"constraintKind": "asap",
"constraintDate": null,
"deadline": null,
"calendarId": null,
"costFixed": 0,
"notes": null,
"color": null,
"wbs": null,
"externalId": "crm-4711",
"startAt": "2026-10-05T06:00:00.000Z",
"finishAt": "2026-10-07T15:00:00.000Z",
"isCritical": true,
"totalFloatMin": 0,
"earlyStartAt": "2026-10-05T06:00:00.000Z",
"lateFinishAt": "2026-10-07T15:00:00.000Z",
"actualStartAt": null,
"actualFinishAt": null,
"actualDurationMin": null,
"remainingDurationMin": null,
"manuallyScheduled": false,
"levelingDelayMin": 0,
"taskType": "fixed_units",
"effortDriven": false,
"durationOptimisticMin": null,
"durationPessimisticMin": null,
"projectId": "40be00e0-7e34-4f7a-864b-5cc986f575b8",
"completed": true,
"assignees": [
{
"resourceId": "0c6a8f52-3d7e-4b19-9a4e-6f1d2c8b7e30",
"userId": "b1666432-132a-4ea9-b1ae-76ea69e226c5",
"name": "Anna Rossi",
"unitsPct": 100
}
],
"url": "https://planitude.app/app/t/WHX-1"
}
}
}{
"id": "6f1c1d1e-2f4b-4d0a-9a77-2a3c5b1e9f10",
"type": "task.dates_changed",
"apiVersion": "2026-10-01",
"createdAt": "2026-10-01T08:30:12.418Z",
"workspaceId": "824650d2-d0b3-4cac-8df8-5743ae9ff65a",
"projectId": "40be00e0-7e34-4f7a-864b-5cc986f575b8",
"actor": {
"id": "b1666432-132a-4ea9-b1ae-76ea69e226c5",
"name": "Anna Rossi"
},
"data": {
"task": {
"id": "4dbd104a-00cd-4035-8955-255f52ea586a",
"number": 1,
"key": "WHX-1",
"parentId": null,
"name": "Foundations",
"type": "task",
"durationMin": 1440,
"workMin": 0,
"progressPct": 0,
"constraintKind": "asap",
"constraintDate": null,
"deadline": null,
"calendarId": null,
"costFixed": 0,
"notes": null,
"color": null,
"wbs": null,
"externalId": "crm-4711",
"startAt": "2026-10-05T06:00:00.000Z",
"finishAt": "2026-10-07T15:00:00.000Z",
"isCritical": true,
"totalFloatMin": 0,
"earlyStartAt": "2026-10-05T06:00:00.000Z",
"lateFinishAt": "2026-10-07T15:00:00.000Z",
"actualStartAt": null,
"actualFinishAt": null,
"actualDurationMin": null,
"remainingDurationMin": null,
"manuallyScheduled": false,
"levelingDelayMin": 0,
"taskType": "fixed_units",
"effortDriven": false,
"durationOptimisticMin": null,
"durationPessimisticMin": null,
"projectId": "40be00e0-7e34-4f7a-864b-5cc986f575b8",
"completed": false,
"assignees": [
{
"resourceId": "0c6a8f52-3d7e-4b19-9a4e-6f1d2c8b7e30",
"userId": "b1666432-132a-4ea9-b1ae-76ea69e226c5",
"name": "Anna Rossi",
"unitsPct": 100
}
],
"url": "https://planitude.app/app/t/WHX-1"
},
"cause": "reschedule",
"changes": {
"startAt": {
"from": "2026-10-02T06:00:00.000Z",
"to": "2026-10-05T06:00:00.000Z"
},
"finishAt": {
"from": "2026-10-06T15:00:00.000Z",
"to": "2026-10-07T15:00:00.000Z"
}
}
}
}{
"id": "6f1c1d1e-2f4b-4d0a-9a77-2a3c5b1e9f10",
"type": "dependency.created",
"apiVersion": "2026-10-01",
"createdAt": "2026-10-01T08:30:12.418Z",
"workspaceId": "824650d2-d0b3-4cac-8df8-5743ae9ff65a",
"projectId": "40be00e0-7e34-4f7a-864b-5cc986f575b8",
"actor": {
"id": "b1666432-132a-4ea9-b1ae-76ea69e226c5",
"name": "Anna Rossi"
},
"data": {
"dependency": {
"id": "9ba5faf8-923d-4ecc-86f0-f245c5d179db",
"predecessorId": "4dbd104a-00cd-4035-8955-255f52ea586a",
"successorId": "a22fd799-c4dc-4869-a466-0dd6e96f71ce",
"type": "FS",
"lagMin": 0
}
}
}{
"id": "6f1c1d1e-2f4b-4d0a-9a77-2a3c5b1e9f10",
"type": "dependency.deleted",
"apiVersion": "2026-10-01",
"createdAt": "2026-10-01T08:30:12.418Z",
"workspaceId": "824650d2-d0b3-4cac-8df8-5743ae9ff65a",
"projectId": "40be00e0-7e34-4f7a-864b-5cc986f575b8",
"actor": {
"id": "b1666432-132a-4ea9-b1ae-76ea69e226c5",
"name": "Anna Rossi"
},
"data": {
"dependency": {
"id": "9ba5faf8-923d-4ecc-86f0-f245c5d179db",
"predecessorId": "4dbd104a-00cd-4035-8955-255f52ea586a",
"successorId": "a22fd799-c4dc-4869-a466-0dd6e96f71ce",
"type": "FS",
"lagMin": 0
}
}
}{
"id": "6f1c1d1e-2f4b-4d0a-9a77-2a3c5b1e9f10",
"type": "baseline.saved",
"apiVersion": "2026-10-01",
"createdAt": "2026-10-01T08:30:12.418Z",
"workspaceId": "824650d2-d0b3-4cac-8df8-5743ae9ff65a",
"projectId": "40be00e0-7e34-4f7a-864b-5cc986f575b8",
"actor": {
"id": "b1666432-132a-4ea9-b1ae-76ea69e226c5",
"name": "Anna Rossi"
},
"data": {
"baseline": {
"id": "b5d68d05-0640-48f9-8eeb-ed7804f4a116",
"name": "Plan v1",
"index": null,
"capturedAt": "2026-10-01T08:30:12.418Z",
"capturedBy": "b1666432-132a-4ea9-b1ae-76ea69e226c5",
"taskCount": 12
}
}
}{
"id": "6f1c1d1e-2f4b-4d0a-9a77-2a3c5b1e9f10",
"type": "member.invited",
"apiVersion": "2026-10-01",
"createdAt": "2026-10-01T08:30:12.418Z",
"workspaceId": "824650d2-d0b3-4cac-8df8-5743ae9ff65a",
"projectId": "40be00e0-7e34-4f7a-864b-5cc986f575b8",
"actor": {
"id": "b1666432-132a-4ea9-b1ae-76ea69e226c5",
"name": "Anna Rossi"
},
"data": {
"invite": {
"id": "5d0b7c11-8e2a-4f63-a1d4-93c7e2b6f804",
"role": "editor",
"expiresAt": "2026-10-31T08:30:12.418Z",
"maxUses": null
}
}
}{
"id": "6f1c1d1e-2f4b-4d0a-9a77-2a3c5b1e9f10",
"type": "member.joined",
"apiVersion": "2026-10-01",
"createdAt": "2026-10-01T08:30:12.418Z",
"workspaceId": "824650d2-d0b3-4cac-8df8-5743ae9ff65a",
"projectId": "40be00e0-7e34-4f7a-864b-5cc986f575b8",
"actor": {
"id": "b1666432-132a-4ea9-b1ae-76ea69e226c5",
"name": "Anna Rossi"
},
"data": {
"member": {
"userId": "b1666432-132a-4ea9-b1ae-76ea69e226c5",
"name": "Anna Rossi",
"role": "editor"
}
}
}{
"id": "6f1c1d1e-2f4b-4d0a-9a77-2a3c5b1e9f10",
"type": "comment.created",
"apiVersion": "2026-10-01",
"createdAt": "2026-10-01T08:30:12.418Z",
"workspaceId": "824650d2-d0b3-4cac-8df8-5743ae9ff65a",
"projectId": "40be00e0-7e34-4f7a-864b-5cc986f575b8",
"actor": {
"id": "b1666432-132a-4ea9-b1ae-76ea69e226c5",
"name": "Anna Rossi"
},
"data": {
"comment": {
"id": "6f1c1d1e-2f4b-4d0a-9a77-2a3c5b1e9f10",
"taskId": "4dbd104a-00cd-4035-8955-255f52ea586a",
"body": "Concrete delivered, we can start the walls.",
"author": {
"id": "b1666432-132a-4ea9-b1ae-76ea69e226c5",
"name": "Anna Rossi"
},
"createdAt": "2026-10-01T08:30:12.418Z"
},
"task": {
"id": "4dbd104a-00cd-4035-8955-255f52ea586a",
"number": 1,
"key": "WHX-1",
"parentId": null,
"name": "Foundations",
"type": "task",
"durationMin": 1440,
"workMin": 0,
"progressPct": 0,
"constraintKind": "asap",
"constraintDate": null,
"deadline": null,
"calendarId": null,
"costFixed": 0,
"notes": null,
"color": null,
"wbs": null,
"externalId": "crm-4711",
"startAt": "2026-10-05T06:00:00.000Z",
"finishAt": "2026-10-07T15:00:00.000Z",
"isCritical": true,
"totalFloatMin": 0,
"earlyStartAt": "2026-10-05T06:00:00.000Z",
"lateFinishAt": "2026-10-07T15:00:00.000Z",
"actualStartAt": null,
"actualFinishAt": null,
"actualDurationMin": null,
"remainingDurationMin": null,
"manuallyScheduled": false,
"levelingDelayMin": 0,
"taskType": "fixed_units",
"effortDriven": false,
"durationOptimisticMin": null,
"durationPessimisticMin": null,
"projectId": "40be00e0-7e34-4f7a-864b-5cc986f575b8",
"completed": false,
"assignees": [
{
"resourceId": "0c6a8f52-3d7e-4b19-9a4e-6f1d2c8b7e30",
"userId": "b1666432-132a-4ea9-b1ae-76ea69e226c5",
"name": "Anna Rossi",
"unitsPct": 100
}
],
"url": "https://planitude.app/app/t/WHX-1"
}
}
}Verifikasi tanda tangan
Setiap permintaan ditandatangani dengan HMAC-SHA256 dan rahasia webhook Anda. Header Planitude-Signature berisi stempel waktu t dan tanda tangan v1, dihitung dari t, sebuah titik, dan isi mentah.
- Gunakan isi mentah, sebelum parsing JSON apa pun: isi yang diserialisasi ulang memiliki tanda tangan berbeda.
- Hitung HMAC dan bandingkan dalam waktu konstan.
- Tolak permintaan yang stempel waktunya berselisih lebih dari 5 menit dari jam Anda: permintaan yang tertangkap tidak dapat diputar ulang.
- Rotasikan rahasia kapan pun Anda mau: yang lama langsung berhenti berlaku.
import { createHmac, timingSafeEqual } from "node:crypto";
// rawBody: the request body as a string, before JSON.parse
export function verifyPlanitude(rawBody, header, secret, toleranceSec = 300) {
const parts = Object.fromEntries(header.split(",").map((p) => p.split("=")));
const t = Number(parts.t);
if (!t || Math.abs(Date.now() / 1000 - t) > toleranceSec) return false; // replay
const expected = createHmac("sha256", secret).update(`${t}.${rawBody}`).digest();
const given = Buffer.from(parts.v1 ?? "", "hex");
return given.length === expected.length && timingSafeEqual(given, expected);
}
// Express: app.post("/hooks/planitude", express.raw({ type: "application/json" }), (req, res) => {
// if (!verifyPlanitude(req.body.toString("utf8"), req.get("Planitude-Signature"), process.env.PLANITUDE_WEBHOOK_SECRET)) return res.sendStatus(400);
// res.sendStatus(200); // then process the event in a queue
// });import hashlib
import hmac
import time
def verify_planitude(raw_body: bytes, header: str, secret: str, tolerance: int = 300) -> bool:
parts = dict(p.split("=", 1) for p in header.split(","))
t = int(parts.get("t", "0"))
if abs(time.time() - t) > tolerance:
return False # replay
expected = hmac.new(secret.encode(), f"{t}.".encode() + raw_body, hashlib.sha256).hexdigest()
return hmac.compare_digest(expected, parts.get("v1", ""))
# Flask: verify_planitude(request.get_data(), request.headers["Planitude-Signature"], os.environ["PLANITUDE_WEBHOOK_SECRET"])Percobaan ulang dan pengiriman
Balas dengan 2xx apa pun dalam 10 detik, lalu kerjakan tugas sebenarnya setelahnya, dalam antrean. Pengalihan tidak diikuti. Jika terjadi galat dan waktu habis, Planitude mencoba hingga 6 kali secara total: segera, lalu setelah 1 min, 5 min, 30 min, 2 h, 12 h.
Pengiriman bersifat setidaknya sekali dan tidak berurutan. Simpan id event (Planitude-Event-Id, juga id di isi) dan lewati yang sudah Anda proses; urutkan berdasarkan createdAt.
Setelah 5 event berturut-turut gagal di setiap percobaan, webhook dinonaktifkan dan pemiliknya menerima email. Jawaban 410 Gone langsung menonaktifkannya. Aktifkan kembali dari profil, atau dengan PATCH dan active: true.
Log pengiriman (status, kode HTTP, cuplikan respons, payload, kirim ulang manual) disimpan selama 30 hari. Hanya alamat publik yang diterima sebagai tujuan.
Percobaan 1 segera
Percobaan 2 + 1 min
Percobaan 3 + 5 min
Percobaan 4 + 30 min
Percobaan 5 + 2 h
Percobaan 6 + 12 hUji endpoint Anda
- Kirim event
webhook.pingdengan endpoint pengujian, atau dengan tombol Uji di profil. - Untuk menerima event di komputer Anda, ekspos server lokal Anda dengan tunnel (misalnya ngrok atau Cloudflare Tunnel) dan berlangganan ke alamat HTTPS publiknya.
- Buka log pengiriman untuk melihat status, kode HTTP, dan respons, lalu kirim ulang pengiriman setelah endpoint Anda diperbaiki.
curl -X POST https://planitude.app/api/webhooks/1747ee7f-a395-4d3c-94b0-54b513d71d88/test \
-H "Authorization: Bearer $PLANITUDE_API_KEY"const res = await fetch("https://planitude.app/api/webhooks/1747ee7f-a395-4d3c-94b0-54b513d71d88/test", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.PLANITUDE_API_KEY}`,
},
});
if (!res.ok) throw new Error(`${res.status} ${await res.text()}`);
console.log(await res.json());import os
import requests
res = requests.post(
"https://planitude.app/api/webhooks/1747ee7f-a395-4d3c-94b0-54b513d71d88/test",
headers={"Authorization": f"Bearer {os.environ['PLANITUDE_API_KEY']}"},
)
res.raise_for_status()
print(res.json()){
"delivery": {
"id": "4b207161-80f9-40bb-bc3f-d8f70315be00",
"eventId": "6f1c1d1e-2f4b-4d0a-9a77-2a3c5b1e9f10",
"eventType": "task.completed",
"status": "success",
"attempts": 1,
"nextAttemptAt": null,
"lastAttemptAt": "2026-10-01T08:30:12.418Z",
"responseStatus": 200,
"responseExcerpt": "{\"ok\":true}",
"error": null,
"durationMs": 39,
"manual": false,
"createdAt": "2026-10-01T08:30:12.418Z"
}
}AI dan MCP
Server MCP
Planitude adalah server MCP (Model Context Protocol): asisten AI dan editor kode membaca proyek, menganalisis jalur kritis dan beban kerja, serta membuat atau mengubah tugas, sesuai izin Anda. Aplikasi web terhubung dengan OAuth (Anda masuk dan mengizinkan akses); alat baris perintah dan editor menggunakan kunci API.
URL server
https://planitude.app/mcp
- ChatGPTOAuth
Di ChatGPT buka Settings › Security and login dan aktifkan Developer mode. Buat aplikasi dengan URL server dan autentikasi OAuth, lalu masuk ke Planitude dan izinkan akses.
Dokumentasi resmi ↗ - ClaudeOAuth
Buka Customize › Connectors › Add custom connector, tempel URL server dan pilih Connect: Planitude terbuka, Anda masuk dan mengizinkan akses. Berfungsi di claude.ai, Claude Desktop, dan aplikasi seluler.
Dokumentasi resmi ↗ - GeminiOAuth
Di gemini.google.com buka Settings › Connected Apps, pilih Add a custom app dan tempel URL server; lalu masuk ke Planitude dan izinkan akses.
Dokumentasi resmi ↗ - Claude CodeKunci API
Jalankan perintah dengan kunci Anda di variabel lingkungan. Tambahkan
Dokumentasi resmi ↗--scope useragar berlaku di setiap proyek dan periksa denganclaude mcp list. - CodexKunci API
Taruh kunci di
Dokumentasi resmi ↗PLANITUDE_API_KEYdan tambahkan blok ke~/.codex/config.toml: berlaku untuk CLI, aplikasi, dan ekstensi IDE. - CursorKunci API
Tambahkan blok ke
Dokumentasi resmi ↗~/.cursor/mcp.json(semua proyek) atau.cursor/mcp.json(satu proyek); Cursor membaca kunci dari lingkungan. - Visual Studio CodeKunci API
Tambahkan
Dokumentasi resmi ↗.vscode/mcp.jsonke ruang kerja: VS Code meminta kunci sekali dan menyimpannya dengan aman, di luar file. - Gemini CLIKunci API
Jalankan perintah dengan kunci Anda di variabel lingkungan, atau tambahkan blok ke
Dokumentasi resmi ↗~/.gemini/settings.json.
Alat
Server menyediakan 29 alat, dari pembacaan dan analisis hingga perubahan yang aman. Tidak satu pun menghapus proyek atau tugas.
read
planitude_list_projectsplanitude_portfolio_overviewplanitude_get_projectplanitude_critical_pathplanitude_delay_impactplanitude_monte_carloplanitude_workloadplanitude_list_baselinesplanitude_list_versionsplanitude_list_templatesplanitude_list_commentsplanitude_preview_import
write
planitude_create_projectplanitude_create_project_from_templateplanitude_create_project_from_planplanitude_import_fileplanitude_edit_projectplanitude_add_taskplanitude_update_taskplanitude_set_progressplanitude_indent_taskplanitude_outdent_taskplanitude_link_tasksplanitude_unlink_tasksplanitude_rescheduleplanitude_configure_simulationplanitude_add_commentplanitude_save_baselineplanitude_save_version
Server URL
https://planitude.app/mcpServer URL
https://planitude.app/mcpServer URL
https://planitude.app/mcpTerminal
claude mcp add --transport http planitude https://planitude.app/mcp \
--header "Authorization: Bearer $PLANITUDE_API_KEY"~/.codex/config.toml
[mcp_servers.planitude]
url = "https://planitude.app/mcp"
bearer_token_env_var = "PLANITUDE_API_KEY"~/.cursor/mcp.json
{
"mcpServers": {
"planitude": {
"url": "https://planitude.app/mcp",
"headers": {
"Authorization": "Bearer ${env:PLANITUDE_API_KEY}"
}
}
}
}.vscode/mcp.json
{
"servers": {
"planitude": {
"type": "http",
"url": "https://planitude.app/mcp",
"headers": {
"Authorization": "Bearer ${input:planitude-key}"
}
}
},
"inputs": [
{
"id": "planitude-key",
"type": "promptString",
"description": "Planitude API key",
"password": true
}
]
}Terminal
gemini mcp add --transport http \
--header "Authorization: Bearer $PLANITUDE_API_KEY" planitude https://planitude.app/mcp~/.gemini/settings.json
{
"mcpServers": {
"planitude": {
"httpUrl": "https://planitude.app/mcp",
"headers": {
"Authorization": "Bearer $PLANITUDE_API_KEY"
}
}
}
}Integrasi siap pakai
Tanpa kode: integrasi ini memakai API dan webhook yang sama dan disiapkan hanya dengan beberapa klik.
- JiraTersediaSinkronisasi dua arah tugas, tanggal, dan dependensi dengan isu Jira.
- Azure DevOpsTersediaSinkronisasi dua arah dengan work item Azure DevOps Boards.
- SlackTersediaPembaruan proyek, ringkasan harian, dan perintah slash di kanal Anda.
- Microsoft TeamsTersediaPembaruan, ringkasan, dan tab Planitude di Microsoft Teams.
- Zapier, Make, n8nSegera hadirPemicu dan aksi instan pada tugas dan proyek untuk otomasi tanpa kode.
Catatan perubahan
Dokumentasi pengembang baru, dihasilkan dari dokumen OpenAPI. Dokumen OpenAPI kini menjelaskan setiap kolom yang dikembalikan untuk anggota, komentar, baseline, templat, dan penerima tugas.
API versi 2026-10-01: webhook keluar bertanda tangan, REST API publik terdokumentasi (OpenAPI 3.1), paginasi kursor, dan pencarian berdasarkan externalId.
OAuth 2.1 untuk server MCP dan API: ChatGPT, Claude, dan Gemini terhubung tanpa menyalin kunci.
Server MCP dan kunci API pribadi dengan akses baca atau baca + tulis.