---
title: "API Planitude, webhook-uri și MCP pentru dezvoltatori"
description: "API REST cu OpenAPI 3.1, webhook-uri semnate și un server MCP pentru asistenți AI: construiți pe Planitude, instrumentul online gratuit de management de proiect."
url: https://planitude.app/ro/developers
language: ro
---

# Construiți cu Planitude

Un API REST, webhook-uri semnate și un server MCP: păstrați sistemele sincronizate cu planul, reacționați la fiecare modificare și lăsați un asistent AI să lucreze la proiectele dvs.

*Codul, numele câmpurilor și referința tehnică sunt în engleză, ca în majoritatea documentațiilor API.*

- OpenAPI 3.1: https://planitude.app/api/openapi.json
- URL de bază: https://planitude.app
- MCP: https://planitude.app/mcp
- API version: 2026-10-01

- **Sincronizați sarcinile cu sistemele dvs.**: Creați proiecte și sarcini dintr-un CRM, un ERP sau un script, regăsiți-le după propriul id cu `externalId` și lăsați motorul de planificare să calculeze datele.
- **Reacționați la fiecare modificare**: Primiți o cerere HTTPS semnată când o sarcină este creată, finalizată sau mutată, indiferent dacă modificarea provine din aplicație, din API, dintr-un import sau de la un asistent AI.
- **Conectați un asistent AI**: ChatGPT, Claude, Gemini, Cursor și VS Code vă citesc planurile și propun modificări prin serverul MCP, cu permisiunile dvs. și nimic în plus.

Cererile și răspunsurile sunt JSON prin HTTPS. Duratele și decalajele sunt exprimate în **minute lucrătoare** (o zi de 8 ore înseamnă 480), momentele sunt ISO 8601 în UTC, iar datele fără oră au formatul `YYYY-MM-DD`.

## Început rapid

De la zero la primul webhook în trei pași. Aveți nevoie doar de un terminal.

### 1. Creați o cheie API

Deschideți [Profil → Chei API](https://planitude.app/ro/app/profile/api-keys), alegeți **Citire și scriere** și copiați cheia: începe cu `gnt_` și este afișată o singură dată. Păstrați-o într-o variabilă de mediu.

```bash
export PLANITUDE_API_KEY="gnt_…"
```

### 2. Faceți primul apel

Listați proiectele pe care le vedeți. Cheia acționează în numele dvs.: aceleași proiecte, aceleași roluri.

```bash
curl https://planitude.app/api/projects \
  -H "Authorization: Bearer $PLANITUDE_API_KEY"
```

Rezultat așteptat:

```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"
    }
  ]
}
```

### 3. Primiți un webhook

Abonați un endpoint HTTPS public la evenimentele de care aveți nevoie, apoi trimiteți imediat un eveniment de test și verificați semnătura acestuia.

```bash
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"
}'
```

```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"
      ]
    }
  }
}
```

## Autentificare

Autentificați fiecare cerere cu o cheie API personală în antetul `Authorization`, ca token bearer. Cheile sunt personale: acționează în numele dvs., cu rolul dvs. pe fiecare proiect, niciodată mai mult. Puteți limita o cheie la un singur spațiu de lucru, îi puteți seta o dată de expirare și o puteți revoca oricând; fiecare apel este înregistrat alături de cheie.

| Domeniu | Permite |
| --- | --- |
| `read` (`planitude:read`) | Citirea proiectelor, sarcinilor, dependențelor, membrilor, comentariilor, liniilor de bază și webhook-urilor. |
| `write` (`planitude:write`) | Tot ce include citirea, plus crearea și modificarea proiectelor, sarcinilor, dependențelor, comentariilor, liniilor de bază și webhook-urilor. |

Cheile și aplicațiile OAuth **nu pot șterge** proiecte sau sarcini: ștergerea rămâne în aplicația web, unde o confirmă o persoană. Un script care vizează un id greșit nu poate șterge un plan.

### OAuth 2.1 pentru aplicații terțe

Aplicațiile care acționează în numele altor persoane folosesc OAuth 2.1: cod de autorizare cu PKCE (S256), refresh token-uri rotite la fiecare utilizare, înregistrare dinamică a clienților (RFC 7591). Solicitați resursa `https://planitude.app/api` și domeniul `planitude:read` sau `planitude:write`.

Endpoint-urile sunt publicate în documentele standard de descoperire, astfel încât bibliotecile OAuth se configurează singure.

```json
{
  "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"
  ]
}
```

### Bune practici

- Păstrați cheile în variabile de mediu sau într-un manager de secrete, niciodată în cod sau într-un depozit. Cheile încep cu `gnt_`, astfel încât scanerele de secrete să le poată detecta.
- Folosiți o cheie doar pentru citire atunci când doar citiți și câte o cheie pentru fiecare integrare: puteți revoca una fără a le opri pe celelalte.
- Setați o dată de expirare cheilor folosite de scripturi și rotiți-le.
- Apelați API-ul de pe serverul dvs., nu din browser: o cheie din codul front-end este o cheie publică.

## Erori

Planitude folosește coduri de stare HTTP standard. Erorile au întotdeauna aceeași structură JSON: un cod `error` stabil pe care să vă bazați logica și, când este util, `details` cu motivul sau câmpurile de corectat.

| Stare | error | Semnificație |
| --- | --- | --- |
| 400 | `invalid_request` | Cererea nu este validă: `details.fields` listează fiecare câmp și problema. |
| 401 | `unauthorized` | Cheia lipsește, este invalidă, revocată sau expirată. |
| 403 | `forbidden` | Cheia sau rolul dvs. nu permite acest lucru (`details.reason`), de exemplu o scriere cu o cheie doar pentru citire sau o ștergere. |
| 404 | `not_found` | Nu a fost găsit sau nu este vizibil pentru dvs. |
| 409 | `dependency_cycle` | Conflict cu planul, de exemplu o dependență care ar închide un ciclu (`dependency_cycle`). |
| 429 | `rate_limited` | Prea multe cereri: așteptați numărul de secunde din `Retry-After`. |
| 500 | `server_error` | A apărut o problemă din partea noastră: reîncercați cu exponential backoff. |

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `error` | string | yes | Stable error code: invalid_request, unauthorized, forbidden, not_found, conflict, dependency_cycle, limit_exceeded, rate_limited, server_error, ... |
| `details` | object |  |  |

```json
HTTP 400
{
  "error": "invalid_request",
  "details": {
    "fields": [
      {
        "path": "name",
        "message": "Invalid input: expected string, received undefined"
      },
      {
        "path": "durationMin",
        "message": "Too small: expected number to be >=0"
      }
    ]
  }
}
```

```json
HTTP 403
{
  "error": "forbidden",
  "details": {
    "reason": "destructive"
  }
}
```

```json
HTTP 409
{
  "error": "dependency_cycle",
  "details": {
    "cycles": [
      {
        "path": "Foundations -> Walls -> Foundations",
        "taskIds": [
          "4dbd104a-00cd-4035-8955-255f52ea586a",
          "a22fd799-c4dc-4869-a466-0dd6e96f71ce"
        ],
        "taskNames": [
          "Foundations",
          "Walls"
        ]
      }
    ]
  }
}
```

## Limite de rată

Limitele se aplică per cheie, într-o fereastră glisantă de un minut: **240** cereri de citire și **60** cereri de scriere. La depășire primiți `429 rate_limited` cu un antet `Retry-After`, în secunde.

Așteptați `Retry-After` înainte de a reîncerca, eșalonați în timp operațiunile în masă și grupați mai multe modificări într-un set de modificări: până la 1.000 modificări într-o singură cerere și o singură recalculare.

```http
HTTP/1.1 429 Too Many Requests
Retry-After: 12
Content-Type: application/json

{
  "error": "rate_limited",
  "details": {
    "retryAfterSec": 12
  }
}
```

## Paginare și căutare

Listele de sarcini sunt paginate cu un cursor. Transmiteți `limit` (1–500, implicit 100) și, pentru pagina următoare, `nextCursor` din răspunsul anterior ca `cursor`. Când `nextCursor` este `null`, nu mai există pagini.

Filtrați cu `externalId` (potrivire exactă cu propriul id), `q` (numele conține), `updatedSince` și `completed`; sortați cu `sort=-number` (cele mai noi primele) sau `-updatedAt`. Listele mai scurte, precum proiectele, membrii și dependențele, sunt returnate integral într-un singur răspuns.

```js
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);
```

## Versionare

API-ul și payload-urile webhook sunt versionate după dată. Versiunea curentă este `2026-10-01`: este câmpul `apiVersion` al fiecărui eveniment și `info.version` din documentul OpenAPI.

În cadrul unei versiuni doar adăugăm: endpoint-uri noi, câmpuri opționale noi, tipuri de evenimente noi. Câmpurile nu sunt niciodată eliminate sau retipizate fără o versiune nouă, așa că ignorați câmpurile pe care nu le cunoașteți.

## Referință API

Every request: `Authorization: Bearer $PLANITUDE_API_KEY`. Examples use the same project (`WHX`), task and person throughout.

### Account

Who is calling, and their workspaces.

#### User object

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `id` | string (uuid) |  |  |
| `email` | string (email) |  |  |
| `name` | string, nullable |  |  |
| `avatarUrl` | string, nullable |  |  |
| `locale` | string |  |  |
| `emailVerified` | boolean |  |  |

```json
{
  "id": "b1666432-132a-4ea9-b1ae-76ea69e226c5",
  "email": "anna@example.com",
  "name": "Anna Rossi",
  "avatarUrl": null,
  "locale": "en",
  "emailVerified": true
}
```

#### Workspace object

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `id` | string (uuid) |  |  |
| `name` | string |  |  |
| `role` | string |  | One of: `owner`, `admin`, `member`. |

```json
{
  "id": "824650d2-d0b3-4cac-8df8-5743ae9ff65a",
  "name": "Acme Construction",
  "role": "owner"
}
```

#### Current user (connection test)

`GET /api/auth/me` (scope: read)

```bash
curl https://planitude.app/api/auth/me \
  -H "Authorization: Bearer $PLANITUDE_API_KEY"
```

Returnează 200 OK: The user

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `user` | User |  |  |

```json
{
  "user": {
    "id": "b1666432-132a-4ea9-b1ae-76ea69e226c5",
    "email": "anna@example.com",
    "name": "Anna Rossi",
    "avatarUrl": null,
    "locale": "en",
    "emailVerified": true
  }
}
```

#### Workspaces of the user, with role

`GET /api/workspaces` (scope: read)

```bash
curl https://planitude.app/api/workspaces \
  -H "Authorization: Bearer $PLANITUDE_API_KEY"
```

Returnează 200 OK: Workspaces

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `workspaces` | array of Workspace |  |  |

```json
{
  "workspaces": [
    {
      "id": "824650d2-d0b3-4cac-8df8-5743ae9ff65a",
      "name": "Acme Construction",
      "role": "owner"
    }
  ]
}
```

### Projects

Projects, templates and baselines.

#### Project object

A project as returned by the write endpoints and project listings.

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `id` | string (uuid) |  |  |
| `workspaceId` | string (uuid) |  |  |
| `key` | string |  | Project key, e.g. `CRON` (task keys are `CRON-12`). |
| `keyLocked` | boolean |  |  |
| `name` | string |  |  |
| `description` | string, nullable |  |  |
| `startDate` | string (date) |  |  |
| `calendarId` | string (uuid), nullable |  |  |
| `currency` | string |  |  |
| `scheduleFrom` | string |  | One of: `forward`, `backward`. |
| `deadline` | string (date), nullable |  |  |
| `color` | string, nullable |  |  |
| `settings` | object |  |  |
| `archivedAt` | string (date-time), nullable |  |  |
| `createdBy` | string (uuid), nullable |  |  |
| `createdAt` | string (date-time) |  |  |
| `updatedAt` | string (date-time) |  |  |

```json
{
  "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 object

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `id` | string |  | `builtin:<slug>` or the id of a template saved by you. |
| `kind` | string |  | One of: `builtin`, `user`. |
| `name` | string |  |  |
| `description` | string, nullable |  |  |
| `taskCount` | integer |  |  |
| `durationDays` | integer |  | Working days from start to finish. |

```json
{
  "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 object

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `id` | string (uuid) |  |  |
| `name` | string |  |  |
| `index` | integer, nullable |  | 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 |  |  |

```json
{
  "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` (scope: read)

All projects visible to the user (not paginated). `?archived=1` includes archived ones.

Parametri de interogare:

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `archived` | string |  | One of: `1`. |

```bash
curl https://planitude.app/api/projects \
  -H "Authorization: Bearer $PLANITUDE_API_KEY"
```

Returnează 200 OK: Projects

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `projects` | array of Project |  |  |

```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` (scope: write)

Corpul cererii:

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `name` | string | yes |  |
| `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` | string, nullable |  |  |
| `startDate` | string (date) |  |  |
| `deadline` | string (date), nullable |  |  |
| `currency` | string |  |  |
| `scheduleFrom` | string |  | One of: `forward`, `backward`. |
| `color` | string, nullable |  |  |

```bash
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"}'
```

Returnează 201 Created: Created

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `project` | Project |  |  |

```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` (scope: write)

Corpul cererii:

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `templateId` | string | yes | Id from `GET /api/templates`. |
| `startDate` | string (date) | yes |  |
| `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) |  |  |

```bash
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"
}'
```

Returnează 201 Created: Created

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `project` | Project |  |  |
| `taskCount` | integer |  |  |
| `conflicts` | array of Conflict |  |  |

```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` (scope: read)

Parametri de interogare:

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `locale` | string |  |  |

```bash
curl https://planitude.app/api/templates \
  -H "Authorization: Bearer $PLANITUDE_API_KEY"
```

Returnează 200 OK: Templates

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `templates` | array of Template |  |  |

```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}` (scope: read)

Parametri de cale:

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `projectId` | string (uuid) | yes | Project id. |

```bash
curl https://planitude.app/api/projects/40be00e0-7e34-4f7a-864b-5cc986f575b8 \
  -H "Authorization: Bearer $PLANITUDE_API_KEY"
```

Returnează 200 OK: Project

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `project` | Project |  |  |
| `tasks` | array of Task |  |  |
| `dependencies` | array of Dependency |  |  |

```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}` (scope: write)

Parametri de cale:

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `projectId` | string (uuid) | yes | Project id. |

Corpul cererii:

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `name` | string |  |  |
| `description` | string, nullable |  |  |
| `startDate` | string (date) |  |  |
| `deadline` | string (date), nullable |  |  |
| `currency` | string |  |  |
| `scheduleFrom` | string |  | One of: `forward`, `backward`. |
| `color` | string, nullable |  |  |
| `archived` | boolean |  |  |

```bash
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"}'
```

Returnează 200 OK: Updated

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `project` | Project |  |  |
| `conflicts` | array of Conflict |  |  |
| `rescheduled` | boolean |  | The schedule was recalculated (start date, calendar or direction changed). |

```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` (scope: read)

Parametri de cale:

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `projectId` | string (uuid) | yes | Project id. |

```bash
curl https://planitude.app/api/projects/40be00e0-7e34-4f7a-864b-5cc986f575b8/baseline \
  -H "Authorization: Bearer $PLANITUDE_API_KEY"
```

Returnează 200 OK: Baselines

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `baselines` | array of Baseline |  |  |

```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` (scope: write)

Parametri de cale:

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `projectId` | string (uuid) | yes | Project id. |

Corpul cererii:

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `name` | string |  |  |

```bash
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"}'
```

Returnează 201 Created: Saved

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `baseline` | Baseline |  |  |

```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
  }
}
```

### Tasks

Tasks, search by external id, comments.

#### Task object

Task representation of `GET /tasks` and webhook payloads: the stored task (without `sortKey`) plus project, assignees and link.

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `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 |  | One of: `summary`, `task`, `milestone`. |
| `durationMin` | integer |  | Duration in working minutes (8h day = 480). |
| `workMin` | integer |  |  |
| `progressPct` | number |  |  |
| `constraintKind` | string |  | One of: `asap`, `alap`, `start_no_earlier_than`, `start_no_later_than`, `finish_no_earlier_than`, `finish_no_later_than`, `must_start_on`, `must_finish_on`. |
| `constraintDate` | string (date-time), nullable |  |  |
| `deadline` | string (date-time), nullable |  |  |
| `calendarId` | string (uuid), nullable |  |  |
| `costFixed` | number |  |  |
| `notes` | string, nullable |  |  |
| `color` | string, nullable |  |  |
| `wbs` | string, nullable |  |  |
| `externalId` | string, nullable |  | 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` | integer, nullable |  | 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` | integer, nullable |  |  |
| `remainingDurationMin` | integer, nullable |  |  |
| `manuallyScheduled` | boolean |  |  |
| `levelingDelayMin` | integer |  |  |
| `taskType` | string |  | One of: `fixed_units`, `fixed_duration`, `fixed_work`, `fixed_duration_and_units`. |
| `effortDriven` | boolean |  |  |
| `durationOptimisticMin` | integer, nullable |  |  |
| `durationPessimisticMin` | integer, nullable |  |  |
| `projectId` | string (uuid) |  |  |
| `completed` | boolean |  | progressPct = 100. |
| `assignees` | array of Assignee |  |  |
| `url` | string (uri) |  | Page of the task in the web app. |

```json
{
  "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 object

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `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 |  |  |
| `stats.taskCount` | integer |  |  |
| `stats.recomputedCount` | integer |  | Tasks the scheduling engine recalculated. |
| `stats.savedCount` | integer |  | Tasks whose stored values changed. |
| `stats.durationMs` | integer |  |  |

```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
  }
}
```

#### Comment object

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `id` | string (uuid) |  |  |
| `taskId` | string (uuid) |  |  |
| `userId` | string (uuid) |  |  |
| `authorName` | string |  |  |
| `authorAvatarUrl` | string, nullable |  |  |
| `body` | string |  |  |
| `mentions` | array of string |  |  |
| `createdAt` | string (date-time) |  |  |
| `editedAt` | string (date-time), nullable |  |  |

```json
{
  "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` (scope: read)

Parametri de cale:

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `projectId` | string (uuid) | yes | Project id. |

Parametri de interogare:

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `limit` | integer |  | 1-500. Default: `100`. |
| `cursor` | string |  | `nextCursor` of the previous page. |
| `sort` | string |  | `-number` = newest first (polling triggers). `-updatedAt` returns the first page only. One of: `number`, `-number`, `-updatedAt`. Default: `number`. |
| `externalId` | string |  | Exact match on `externalId`. |
| `q` | string |  | Name contains (case-insensitive). |
| `updatedSince` | string (date-time) |  |  |
| `completed` | string |  | One of: `true`, `false`. |

```bash
curl "https://planitude.app/api/projects/40be00e0-7e34-4f7a-864b-5cc986f575b8/tasks?externalId=crm-4711" \
  -H "Authorization: Bearer $PLANITUDE_API_KEY"
```

Returnează 200 OK: A page of tasks

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `tasks` | array of Task |  |  |
| `nextCursor` | string, nullable |  |  |

```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` (scope: write)

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.

Parametri de cale:

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `projectId` | string (uuid) | yes | Project id. |

Corpul cererii (`TaskCreate`):

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `name` | string | yes |  |
| `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 |  | One of: `summary`, `task`, `milestone`. |
| `durationMin` | integer |  | Duration in working minutes (8h day = 480). |
| `workMin` | integer |  |  |
| `progressPct` | number |  |  |
| `constraintKind` | string |  | One of: `asap`, `alap`, `start_no_earlier_than`, `start_no_later_than`, `finish_no_earlier_than`, `finish_no_later_than`, `must_start_on`, `must_finish_on`. |
| `constraintDate` | string (date-time), nullable |  |  |
| `deadline` | string (date-time), nullable |  |  |
| `calendarId` | string (uuid), nullable |  |  |
| `costFixed` | number |  |  |
| `notes` | string, nullable |  |  |
| `color` | string, nullable |  |  |
| `wbs` | string, nullable |  |  |
| `externalId` | string, nullable |  | Your identifier for this task in another system. Searchable with `GET /tasks?externalId=`. |

Corpul cererii (sau `ChangeSet`):

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `createTasks` | array of TaskCreate |  |  |
| `updateTasks` | array of any |  |  |
| `createDependencies` | array of DependencyCreate |  |  |
| `deleteDependencyIds` | array of string |  |  |
| `fullReschedule` | boolean |  |  |

```bash
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"}'
```

Returnează 201 Created: Task created

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `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 |  |  |
| `stats.taskCount` | integer |  |  |
| `stats.recomputedCount` | integer |  | Tasks the scheduling engine recalculated. |
| `stats.savedCount` | integer |  | Tasks whose stored values changed. |
| `stats.durationMs` | integer |  |  |

```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}` (scope: read)

Parametri de cale:

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `projectId` | string (uuid) | yes | Project id. |
| `taskId` | string (uuid) | yes | Task id. |

```bash
curl https://planitude.app/api/projects/40be00e0-7e34-4f7a-864b-5cc986f575b8/tasks/4dbd104a-00cd-4035-8955-255f52ea586a \
  -H "Authorization: Bearer $PLANITUDE_API_KEY"
```

Returnează 200 OK: The task

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `task` | Task |  |  |

```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}` (scope: write)

Only the fields you send change; `null` clears a field.

Parametri de cale:

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `projectId` | string (uuid) | yes | Project id. |
| `taskId` | string (uuid) | yes | Task id. |

Corpul cererii:

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `name` | string |  |  |
| `type` | string |  | One of: `summary`, `task`, `milestone`. |
| `durationMin` | integer |  | Duration in working minutes (8h day = 480). |
| `workMin` | integer |  |  |
| `progressPct` | number |  |  |
| `constraintKind` | string |  | One of: `asap`, `alap`, `start_no_earlier_than`, `start_no_later_than`, `finish_no_earlier_than`, `finish_no_later_than`, `must_start_on`, `must_finish_on`. |
| `constraintDate` | string (date-time), nullable |  |  |
| `deadline` | string (date-time), nullable |  |  |
| `calendarId` | string (uuid), nullable |  |  |
| `costFixed` | number |  |  |
| `notes` | string, nullable |  |  |
| `color` | string, nullable |  |  |
| `wbs` | string, nullable |  |  |
| `externalId` | string, nullable |  | Your identifier for this task in another system. Searchable with `GET /tasks?externalId=`. |
| `placement` | object |  |  |
| `placement.parentId` | string (uuid), nullable |  | Parent (summary) task; null = top level. |
| `placement.afterTaskId` | string (uuid), nullable |  | Insert after this sibling. |
| `placement.beforeTaskId` | string (uuid), nullable |  | Insert before this sibling. |

```bash
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}'
```

Returnează 200 OK: Updated

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `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 |  |  |
| `stats.taskCount` | integer |  |  |
| `stats.recomputedCount` | integer |  | Tasks the scheduling engine recalculated. |
| `stats.savedCount` | integer |  | Tasks whose stored values changed. |
| `stats.durationMs` | integer |  |  |

```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` (scope: read)

Parametri de cale:

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `projectId` | string (uuid) | yes | Project id. |
| `taskId` | string (uuid) | yes | Task id. |

```bash
curl https://planitude.app/api/projects/40be00e0-7e34-4f7a-864b-5cc986f575b8/tasks/4dbd104a-00cd-4035-8955-255f52ea586a/comments \
  -H "Authorization: Bearer $PLANITUDE_API_KEY"
```

Returnează 200 OK: Comments

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `comments` | array of Comment |  |  |

```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` (scope: write)

Parametri de cale:

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `projectId` | string (uuid) | yes | Project id. |
| `taskId` | string (uuid) | yes | Task id. |

Corpul cererii:

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `body` | string | yes | Plain text. |
| `mentions` | array of string |  | User ids to notify. |

```bash
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."}'
```

Returnează 201 Created: Created

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `comment` | Comment |  |  |

```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
  }
}
```

### Dependencies

Links between tasks (FS, SS, FF, SF, with lag).

#### Dependency object

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `id` | string (uuid) |  |  |
| `predecessorId` | string (uuid) |  |  |
| `successorId` | string (uuid) |  |  |
| `type` | string |  | One of: `FS`, `SS`, `FF`, `SF`. |
| `lagMin` | integer |  | Working minutes; negative = lead. |

```json
{
  "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` (scope: read)

Parametri de cale:

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `projectId` | string (uuid) | yes | Project id. |

```bash
curl https://planitude.app/api/projects/40be00e0-7e34-4f7a-864b-5cc986f575b8/dependencies \
  -H "Authorization: Bearer $PLANITUDE_API_KEY"
```

Returnează 200 OK: Dependencies

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `dependencies` | array of Dependency |  |  |

```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` (scope: write)

A dependency that would close a cycle is refused with `409 dependency_cycle`.

Parametri de cale:

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `projectId` | string (uuid) | yes | Project id. |

Corpul cererii (`DependencyCreate`):

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `predecessorId` | string (uuid) | yes |  |
| `successorId` | string (uuid) | yes |  |
| `type` | string |  | One of: `FS`, `SS`, `FF`, `SF`. Default: `FS`. |
| `lagMin` | integer |  | Default: `0`. |

Corpul cererii (sau `dependencies`):

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `dependencies` | array of DependencyCreate | yes |  |

```bash
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
}'
```

Returnează 201 Created: Created

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `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 |  |  |
| `stats.taskCount` | integer |  |  |
| `stats.recomputedCount` | integer |  | Tasks the scheduling engine recalculated. |
| `stats.savedCount` | integer |  | Tasks whose stored values changed. |
| `stats.durationMs` | integer |  |  |

```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

`DELETE /api/projects/{projectId}/dependencies/{dependencyId}` (scope: write)

Parametri de cale:

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `projectId` | string (uuid) | yes | Project id. |
| `dependencyId` | string (uuid) | yes |  |

```bash
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"
```

Returnează 200 OK: Removed

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `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 |  |  |
| `stats.taskCount` | integer |  |  |
| `stats.recomputedCount` | integer |  | Tasks the scheduling engine recalculated. |
| `stats.savedCount` | integer |  | Tasks whose stored values changed. |
| `stats.durationMs` | integer |  |  |

```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
  }
}
```

### People

Project members and task assignees.

#### Member object

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `userId` | string (uuid) |  |  |
| `name` | string |  |  |
| `email` | string |  |  |
| `role` | string |  | Effective role on the project. One of: `owner`, `editor`, `viewer`. |
| `directRole` | string, nullable |  | Role granted on the project itself (null = only through the workspace). One of: `owner`, `editor`, `viewer`. |
| `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` | string, nullable |  |  |

```json
{
  "userId": "b1666432-132a-4ea9-b1ae-76ea69e226c5",
  "name": "Anna Rossi",
  "email": "anna@example.com",
  "role": "owner",
  "directRole": null,
  "inherited": false,
  "resourceId": "0c6a8f52-3d7e-4b19-9a4e-6f1d2c8b7e30",
  "addedAt": "2026-10-01T08:30:12.418Z",
  "avatarUrl": null
}
```

#### Assignee object

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `resourceId` | string (uuid) |  |  |
| `userId` | string (uuid), nullable |  |  |
| `name` | string |  |  |
| `unitsPct` | integer |  |  |

```json
{
  "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` (scope: write)

`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.

Parametri de cale:

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `projectId` | string (uuid) | yes | Project id. |
| `taskId` | string (uuid) | yes | Task id. |

Corpul cererii:

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `userIds` | array of string | yes |  |
| `resourceIds` | array of string |  |  |

```bash
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"]}'
```

Returnează 200 OK: Assignees saved

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `taskId` | string (uuid) |  |  |
| `assignments` | array of object |  |  |
| `assignments.id` | string (uuid) |  |  |
| `assignments.taskId` | string (uuid) |  |  |
| `assignments.resourceId` | string (uuid) |  |  |
| `assignments.unitsPct` | integer |  |  |
| `assignments.workMin` | integer |  |  |
| `resources` | array of object |  |  |
| `resources.id` | string (uuid) |  |  |
| `resources.userId` | string (uuid), nullable |  |  |
| `resources.name` | string |  |  |
| `resources.kind` | string |  | One of: `work`, `material`, `cost`. |
| `resources.email` | string, nullable |  |  |
| `resources.costPerHour` | number |  |  |
| `resources.costPerUse` | number |  |  |
| `resources.capacityPct` | integer |  |  |
| `resources.calendarId` | string (uuid), nullable |  |  |
| `resources.color` | string, nullable |  |  |
| `resources.avatarUrl` | string, nullable |  |  |
| `needsReschedule` | boolean |  |  |
| `conflicts` | array of Conflict |  |  |

```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": "anna@example.com",
      "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` (scope: read)

Parametri de cale:

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `projectId` | string (uuid) | yes | Project id. |

```bash
curl https://planitude.app/api/projects/40be00e0-7e34-4f7a-864b-5cc986f575b8/members \
  -H "Authorization: Bearer $PLANITUDE_API_KEY"
```

Returnează 200 OK: Members

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `members` | array of Member |  |  |
| `role` | string |  |  |

```json
{
  "members": [
    {
      "userId": "b1666432-132a-4ea9-b1ae-76ea69e226c5",
      "name": "Anna Rossi",
      "email": "anna@example.com",
      "role": "owner",
      "directRole": null,
      "inherited": false,
      "resourceId": "0c6a8f52-3d7e-4b19-9a4e-6f1d2c8b7e30",
      "addedAt": "2026-10-01T08:30:12.418Z",
      "avatarUrl": null
    }
  ],
  "role": "owner"
}
```

### Webhooks

Outgoing webhook subscriptions (REST hooks: subscribe/unsubscribe).

#### Webhook object

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `id` | string (uuid) |  |  |
| `workspaceId` | string (uuid) |  |  |
| `workspaceName` | string |  |  |
| `projectId` | string (uuid), nullable |  | null = every project of the workspace. |
| `projectName` | string, nullable |  |  |
| `name` | string |  |  |
| `url` | string (uri) |  |  |
| `events` | array of string |  | One of: `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`. |
| `secretPrefix` | string |  | First characters of the signing secret (not secret). |
| `active` | boolean |  |  |
| `disabledReason` | string, nullable |  | One of: `failures`, `gone`, `project_deleted`, `user`. |
| `disabledAt` | string (date-time), nullable |  |  |
| `consecutiveFailures` | integer |  |  |
| `viaApi` | boolean |  | Created with the API (REST hook) rather than from the profile. |
| `createdBy` | object, nullable |  |  |
| `createdBy.id` | string (uuid) |  |  |
| `createdBy.name` | string, nullable |  |  |
| `createdAt` | string (date-time) |  |  |
| `updatedAt` | string (date-time) |  |  |
| `lastDeliveryAt` | string (date-time), nullable |  |  |
| `lastSuccessAt` | string (date-time), nullable |  |  |

```json
{
  "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 object

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `id` | string (uuid) |  |  |
| `eventId` | string (uuid) |  |  |
| `eventType` | string |  |  |
| `status` | string |  | One of: `pending`, `success`, `failed`, `cancelled`. |
| `attempts` | integer |  |  |
| `nextAttemptAt` | string (date-time), nullable |  |  |
| `lastAttemptAt` | string (date-time), nullable |  |  |
| `responseStatus` | integer, nullable |  |  |
| `responseExcerpt` | string, nullable |  |  |
| `error` | string, nullable |  |  |
| `durationMs` | integer, nullable |  |  |
| `manual` | boolean |  |  |
| `createdAt` | string (date-time) |  |  |

```json
{
  "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 object

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `id` | string (uuid) | yes | Event id, also in the `Planitude-Event-Id` header: use it to deduplicate. |
| `type` | string | yes | One of: `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`, `webhook.ping`. |
| `apiVersion` | string | yes | One of: `2026-10-01`. |
| `createdAt` | string (date-time) | yes |  |
| `workspaceId` | string (uuid) | yes |  |
| `projectId` | string (uuid), nullable |  |  |
| `actor` | object, nullable |  | Who made the change (null for system changes). |
| `actor.id` | string (uuid) |  |  |
| `actor.name` | string, nullable |  |  |
| `data` | object | yes |  |

```json
{
  "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) object

Compact project representation used in webhook payloads.

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `id` | string (uuid) |  |  |
| `workspaceId` | string (uuid) |  |  |
| `key` | string |  |  |
| `name` | string |  |  |
| `description` | string, nullable |  |  |
| `startDate` | string (date) |  |  |
| `deadline` | string (date), nullable |  |  |
| `currency` | string |  |  |
| `scheduleFrom` | string |  | One of: `forward`, `backward`. |
| `color` | string, nullable |  |  |
| `archived` | boolean |  |  |
| `createdAt` | string (date-time) |  |  |
| `updatedAt` | string (date-time) |  |  |
| `url` | string (uri) |  |  |

```json
{
  "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` (scope: read)

Parametri de interogare:

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `workspaceId` | string (uuid) |  |  |
| `projectId` | string (uuid) |  |  |

```bash
curl https://planitude.app/api/webhooks \
  -H "Authorization: Bearer $PLANITUDE_API_KEY"
```

Returnează 200 OK: Subscriptions

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `webhooks` | array of Webhook |  |  |

```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` (scope: write)

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.

Corpul cererii:

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `url` | string (uri) | yes | HTTPS endpoint that receives the events. Public addresses only. |
| `events` | array of string | yes | `*` = all events. One of: `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`, `*`. |
| `name` | string |  |  |
| `projectId` | string (uuid) |  | Limit to one project (editor role needed). Omit for the whole workspace (owner/admin). |
| `workspaceId` | string (uuid) |  |  |

```bash
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"
}'
```

Returnează 201 Created: Created

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `webhook` | Webhook |  |  |
| `secret` | string |  | whsec_... |

```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` (public, no key)

```bash
curl https://planitude.app/api/webhooks/events
```

Returnează 200 OK: Events

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `apiVersion` | string |  |  |
| `events` | array of string |  |  |

```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}` (scope: read)

Parametri de cale:

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `webhookId` | string (uuid) | yes | Webhook id. |

```bash
curl https://planitude.app/api/webhooks/1747ee7f-a395-4d3c-94b0-54b513d71d88 \
  -H "Authorization: Bearer $PLANITUDE_API_KEY"
```

Returnează 200 OK: Subscription

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `webhook` | Webhook |  |  |

```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}` (scope: write)

Parametri de cale:

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `webhookId` | string (uuid) | yes | Webhook id. |

Corpul cererii:

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `name` | string |  |  |
| `url` | string (uri) |  |  |
| `events` | array of string |  |  |
| `active` | boolean |  | false = pause; true = resume (also resets the failure counter). |

```bash
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}'
```

Returnează 200 OK: Updated

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `webhook` | Webhook |  |  |

```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)

`DELETE /api/webhooks/{webhookId}` (scope: write)

Parametri de cale:

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `webhookId` | string (uuid) | yes | Webhook id. |

```bash
curl -X DELETE https://planitude.app/api/webhooks/1747ee7f-a395-4d3c-94b0-54b513d71d88 \
  -H "Authorization: Bearer $PLANITUDE_API_KEY"
```

Returnează 204 No Content: Deleted

#### Delivery log (newest first, kept 30 days)

`GET /api/webhooks/{webhookId}/deliveries` (scope: read)

Parametri de cale:

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `webhookId` | string (uuid) | yes | Webhook id. |

Parametri de interogare:

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `limit` | integer |  | 1-100. Default: `50`. |
| `before` | string (date-time) |  | `nextCursor` of the previous page. |

```bash
curl https://planitude.app/api/webhooks/1747ee7f-a395-4d3c-94b0-54b513d71d88/deliveries \
  -H "Authorization: Bearer $PLANITUDE_API_KEY"
```

Returnează 200 OK: Deliveries

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `deliveries` | array of Delivery |  |  |
| `nextCursor` | string, nullable |  |  |

```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}` (scope: read)

Parametri de cale:

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `webhookId` | string (uuid) | yes | Webhook id. |
| `deliveryId` | string (uuid) | yes |  |

```bash
curl https://planitude.app/api/webhooks/1747ee7f-a395-4d3c-94b0-54b513d71d88/deliveries/4b207161-80f9-40bb-bc3f-d8f70315be00 \
  -H "Authorization: Bearer $PLANITUDE_API_KEY"
```

Returnează 200 OK: Payload

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `payload` | Event |  |  |

```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` (scope: write)

Parametri de cale:

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `webhookId` | string (uuid) | yes | Webhook id. |
| `deliveryId` | string (uuid) | yes |  |

```bash
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"
```

Returnează 202 Accepted: Queued

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `delivery` | Delivery |  |  |

```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` (scope: write)

Parametri de cale:

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `webhookId` | string (uuid) | yes | Webhook id. |

```bash
curl -X POST https://planitude.app/api/webhooks/1747ee7f-a395-4d3c-94b0-54b513d71d88/test \
  -H "Authorization: Bearer $PLANITUDE_API_KEY"
```

Returnează 202 Accepted: Queued

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `delivery` | Delivery |  |  |

```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` (scope: write)

Parametri de cale:

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `webhookId` | string (uuid) | yes | Webhook id. |

```bash
curl -X POST https://planitude.app/api/webhooks/1747ee7f-a395-4d3c-94b0-54b513d71d88/rotate-secret \
  -H "Authorization: Bearer $PLANITUDE_API_KEY"
```

Returnează 200 OK: New secret (shown once)

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `webhook` | Webhook |  |  |
| `secret` | string |  |  |

```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-uri

Webhook-urile trimit un `POST` HTTPS cu un corp JSON către endpoint-ul dvs. imediat ce se schimbă ceva, indiferent dacă modificarea provine din aplicația web, din API, de la serverul MCP sau dintr-un import. Un webhook acoperă un proiect sau toate proiectele unui spațiu de lucru (proprietari și administratori).

Creați-le în [Profil → Webhook-uri](https://planitude.app/ro/app/profile/webhooks) sau prin API, ca REST hooks: abonați-vă cu `POST /api/webhooks`, dezabonați-vă cu `DELETE`. Secretul de semnare este afișat o singură dată.

| Antet | Descriere |
| --- | --- |
| `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` |

### Tipuri de evenimente

Abonați-vă la evenimente individuale sau la `*` pentru toate. Fiecare eveniment are aceeași structură; `data` se schimbă în funcție de tip.

| Eveniment | Descriere |
| --- | --- |
| `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. |

#### project.created

```json
{
  "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"
  }
}
```

#### project.updated

```json
{
  "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"
  }
}
```

#### project.deleted

```json
{
  "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"
    }
  }
}
```

#### task.created

```json
{
  "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"
    }
  }
}
```

#### task.updated

```json
{
  "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
      }
    }
  }
}
```

#### task.deleted

```json
{
  "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"
    }
  }
}
```

#### task.completed

```json
{
  "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"
    }
  }
}
```

#### task.dates_changed

```json
{
  "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"
      }
    }
  }
}
```

#### dependency.created

```json
{
  "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
    }
  }
}
```

#### dependency.deleted

```json
{
  "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
    }
  }
}
```

#### baseline.saved

```json
{
  "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
    }
  }
}
```

#### member.invited

```json
{
  "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
    }
  }
}
```

#### member.joined

```json
{
  "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"
    }
  }
}
```

#### comment.created

```json
{
  "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"
    }
  }
}
```

### Verificarea semnăturilor

Fiecare cerere este semnată cu HMAC-SHA256 și secretul webhook-ului dvs. Antetul `Planitude-Signature` conține un timestamp `t` și semnătura `v1`, calculată pe `t`, un punct și corpul brut.

1. Folosiți corpul brut, înainte de orice parsare JSON: un corp re-serializat are o altă semnătură.
2. Calculați HMAC-ul și comparați-l în timp constant.
3. Respingeți cererile al căror timestamp diferă cu mai mult de 5 minute de ceasul dvs.: o cerere interceptată nu poate fi reluată.
4. Rotiți secretul oricând doriți: cel vechi încetează să funcționeze imediat.

```js
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
// });
```

```python
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"])
```

### Reîncercări și livrare

Răspundeți cu orice cod **2xx** în 10 secunde și efectuați munca propriu-zisă ulterior, într-o coadă. Redirecționările nu sunt urmate. În caz de erori și depășiri de timp, Planitude încearcă de maximum 6 ori în total: imediat, apoi după 1 min, 5 min, 30 min, 2 h, 12 h.

Livrarea este **cel puțin o dată** și **fără ordine garantată**. Stocați id-ul evenimentului (`Planitude-Event-Id`, la fel ca `id` din corp) și săriți peste cele deja procesate; ordonați după `createdAt`.

După ce 5 evenimente consecutive eșuează la toate încercările, webhook-ul este dezactivat, iar proprietarul său primește un e-mail. Un răspuns `410 Gone` îl dezactivează imediat. Reactivați-l din profil sau cu `PATCH` și `active: true`.

Jurnalul livrărilor (stare, cod HTTP, fragment de răspuns, payload, retrimitere manuală) este păstrat 30 zile. Ca destinații sunt acceptate doar adrese publice.

### Testați endpoint-ul

1. Trimiteți un eveniment `webhook.ping` cu endpoint-ul de test sau cu butonul Testare din profil.
2. Pentru a primi evenimente pe computerul dvs., expuneți serverul local printr-un tunel (de exemplu ngrok sau Cloudflare Tunnel) și abonați adresa lui HTTPS publică.
3. Deschideți jurnalul livrărilor pentru a vedea starea, codul HTTP și răspunsul și retrimiteți o livrare după ce endpoint-ul dvs. a fost reparat.

```bash
curl -X POST https://planitude.app/api/webhooks/1747ee7f-a395-4d3c-94b0-54b513d71d88/test \
  -H "Authorization: Bearer $PLANITUDE_API_KEY"
```

## Server MCP

Planitude este un server MCP (Model Context Protocol): asistenții AI și editoarele de cod citesc proiecte, analizează calea critică și încărcarea, și creează sau modifică sarcini, cu permisiunile dvs. Aplicațiile web se conectează prin OAuth (vă autentificați și permiteți accesul); instrumentele din linia de comandă și editoarele folosesc o cheie API.

URL server: https://planitude.app/mcp

### ChatGPT (OAuth)

În ChatGPT deschideți Setări › Securitate și autentificare și activați Developer mode. Creați o aplicație cu URL-ul serverului și autentificare OAuth, apoi autentificați-vă în Planitude și permiteți accesul.

Server URL:

```
https://planitude.app/mcp
```

Documentație oficială: https://developers.openai.com/api/docs/guides/developer-mode

### Claude (OAuth)

Deschideți Personalizare › Conectori › Adăugare conector personalizat, lipiți URL-ul serverului și alegeți Conectare: se deschide Planitude, vă autentificați și permiteți accesul. Funcționează în claude.ai, Claude Desktop și în aplicația mobilă.

Server URL:

```
https://planitude.app/mcp
```

Documentație oficială: https://claude.com/docs/connectors/custom/add-unlisted

### Gemini (OAuth)

Pe gemini.google.com deschideți Setări › Aplicații conectate, alegeți Adăugare aplicație personalizată și lipiți URL-ul serverului; apoi autentificați-vă în Planitude și permiteți accesul.

Server URL:

```
https://planitude.app/mcp
```

Documentație oficială: https://support.google.com/gemini/answer/17209137

### Claude Code (Cheie API)

Rulați comanda cu cheia dvs. într-o variabilă de mediu. Adăugați `--scope user` pentru a o folosi în fiecare proiect și verificați cu `claude mcp list`.

Terminal:

```bash
claude mcp add --transport http planitude https://planitude.app/mcp \
  --header "Authorization: Bearer $PLANITUDE_API_KEY"
```

Documentație oficială: https://code.claude.com/docs/en/mcp

### Codex (Cheie API)

Puneți cheia în `PLANITUDE_API_KEY` și adăugați blocul în `~/.codex/config.toml`: se aplică CLI-ului, aplicației și extensiei IDE.

~/.codex/config.toml:

```toml
[mcp_servers.planitude]
url = "https://planitude.app/mcp"
bearer_token_env_var = "PLANITUDE_API_KEY"
```

Documentație oficială: https://learn.chatgpt.com/docs/extend/mcp

### Cursor (Cheie API)

Adăugați blocul în `~/.cursor/mcp.json` (toate proiectele) sau în `.cursor/mcp.json` (un singur proiect); Cursor citește cheia din mediu.

~/.cursor/mcp.json:

```json
{
  "mcpServers": {
    "planitude": {
      "url": "https://planitude.app/mcp",
      "headers": {
        "Authorization": "Bearer ${env:PLANITUDE_API_KEY}"
      }
    }
  }
}
```

Documentație oficială: https://cursor.com/docs/context/mcp

### Visual Studio Code (Cheie API)

Adăugați `.vscode/mcp.json` în spațiul de lucru: VS Code solicită cheia o singură dată și o stochează în siguranță, în afara fișierului.

.vscode/mcp.json:

```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
    }
  ]
}
```

Documentație oficială: https://code.visualstudio.com/docs/copilot/customization/mcp-servers

### Gemini CLI (Cheie API)

Rulați comanda cu cheia dvs. într-o variabilă de mediu sau adăugați blocul în `~/.gemini/settings.json`.

Terminal:

```bash
gemini mcp add --transport http \
  --header "Authorization: Bearer $PLANITUDE_API_KEY" planitude https://planitude.app/mcp
```

~/.gemini/settings.json:

```json
{
  "mcpServers": {
    "planitude": {
      "httpUrl": "https://planitude.app/mcp",
      "headers": {
        "Authorization": "Bearer $PLANITUDE_API_KEY"
      }
    }
  }
}
```

Documentație oficială: https://geminicli.com/docs/tools/mcp-server/

### Instrumente

Serverul expune 29 instrumente, de la citire și analiză până la modificări sigure. Niciunul nu șterge proiecte sau sarcini.

- read: `planitude_list_projects`, `planitude_portfolio_overview`, `planitude_get_project`, `planitude_critical_path`, `planitude_delay_impact`, `planitude_monte_carlo`, `planitude_workload`, `planitude_list_baselines`, `planitude_list_versions`, `planitude_list_templates`, `planitude_list_comments`, `planitude_preview_import`
- write: `planitude_create_project`, `planitude_create_project_from_template`, `planitude_create_project_from_plan`, `planitude_import_file`, `planitude_edit_project`, `planitude_add_task`, `planitude_update_task`, `planitude_set_progress`, `planitude_indent_task`, `planitude_outdent_task`, `planitude_link_tasks`, `planitude_unlink_tasks`, `planitude_reschedule`, `planitude_configure_simulation`, `planitude_add_comment`, `planitude_save_baseline`, `planitude_save_version`

[Ghid pas cu pas pentru ChatGPT, Claude și Gemini](https://planitude.app/ro/blog/chatgpt-claude-gemini-mcp-project-plans)

## Integrări gata de utilizare

Nu este nevoie de cod: aceste integrări folosesc același API și aceleași webhook-uri și se configurează în câteva clicuri.

- [Jira](https://planitude.app/ro/integrations/jira) (Disponibil): Sincronizare bidirecțională a sarcinilor, datelor și dependențelor cu issue-urile Jira.
- [Azure DevOps](https://planitude.app/ro/integrations/azure-devops) (Disponibil): Sincronizare bidirecțională cu work item-urile din Azure DevOps Boards.
- [Slack](https://planitude.app/ro/integrations/slack) (Disponibil): Actualizări de proiect, rezumate zilnice și o comandă slash în canalele dvs.
- [Microsoft Teams](https://planitude.app/ro/integrations/teams) (Disponibil): Actualizări, rezumate și o filă Planitude în Microsoft Teams.
- [Zapier, Make, n8n](https://planitude.app/ro/integrations?category=automation) (În curând): Declanșatoare și acțiuni instantanee pe sarcini și proiecte pentru automatizări fără cod.

## Jurnal de modificări

- **2026-10-02**: Documentație nouă pentru dezvoltatori, generată din documentul OpenAPI. Documentul OpenAPI descrie acum fiecare câmp returnat pentru membri, comentarii, linii de bază, șabloane și persoane desemnate.
- **2026-10-01**: Versiunea API 2026-10-01: webhook-uri semnate de ieșire, API REST public documentat (OpenAPI 3.1), paginare cu cursor și căutare după externalId.
- **2026-09-30**: OAuth 2.1 pentru serverul MCP și API: ChatGPT, Claude și Gemini se conectează fără a copia o cheie.
- **2026-09-28**: Server MCP și chei API personale cu acces de citire sau citire + scriere.
