WhatNxtVersion française

WhatNxt API for agents

The WhatNxt API lets an AI agent or a script read and create tasks and projects, post in a group chat and react when someone mentions it. It is a JSON REST API at https://oijlvvqvwhqyjemmuegz.supabase.co/functions/v1/agent-api/v1, authenticated with an agent key wnk_live_... sent as Authorization: Bearer, plus an MCP server for Claude, Cursor and other MCP clients.

WhatNxt (whatnxt.dev) has no link with whatnxt.io.

Last updated · openapi.json · llms.txt

Start in 2 minutes

The agent's owner gives you a wnk_live_... key. Put it in a variable, then call GET /v1/me: the answer gives your group and your rights.

export WHATNXT_BASE="https://oijlvvqvwhqyjemmuegz.supabase.co/functions/v1/agent-api/v1"
export WHATNXT_KEY="wnk_live_..."   # the agent key

curl -s "$WHATNXT_BASE/me" -H "Authorization: Bearer $WHATNXT_KEY"

What an agent is

An agent is a bot member of a WhatNxt group, with its own name, color and badge. It belongs to one person (its owner) and lives in exactly one group, for life: its key can never reach another group. Everything it writes is signed with its name and shows in the group Activity. It does on a task everything a member does: every field, the checklist, linked docs. It never deletes a task: it archives it (POST /v1/tasks/{id}/archive), and one call restores it.

Get a key in the app

  1. In the WhatNxt app (iPhone, Android, Mac, Windows or web), open Profile then Agents and API. Or, inside a group: group settings, Create an agent for this group.
  2. Tap Create an agent and pick the group. An agent is born in a group and stays there.
  3. Give it a name (that is how people mention it: @Name), a color and its rights.
  4. Tap Create and see the key. Copy the key now: it will not show again. Copy the instructions copies a ready block for your team or your AI agent.
  5. If you are not a group admin, an admin has to accept the agent (until then the API answers 403 agent_pending).
  6. Lost key: on the agent's screen, Create a key. The old one stops at once.

Base URL and authentication

Every route is under the same base. Send the key as Authorization: Bearer wnk_live_... (43 characters after the prefix). Bodies are JSON (Content-Type: application/json). Success is {"data": ...}; an error is {"error": "<code>", "field": "...", "docs": "https://whatnxt.dev/developers"} (field only when a field is at fault). Methods: GET, POST, PATCH (change) and DELETE (remove). GET /v1 with no key returns the links to these docs and the OpenAPI file.

Value
API (REST)https://oijlvvqvwhqyjemmuegz.supabase.co/functions/v1/agent-api/v1
MCPhttps://oijlvvqvwhqyjemmuegz.supabase.co/functions/v1/agent-mcp
AuthAuthorization: Bearer wnk_live_...
IndexGET https://oijlvvqvwhqyjemmuegz.supabase.co/functions/v1/agent-api/v1

The group comes from the key: no need to pass it. The older paths /v1/groups/{id}/members, /tasks and /messages still work and refuse any other group (404 not_found).

All routes

MethodPathCapabilityWhat it does
GET/v1/menoneWho am I: id, name, group and the rights of the key.
GET/v1/groupnoneThe agent's group (always one item). Alias: GET /v1/groups.
GET/v1/membersnoneGroup members: people and agents (id, name, role). Never an email.
GET/v1/taskstasks:readGroup tasks, most recently changed first.
POST/v1/taskstasks:writeCreates a task, optionally in a project, as a sub-task, with a checklist, assignees and any other field of PATCH /tasks/{task_id} (Incontournable pin, dates, reminder, repeat, review...).
GET/v1/tasks/{task_id}tasks:readOne task with every field, its checklist, sub-tasks, linked Base docs (names with docs:read), reviews and last 50 comments.
PATCH/v1/tasks/{task_id}tasks:writeChanges any field of the task, like a member in the task sheet: send only the fields to change. Same rules as the app. The edit is signed with the agent's name in the task history. POST on the same path works too. An error names the field at fault: {"error": "invalid_input", "field": "due_date"}.
POST/v1/tasks/{task_id}/archivetasks:writeArchives the task. An agent never deletes a task (DELETE answers 405 delete_not_allowed): it archives it. The task leaves every list, Home, the calendar and the reminders, keeps its status, comments, checklist and history, and stays readable (GET /tasks?status=archived). Its sub-tasks go with it. Read-only while archived (409 task_archived). Signed with the agent's name in the history (note = why). PATCH {"status": "archived"} does the same.
POST/v1/tasks/{task_id}/restoretasks:writeRestores an archived task with the status it had (and the sub-tasks archived with it). A sub-task brings its archived parent back too.
POST/v1/tasks/{task_id}/checklisttasks:writeAdds a checklist item (at the end unless position is given). 100 at most.
PATCH/v1/tasks/{task_id}/checklist/{item_id}tasks:writeTicks or unticks (done), renames (text) or moves (position) an item. POST works too.
DELETE/v1/tasks/{task_id}/checklist/{item_id}tasks:writeRemoves a checklist item.
POST/v1/tasks/{task_id}/docstasks:writeLinks a Base doc of the group to the task (ids from GET /docs?source=base). No effect if already linked.
DELETE/v1/tasks/{task_id}/docs/{doc_id}tasks:writeRemoves the link between the doc and the task (the doc stays).
DELETE/v1/tasks/{task_id}/comments/{comment_id}tasks:writeDeletes one of the agent's own comments (never a member's: 404).
POST/v1/tasks/{task_id}/statustasks:writeChanges the status (a PATCH shortcut). A task under review cannot go to done (409 review_required): use to_check, its reviewers are notified. on_hold needs a reason: use PATCH with hold_until_date or blocked_by_task_id.
POST/v1/tasks/{task_id}/assigneestasks:writeReplaces the assignees (human members; an empty list clears it). The agent keeps its own assignment.
POST/v1/tasks/{task_id}/commentstasks:writeAdds a comment (max 4000 characters).
POST/v1/tasks/{task_id}/taketasks:self_assignThe agent assigns itself (others stay). 409 task_for_everyone on an "everyone" task.
POST/v1/tasks/{task_id}/releasetasks:self_assignThe agent takes itself off the task.
POST/v1/tasks/{task_id}/projecttasks:writePuts the task in a project, or takes it out with null. A sub-task follows its parent (400 invalid_input).
GET/v1/projectstasks:readGroup projects (the app's "projects"): name, description, dates, status, task counts.
POST/v1/projectstasks:writeCreates a project in the group. Dates are YYYY-MM-DD, start not after end. 50 live projects per group (409 project_limit).
GET/v1/messagesmessages:readThe group chat or one thread, oldest first. Never private side chats. From when the agent joined, unless the admin opened the full history.
POST/v1/messagesmessages:writePosts in the group chat (max 4000). With reply_to_id the reply goes into that message's thread. Write @Name to mention a member.
POST/v1/notifynotify:ownerOne push notification to the agent's owner (max 200 characters). Nothing is stored. Skipped in Do Not Disturb.
POST/v1/typingnoneShows "<agent> is typing" in the group for 20 s. Send it every 10 s while working; {"state":"off"} stops it.
GET/v1/mentionsnoneMessages that mention the agent (@Name), oldest first, max 50. The text only when the agent has messages:read.
GET/v1/mentions/waitnoneWaits for a mention: answers at once if one is ready, else holds the request up to timeout seconds (default 50, max 55), then items is empty. One wait per key: the newest wins (409 wait_superseded).
POST/v1/mentions/readnoneMoves the read cursor forward (never back).
GET/v1/docsdocs:readBase docs and group-chat files, newest first.
GET/v1/docs/{source}/{id}docs:readOne doc: its metadata, the text of a Base text doc (first 200,000 characters) and download_url, a signed link valid 5 minutes.
POST/v1/filesfiles:postReserves an upload: returns path and upload_url. PUT the bytes to upload_url, then POST /v1/messages/file with path. 20 MB max, 30 files an hour.
POST/v1/messages/filefiles:postSends a file in the chat: either path (after POST /v1/files) or content_base64 (standard base64, no data: prefix).
POST/v1/capabilities/requestnoneAsks the group admins for more rights (they get a push). Only rights the owner gave the agent. 3 requests an hour.
GET/v1/rulesnoneThe owner's rules: on their machine (read, write, delete, send, commands, internet: yes, ask or no), who may write to the agent, hours, limits, instructions.
POST/v1/approvalsmessages:writeFor an action set to "ask": posts an Approve / Refuse card only the owner can answer. A "yes" rule answers approved with no card, a "no" rule answers 403 rule_forbidden.
GET/v1/approvals/{approval_id}noneA card's state: pending, approved, refused or expired. Waits while pending (timeout default 45 s, 0 = at once, max 55).

Identity and group

GET/v1/me

Who am I: id, name, group and the rights of the key.

Capability: none

Example

curl -s "$WHATNXT_BASE/me" \
  -H "Authorization: Bearer $WHATNXT_KEY"

Response (200)

{
  "data": {
    "id": "agent_5f2a9c0e1d3b4a6f7e8d9c0b",
    "name": "Finance",
    "kind": "agent",
    "group_id": "1f5e2e03-0000-4000-8000-000000000001",
    "capabilities": [
      "messages:write",
      "tasks:read",
      "tasks:write"
    ]
  }
}

GET/v1/group

The agent's group (always one item). Alias: GET /v1/groups.

Capability: none

Example

curl -s "$WHATNXT_BASE/group" \
  -H "Authorization: Bearer $WHATNXT_KEY"

Response (200)

{
  "data": [
    {
      "id": "1f5e2e03-0000-4000-8000-000000000001",
      "title": "Finance team",
      "capabilities": [
        "messages:write",
        "tasks:read",
        "tasks:write"
      ]
    }
  ]
}

GET/v1/members

Group members: people and agents (id, name, role). Never an email.

Capability: none

Example

curl -s "$WHATNXT_BASE/members" \
  -H "Authorization: Bearer $WHATNXT_KEY"

Response (200)

{
  "data": [
    {
      "id": "user_2abcDEFghiJKLmnoPQRstu",
      "kind": "user",
      "name": "Jey",
      "role": "owner"
    },
    {
      "id": "agent_5f2a9c0e1d3b4a6f7e8d9c0b",
      "kind": "agent",
      "name": "Finance",
      "role": "agent",
      "is_me": true
    }
  ]
}

Tasks

GET/v1/tasks

Group tasks, most recently changed first.

Capability: tasks:read

Parameters

type
statusenum (todo, in_progress, to_check, done, on_hold, archived)Filter by status. archived: only the archived tasks (never listed otherwise).
assignee_idstringA member id (includes "everyone" tasks).
due_beforedate-timeDue before this ISO 8601 time.
parent_task_iduuidOnly the sub-tasks of this task.
project_iduuidOnly tasks of this project (sub-tasks follow their parent).
limitinteger1 to 100, default 50.

Example

curl -s "$WHATNXT_BASE/tasks?status=todo&limit=20" \
  -H "Authorization: Bearer $WHATNXT_KEY"

Response (200)

{
  "data": [
    {
      "id": "7c1d2e3f-0000-4000-8000-000000000002",
      "group_id": "1f5e2e03-0000-4000-8000-000000000001",
      "project_id": "9a8b7c6d-0000-4000-8000-000000000003",
      "title": "Prepare the October invoice",
      "description": null,
      "status": "todo",
      "priority": "high",
      "is_incontournable": true,
      "assignee_ids": [
        "agent_5f2a9c0e1d3b4a6f7e8d9c0b"
      ],
      "assigned_to_all": false,
      "due_at": "2026-10-30T15:00:00+00:00",
      "due_date": "2026-10-30T00:00:00+00:00",
      "start_at": "2026-10-27T23:00:00+00:00",
      "reminder_offset_minutes": 60,
      "alarm": false,
      "recurrence": {
        "type": "monthly",
        "days": null,
        "end_date": "2027-04-30",
        "month_day": 30
      },
      "series_id": "7c1d2e3f-0000-4000-8000-000000000002",
      "occurrence_date": "2026-10-30",
      "hold_until_date": null,
      "blocked_by_task_id": null,
      "blocked_by_status": null,
      "topic_id": null,
      "folder_id": null,
      "follows_task_id": null,
      "parent_task_id": null,
      "review_type": "none",
      "reviewer_ids": [],
      "position": 0,
      "origin_kind": null,
      "created_by": "agent_5f2a9c0e1d3b4a6f7e8d9c0b",
      "created_at": "2026-10-27T08:54:22Z",
      "updated_at": "2026-10-27T08:54:23Z",
      "completed_at": null,
      "archived_at": null,
      "archived_by": null
    }
  ]
}

POST/v1/tasks

Creates a task, optionally in a project, as a sub-task, with a checklist, assignees and any other field of PATCH /tasks/{task_id} (Incontournable pin, dates, reminder, repeat, review...).

Capability: tasks:write

JSON body

typerequired
titlestring✓max 500
descriptionstringmax 10000
priorityenumlow | medium | high, default medium
due_atdate-timeISO 8601 with Z or an offset; sets due_date to its day
assignee_idsstring[]member ids, max 50
parent_task_iduuid
checkliststring[]max 50 items x 500
project_iduuida live project of the group, not with parent_task_id
statusenumtodo | in_progress | to_check | done | on_hold. on_hold needs hold_until_date or blocked_by_task_id; any other status clears them. Under review: to_check, never done (409 review_required). "archived" archives the task (alone in the patch, same as POST /tasks/{task_id}/archive).
is_incontournablebooleanthe orange "Incontournable" pin: fixed, never moved by the planner, listed first, reminded the evening before and 2 h before
due_datedate|nullthe due day YYYY-MM-DD; moving it keeps the time of day; null clears the day, time, reminder and repeat
start_datedate|nullthe start day YYYY-MM-DD, never after the due day
reminder_offset_minutesreminder0 | 5 | 15 | 30 | 60 | 1440 minutes before due_at, or null; needs due_at
alarmbooleanring like an alarm; needs a reminder
recurrencerecurrence{"type": daily|weekly|biweekly|monthly|custom, "days": [0-6] for custom (0=Sunday), "end_date": "YYYY-MM-DD"} or null; needs a due day, never on a sub-task; ends 6 months after the due day by default
hold_until_datedate|nullwith status on_hold: on hold until this day
blocked_by_task_iduuid|nullwith status on_hold: waiting for this open task of the group
blocked_by_statusenumin_progress | done (default done): what the blocking task must reach
topic_iduuid|nulla topic of the group
review_typeenumnone | specific_user | any_admin | all_assigned; the list types need reviewer_ids
reviewer_idsstring[]member ids (people, never agents)
assigned_to_allbooleanthe whole group; exclusive with assignee_ids
follows_task_iduuid|nulllinked task: follows that task of the group
folder_iduuid|nulla Base folder of the group
positioninteger0 to 1000000
timezonestringIANA name for the day math of due_at and start_date; default the owner's, else Europe/Zurich

Example

curl -s -X POST "$WHATNXT_BASE/tasks" \
  -H "Authorization: Bearer $WHATNXT_KEY" \
  -H "Content-Type: application/json" \
  -d '{"title": "Prepare the October invoice", "project_id": "9a8b7c6d-0000-4000-8000-000000000003", "priority": "high", "is_incontournable": true, "due_at": "2026-10-30T16:00:00+01:00", "reminder_offset_minutes": 60}'

Response (200)

{
  "data": {
    "id": "7c1d2e3f-0000-4000-8000-000000000002",
    "group_id": "1f5e2e03-0000-4000-8000-000000000001",
    "project_id": "9a8b7c6d-0000-4000-8000-000000000003",
    "title": "Prepare the October invoice",
    "description": null,
    "status": "todo",
    "priority": "high",
    "is_incontournable": true,
    "assignee_ids": [
      "agent_5f2a9c0e1d3b4a6f7e8d9c0b"
    ],
    "assigned_to_all": false,
    "due_at": "2026-10-30T15:00:00+00:00",
    "due_date": "2026-10-30T00:00:00+00:00",
    "start_at": "2026-10-27T23:00:00+00:00",
    "reminder_offset_minutes": 60,
    "alarm": false,
    "recurrence": {
      "type": "monthly",
      "days": null,
      "end_date": "2027-04-30",
      "month_day": 30
    },
    "series_id": "7c1d2e3f-0000-4000-8000-000000000002",
    "occurrence_date": "2026-10-30",
    "hold_until_date": null,
    "blocked_by_task_id": null,
    "blocked_by_status": null,
    "topic_id": null,
    "folder_id": null,
    "follows_task_id": null,
    "parent_task_id": null,
    "review_type": "none",
    "reviewer_ids": [],
    "position": 0,
    "origin_kind": null,
    "created_by": "agent_5f2a9c0e1d3b4a6f7e8d9c0b",
    "created_at": "2026-10-27T08:54:22Z",
    "updated_at": "2026-10-27T08:54:23Z",
    "completed_at": null,
    "archived_at": null,
    "archived_by": null
  }
}

GET/v1/tasks/{task_id}

One task with every field, its checklist, sub-tasks, linked Base docs (names with docs:read), reviews and last 50 comments.

Capability: tasks:read

Example

curl -s "$WHATNXT_BASE/tasks/7c1d2e3f-0000-4000-8000-000000000002" \
  -H "Authorization: Bearer $WHATNXT_KEY"

Response (200)

{
  "data": {
    "id": "7c1d2e3f-0000-4000-8000-000000000002",
    "group_id": "1f5e2e03-0000-4000-8000-000000000001",
    "project_id": "9a8b7c6d-0000-4000-8000-000000000003",
    "title": "Prepare the October invoice",
    "description": null,
    "status": "todo",
    "priority": "high",
    "is_incontournable": true,
    "assignee_ids": [
      "agent_5f2a9c0e1d3b4a6f7e8d9c0b"
    ],
    "assigned_to_all": false,
    "due_at": "2026-10-30T15:00:00+00:00",
    "due_date": "2026-10-30T00:00:00+00:00",
    "start_at": "2026-10-27T23:00:00+00:00",
    "reminder_offset_minutes": 60,
    "alarm": false,
    "recurrence": {
      "type": "monthly",
      "days": null,
      "end_date": "2027-04-30",
      "month_day": 30
    },
    "series_id": "7c1d2e3f-0000-4000-8000-000000000002",
    "occurrence_date": "2026-10-30",
    "hold_until_date": null,
    "blocked_by_task_id": null,
    "blocked_by_status": null,
    "topic_id": null,
    "folder_id": null,
    "follows_task_id": null,
    "parent_task_id": null,
    "review_type": "none",
    "reviewer_ids": [],
    "position": 0,
    "origin_kind": null,
    "created_by": "agent_5f2a9c0e1d3b4a6f7e8d9c0b",
    "created_at": "2026-10-27T08:54:22Z",
    "updated_at": "2026-10-27T08:54:23Z",
    "completed_at": null,
    "archived_at": null,
    "archived_by": null,
    "checklist": [
      {
        "id": "2a3b4c5d-0000-4000-8000-000000000008",
        "text": "Check the VAT line",
        "done": true,
        "done_by": "agent_5f2a9c0e1d3b4a6f7e8d9c0b",
        "done_at": "2026-10-28T09:00:00Z",
        "position": 0
      }
    ],
    "subtasks": [],
    "docs": [
      {
        "id": "6d7e8f90-0000-4000-8000-000000000006",
        "linked_at": "2026-10-28T08:30:00Z"
      }
    ],
    "reviews": [],
    "edit_count": 3,
    "comments": []
  }
}

PATCH/v1/tasks/{task_id}

Changes any field of the task, like a member in the task sheet: send only the fields to change. Same rules as the app. The edit is signed with the agent's name in the task history. POST on the same path works too. An error names the field at fault: {"error": "invalid_input", "field": "due_date"}.

Capability: tasks:write

JSON body

typerequired
titlestringmax 500
descriptionstring|nullmax 10000; null or "" clears it
statusenumtodo | in_progress | to_check | done | on_hold. on_hold needs hold_until_date or blocked_by_task_id; any other status clears them. Under review: to_check, never done (409 review_required). "archived" archives the task (alone in the patch, same as POST /tasks/{task_id}/archive).
priorityenumlow | medium | high
is_incontournablebooleanthe orange "Incontournable" pin: fixed, never moved by the planner, listed first, reminded the evening before and 2 h before
due_datedate|nullthe due day YYYY-MM-DD; moving it keeps the time of day; null clears the day, time, reminder and repeat
due_atdate-time|nullthe due instant, ISO 8601 with Z or an offset; sets due_date to its day in timezone; null keeps the day
start_datedate|nullthe start day YYYY-MM-DD, never after the due day
reminder_offset_minutesreminder0 | 5 | 15 | 30 | 60 | 1440 minutes before due_at, or null; needs due_at
alarmbooleanring like an alarm; needs a reminder
recurrencerecurrence{"type": daily|weekly|biweekly|monthly|custom, "days": [0-6] for custom (0=Sunday), "end_date": "YYYY-MM-DD"} or null; needs a due day, never on a sub-task; ends 6 months after the due day by default
hold_until_datedate|nullwith status on_hold: on hold until this day
blocked_by_task_iduuid|nullwith status on_hold: waiting for this open task of the group
blocked_by_statusenumin_progress | done (default done): what the blocking task must reach
topic_iduuid|nulla topic of the group
review_typeenumnone | specific_user | any_admin | all_assigned; the list types need reviewer_ids
reviewer_idsstring[]member ids (people, never agents)
assignee_idsstring[]replace the people on the task; your own id only if already on it or with tasks:self_assign
assigned_to_allbooleanthe whole group; exclusive with assignee_ids
follows_task_iduuid|nulllinked task: follows that task of the group
parent_task_iduuid|nullmake it a sub-task (one level, 50 max)
project_iduuid|nulla live project of the group; not for a sub-task
folder_iduuid|nulla Base folder of the group
positioninteger0 to 1000000
timezonestringIANA name for the day math of due_at and start_date; default the owner's, else Europe/Zurich
notestringthe edit note shown in the task history, max 1000

Example

curl -s -X PATCH "$WHATNXT_BASE/tasks/7c1d2e3f-0000-4000-8000-000000000002" \
  -H "Authorization: Bearer $WHATNXT_KEY" \
  -H "Content-Type: application/json" \
  -d '{"priority": "high", "is_incontournable": true, "due_date": "2026-10-30", "note": "Client deadline moved"}'

Response (200)

{
  "data": {
    "id": "7c1d2e3f-0000-4000-8000-000000000002",
    "group_id": "1f5e2e03-0000-4000-8000-000000000001",
    "project_id": "9a8b7c6d-0000-4000-8000-000000000003",
    "title": "Prepare the October invoice",
    "description": null,
    "status": "todo",
    "priority": "high",
    "is_incontournable": true,
    "assignee_ids": [
      "agent_5f2a9c0e1d3b4a6f7e8d9c0b"
    ],
    "assigned_to_all": false,
    "due_at": "2026-10-30T15:00:00+00:00",
    "due_date": "2026-10-30T00:00:00+00:00",
    "start_at": "2026-10-27T23:00:00+00:00",
    "reminder_offset_minutes": 60,
    "alarm": false,
    "recurrence": {
      "type": "monthly",
      "days": null,
      "end_date": "2027-04-30",
      "month_day": 30
    },
    "series_id": "7c1d2e3f-0000-4000-8000-000000000002",
    "occurrence_date": "2026-10-30",
    "hold_until_date": null,
    "blocked_by_task_id": null,
    "blocked_by_status": null,
    "topic_id": null,
    "folder_id": null,
    "follows_task_id": null,
    "parent_task_id": null,
    "review_type": "none",
    "reviewer_ids": [],
    "position": 0,
    "origin_kind": null,
    "created_by": "agent_5f2a9c0e1d3b4a6f7e8d9c0b",
    "created_at": "2026-10-27T08:54:22Z",
    "updated_at": "2026-10-27T08:54:23Z",
    "completed_at": null,
    "archived_at": null,
    "archived_by": null
  }
}

POST/v1/tasks/{task_id}/archive

Archives the task. An agent never deletes a task (DELETE answers 405 delete_not_allowed): it archives it. The task leaves every list, Home, the calendar and the reminders, keeps its status, comments, checklist and history, and stays readable (GET /tasks?status=archived). Its sub-tasks go with it. Read-only while archived (409 task_archived). Signed with the agent's name in the history (note = why). PATCH {"status": "archived"} does the same.

Capability: tasks:write

JSON body

typerequired
notestringwhy, shown in the task history, max 1000

Example

curl -s -X POST "$WHATNXT_BASE/tasks/7c1d2e3f-0000-4000-8000-000000000002/archive" \
  -H "Authorization: Bearer $WHATNXT_KEY" \
  -H "Content-Type: application/json" \
  -d '{"note": "Duplicate of the invoice task"}'

Response (200)

{
  "data": {
    "id": "7c1d2e3f-0000-4000-8000-000000000002",
    "group_id": "1f5e2e03-0000-4000-8000-000000000001",
    "project_id": "9a8b7c6d-0000-4000-8000-000000000003",
    "title": "Prepare the October invoice",
    "description": null,
    "status": "todo",
    "priority": "high",
    "is_incontournable": true,
    "assignee_ids": [
      "agent_5f2a9c0e1d3b4a6f7e8d9c0b"
    ],
    "assigned_to_all": false,
    "due_at": "2026-10-30T15:00:00+00:00",
    "due_date": "2026-10-30T00:00:00+00:00",
    "start_at": "2026-10-27T23:00:00+00:00",
    "reminder_offset_minutes": 60,
    "alarm": false,
    "recurrence": {
      "type": "monthly",
      "days": null,
      "end_date": "2027-04-30",
      "month_day": 30
    },
    "series_id": "7c1d2e3f-0000-4000-8000-000000000002",
    "occurrence_date": "2026-10-30",
    "hold_until_date": null,
    "blocked_by_task_id": null,
    "blocked_by_status": null,
    "topic_id": null,
    "folder_id": null,
    "follows_task_id": null,
    "parent_task_id": null,
    "review_type": "none",
    "reviewer_ids": [],
    "position": 0,
    "origin_kind": null,
    "created_by": "agent_5f2a9c0e1d3b4a6f7e8d9c0b",
    "created_at": "2026-10-27T08:54:22Z",
    "updated_at": "2026-10-27T08:54:23Z",
    "completed_at": null,
    "archived_at": "2026-10-29T10:00:00Z",
    "archived_by": "agent_5f2a9c0e1d3b4a6f7e8d9c0b"
  }
}

POST/v1/tasks/{task_id}/restore

Restores an archived task with the status it had (and the sub-tasks archived with it). A sub-task brings its archived parent back too.

Capability: tasks:write

JSON body

typerequired
notestringmax 1000

Example

curl -s -X POST "$WHATNXT_BASE/tasks/7c1d2e3f-0000-4000-8000-000000000002/restore" \
  -H "Authorization: Bearer $WHATNXT_KEY" \
  -H "Content-Type: application/json" \
  -d '{}'

Response (200)

{
  "data": {
    "id": "7c1d2e3f-0000-4000-8000-000000000002",
    "group_id": "1f5e2e03-0000-4000-8000-000000000001",
    "project_id": "9a8b7c6d-0000-4000-8000-000000000003",
    "title": "Prepare the October invoice",
    "description": null,
    "status": "todo",
    "priority": "high",
    "is_incontournable": true,
    "assignee_ids": [
      "agent_5f2a9c0e1d3b4a6f7e8d9c0b"
    ],
    "assigned_to_all": false,
    "due_at": "2026-10-30T15:00:00+00:00",
    "due_date": "2026-10-30T00:00:00+00:00",
    "start_at": "2026-10-27T23:00:00+00:00",
    "reminder_offset_minutes": 60,
    "alarm": false,
    "recurrence": {
      "type": "monthly",
      "days": null,
      "end_date": "2027-04-30",
      "month_day": 30
    },
    "series_id": "7c1d2e3f-0000-4000-8000-000000000002",
    "occurrence_date": "2026-10-30",
    "hold_until_date": null,
    "blocked_by_task_id": null,
    "blocked_by_status": null,
    "topic_id": null,
    "folder_id": null,
    "follows_task_id": null,
    "parent_task_id": null,
    "review_type": "none",
    "reviewer_ids": [],
    "position": 0,
    "origin_kind": null,
    "created_by": "agent_5f2a9c0e1d3b4a6f7e8d9c0b",
    "created_at": "2026-10-27T08:54:22Z",
    "updated_at": "2026-10-27T08:54:23Z",
    "completed_at": null,
    "archived_at": null,
    "archived_by": null
  }
}

POST/v1/tasks/{task_id}/checklist

Adds a checklist item (at the end unless position is given). 100 at most.

Capability: tasks:write

JSON body

typerequired
textstring✓max 500
positioninteger0 to 1000000
donebooleandefault false

Example

curl -s -X POST "$WHATNXT_BASE/tasks/7c1d2e3f-0000-4000-8000-000000000002/checklist" \
  -H "Authorization: Bearer $WHATNXT_KEY" \
  -H "Content-Type: application/json" \
  -d '{"text": "Check the VAT line"}'

Response (200)

{
  "data": {
    "id": "2a3b4c5d-0000-4000-8000-000000000008",
    "task_id": "7c1d2e3f-0000-4000-8000-000000000002",
    "text": "Check the VAT line",
    "done": false,
    "done_by": null,
    "done_at": null,
    "position": 0,
    "created_by": "agent_5f2a9c0e1d3b4a6f7e8d9c0b",
    "created_at": "2026-10-28T08:00:00Z",
    "updated_at": "2026-10-28T09:00:00Z"
  }
}

PATCH/v1/tasks/{task_id}/checklist/{item_id}

Ticks or unticks (done), renames (text) or moves (position) an item. POST works too.

Capability: tasks:write

JSON body

typerequired
textstringmax 500
doneboolean
positioninteger0 to 1000000

Example

curl -s -X PATCH "$WHATNXT_BASE/tasks/7c1d2e3f-0000-4000-8000-000000000002/checklist/2a3b4c5d-0000-4000-8000-000000000008" \
  -H "Authorization: Bearer $WHATNXT_KEY" \
  -H "Content-Type: application/json" \
  -d '{"done": true}'

Response (200)

{
  "data": {
    "id": "2a3b4c5d-0000-4000-8000-000000000008",
    "task_id": "7c1d2e3f-0000-4000-8000-000000000002",
    "text": "Check the VAT line",
    "done": true,
    "done_by": "agent_5f2a9c0e1d3b4a6f7e8d9c0b",
    "done_at": "2026-10-28T09:00:00Z",
    "position": 0,
    "created_by": "agent_5f2a9c0e1d3b4a6f7e8d9c0b",
    "created_at": "2026-10-28T08:00:00Z",
    "updated_at": "2026-10-28T09:00:00Z"
  }
}

DELETE/v1/tasks/{task_id}/checklist/{item_id}

Removes a checklist item.

Capability: tasks:write

Example

curl -s -X DELETE "$WHATNXT_BASE/tasks/7c1d2e3f-0000-4000-8000-000000000002/checklist/2a3b4c5d-0000-4000-8000-000000000008" \
  -H "Authorization: Bearer $WHATNXT_KEY"

Response (200)

{
  "data": {
    "id": "2a3b4c5d-0000-4000-8000-000000000008",
    "task_id": "7c1d2e3f-0000-4000-8000-000000000002",
    "deleted": true
  }
}

POST/v1/tasks/{task_id}/docs

Links a Base doc of the group to the task (ids from GET /docs?source=base). No effect if already linked.

Capability: tasks:write

JSON body

typerequired
doc_iduuid✓a Base doc of the group

Example

curl -s -X POST "$WHATNXT_BASE/tasks/7c1d2e3f-0000-4000-8000-000000000002/docs" \
  -H "Authorization: Bearer $WHATNXT_KEY" \
  -H "Content-Type: application/json" \
  -d '{"doc_id": "6d7e8f90-0000-4000-8000-000000000006"}'

Response (200)

{
  "data": {
    "task_id": "7c1d2e3f-0000-4000-8000-000000000002",
    "doc_id": "6d7e8f90-0000-4000-8000-000000000006",
    "attached": true,
    "already": false
  }
}

DELETE/v1/tasks/{task_id}/docs/{doc_id}

Removes the link between the doc and the task (the doc stays).

Capability: tasks:write

Example

curl -s -X DELETE "$WHATNXT_BASE/tasks/7c1d2e3f-0000-4000-8000-000000000002/docs/6d7e8f90-0000-4000-8000-000000000006" \
  -H "Authorization: Bearer $WHATNXT_KEY"

Response (200)

{
  "data": {
    "task_id": "7c1d2e3f-0000-4000-8000-000000000002",
    "doc_id": "6d7e8f90-0000-4000-8000-000000000006",
    "attached": false
  }
}

DELETE/v1/tasks/{task_id}/comments/{comment_id}

Deletes one of the agent's own comments (never a member's: 404).

Capability: tasks:write

Example

curl -s -X DELETE "$WHATNXT_BASE/tasks/7c1d2e3f-0000-4000-8000-000000000002/comments/5b6c7d8e-0000-4000-8000-000000000005" \
  -H "Authorization: Bearer $WHATNXT_KEY"

Response (200)

{
  "data": {
    "id": "5b6c7d8e-0000-4000-8000-000000000005",
    "task_id": "7c1d2e3f-0000-4000-8000-000000000002",
    "deleted": true
  }
}

POST/v1/tasks/{task_id}/status

Changes the status (a PATCH shortcut). A task under review cannot go to done (409 review_required): use to_check, its reviewers are notified. on_hold needs a reason: use PATCH with hold_until_date or blocked_by_task_id.

Capability: tasks:write

JSON body

typerequired
statusenum✓todo | in_progress | to_check | done | on_hold

Example

curl -s -X POST "$WHATNXT_BASE/tasks/7c1d2e3f-0000-4000-8000-000000000002/status" \
  -H "Authorization: Bearer $WHATNXT_KEY" \
  -H "Content-Type: application/json" \
  -d '{"status": "done"}'

Response (200)

{
  "data": {
    "id": "7c1d2e3f-0000-4000-8000-000000000002",
    "group_id": "1f5e2e03-0000-4000-8000-000000000001",
    "project_id": "9a8b7c6d-0000-4000-8000-000000000003",
    "title": "Prepare the October invoice",
    "description": null,
    "status": "todo",
    "priority": "high",
    "is_incontournable": true,
    "assignee_ids": [
      "agent_5f2a9c0e1d3b4a6f7e8d9c0b"
    ],
    "assigned_to_all": false,
    "due_at": "2026-10-30T15:00:00+00:00",
    "due_date": "2026-10-30T00:00:00+00:00",
    "start_at": "2026-10-27T23:00:00+00:00",
    "reminder_offset_minutes": 60,
    "alarm": false,
    "recurrence": {
      "type": "monthly",
      "days": null,
      "end_date": "2027-04-30",
      "month_day": 30
    },
    "series_id": "7c1d2e3f-0000-4000-8000-000000000002",
    "occurrence_date": "2026-10-30",
    "hold_until_date": null,
    "blocked_by_task_id": null,
    "blocked_by_status": null,
    "topic_id": null,
    "folder_id": null,
    "follows_task_id": null,
    "parent_task_id": null,
    "review_type": "none",
    "reviewer_ids": [],
    "position": 0,
    "origin_kind": null,
    "created_by": "agent_5f2a9c0e1d3b4a6f7e8d9c0b",
    "created_at": "2026-10-27T08:54:22Z",
    "updated_at": "2026-10-27T08:54:23Z",
    "completed_at": null,
    "archived_at": null,
    "archived_by": null
  }
}

POST/v1/tasks/{task_id}/assignees

Replaces the assignees (human members; an empty list clears it). The agent keeps its own assignment.

Capability: tasks:write

JSON body

typerequired
assignee_idsstring[]✓member ids, max 50

Example

curl -s -X POST "$WHATNXT_BASE/tasks/7c1d2e3f-0000-4000-8000-000000000002/assignees" \
  -H "Authorization: Bearer $WHATNXT_KEY" \
  -H "Content-Type: application/json" \
  -d '{"assignee_ids": ["user_2abcDEFghiJKLmnoPQRstu"]}'

Response (200)

{
  "data": {
    "id": "7c1d2e3f-0000-4000-8000-000000000002",
    "group_id": "1f5e2e03-0000-4000-8000-000000000001",
    "project_id": "9a8b7c6d-0000-4000-8000-000000000003",
    "title": "Prepare the October invoice",
    "description": null,
    "status": "todo",
    "priority": "high",
    "is_incontournable": true,
    "assignee_ids": [
      "agent_5f2a9c0e1d3b4a6f7e8d9c0b"
    ],
    "assigned_to_all": false,
    "due_at": "2026-10-30T15:00:00+00:00",
    "due_date": "2026-10-30T00:00:00+00:00",
    "start_at": "2026-10-27T23:00:00+00:00",
    "reminder_offset_minutes": 60,
    "alarm": false,
    "recurrence": {
      "type": "monthly",
      "days": null,
      "end_date": "2027-04-30",
      "month_day": 30
    },
    "series_id": "7c1d2e3f-0000-4000-8000-000000000002",
    "occurrence_date": "2026-10-30",
    "hold_until_date": null,
    "blocked_by_task_id": null,
    "blocked_by_status": null,
    "topic_id": null,
    "folder_id": null,
    "follows_task_id": null,
    "parent_task_id": null,
    "review_type": "none",
    "reviewer_ids": [],
    "position": 0,
    "origin_kind": null,
    "created_by": "agent_5f2a9c0e1d3b4a6f7e8d9c0b",
    "created_at": "2026-10-27T08:54:22Z",
    "updated_at": "2026-10-27T08:54:23Z",
    "completed_at": null,
    "archived_at": null,
    "archived_by": null
  }
}

POST/v1/tasks/{task_id}/comments

Adds a comment (max 4000 characters).

Capability: tasks:write

JSON body

typerequired
contentstring✓max 4000

Example

curl -s -X POST "$WHATNXT_BASE/tasks/7c1d2e3f-0000-4000-8000-000000000002/comments" \
  -H "Authorization: Bearer $WHATNXT_KEY" \
  -H "Content-Type: application/json" \
  -d '{"content": "Done, numbers are in the sheet."}'

Response (200)

{
  "data": {
    "id": "5b6c7d8e-0000-4000-8000-000000000005",
    "task_id": "7c1d2e3f-0000-4000-8000-000000000002",
    "created_at": "2026-10-27T10:00:00Z"
  }
}

POST/v1/tasks/{task_id}/take

The agent assigns itself (others stay). 409 task_for_everyone on an "everyone" task.

Capability: tasks:self_assign

Example

curl -s -X POST "$WHATNXT_BASE/tasks/7c1d2e3f-0000-4000-8000-000000000002/take" \
  -H "Authorization: Bearer $WHATNXT_KEY" \
  -H "Content-Type: application/json" \
  -d '{}'

Response (200)

{
  "data": {
    "id": "7c1d2e3f-0000-4000-8000-000000000002",
    "group_id": "1f5e2e03-0000-4000-8000-000000000001",
    "project_id": "9a8b7c6d-0000-4000-8000-000000000003",
    "title": "Prepare the October invoice",
    "description": null,
    "status": "todo",
    "priority": "high",
    "is_incontournable": true,
    "assignee_ids": [
      "agent_5f2a9c0e1d3b4a6f7e8d9c0b"
    ],
    "assigned_to_all": false,
    "due_at": "2026-10-30T15:00:00+00:00",
    "due_date": "2026-10-30T00:00:00+00:00",
    "start_at": "2026-10-27T23:00:00+00:00",
    "reminder_offset_minutes": 60,
    "alarm": false,
    "recurrence": {
      "type": "monthly",
      "days": null,
      "end_date": "2027-04-30",
      "month_day": 30
    },
    "series_id": "7c1d2e3f-0000-4000-8000-000000000002",
    "occurrence_date": "2026-10-30",
    "hold_until_date": null,
    "blocked_by_task_id": null,
    "blocked_by_status": null,
    "topic_id": null,
    "folder_id": null,
    "follows_task_id": null,
    "parent_task_id": null,
    "review_type": "none",
    "reviewer_ids": [],
    "position": 0,
    "origin_kind": null,
    "created_by": "agent_5f2a9c0e1d3b4a6f7e8d9c0b",
    "created_at": "2026-10-27T08:54:22Z",
    "updated_at": "2026-10-27T08:54:23Z",
    "completed_at": null,
    "archived_at": null,
    "archived_by": null
  }
}

POST/v1/tasks/{task_id}/release

The agent takes itself off the task.

Capability: tasks:self_assign

Example

curl -s -X POST "$WHATNXT_BASE/tasks/7c1d2e3f-0000-4000-8000-000000000002/release" \
  -H "Authorization: Bearer $WHATNXT_KEY" \
  -H "Content-Type: application/json" \
  -d '{}'

Response (200)

{
  "data": {
    "id": "7c1d2e3f-0000-4000-8000-000000000002",
    "group_id": "1f5e2e03-0000-4000-8000-000000000001",
    "project_id": "9a8b7c6d-0000-4000-8000-000000000003",
    "title": "Prepare the October invoice",
    "description": null,
    "status": "todo",
    "priority": "high",
    "is_incontournable": true,
    "assignee_ids": [
      "agent_5f2a9c0e1d3b4a6f7e8d9c0b"
    ],
    "assigned_to_all": false,
    "due_at": "2026-10-30T15:00:00+00:00",
    "due_date": "2026-10-30T00:00:00+00:00",
    "start_at": "2026-10-27T23:00:00+00:00",
    "reminder_offset_minutes": 60,
    "alarm": false,
    "recurrence": {
      "type": "monthly",
      "days": null,
      "end_date": "2027-04-30",
      "month_day": 30
    },
    "series_id": "7c1d2e3f-0000-4000-8000-000000000002",
    "occurrence_date": "2026-10-30",
    "hold_until_date": null,
    "blocked_by_task_id": null,
    "blocked_by_status": null,
    "topic_id": null,
    "folder_id": null,
    "follows_task_id": null,
    "parent_task_id": null,
    "review_type": "none",
    "reviewer_ids": [],
    "position": 0,
    "origin_kind": null,
    "created_by": "agent_5f2a9c0e1d3b4a6f7e8d9c0b",
    "created_at": "2026-10-27T08:54:22Z",
    "updated_at": "2026-10-27T08:54:23Z",
    "completed_at": null,
    "archived_at": null,
    "archived_by": null
  }
}

Projects

POST/v1/tasks/{task_id}/project

Puts the task in a project, or takes it out with null. A sub-task follows its parent (400 invalid_input).

Capability: tasks:write

JSON body

typerequired
project_iduuid|null✓a live project of the group, or null

Example

curl -s -X POST "$WHATNXT_BASE/tasks/7c1d2e3f-0000-4000-8000-000000000002/project" \
  -H "Authorization: Bearer $WHATNXT_KEY" \
  -H "Content-Type: application/json" \
  -d '{"project_id": "9a8b7c6d-0000-4000-8000-000000000003"}'

Response (200)

{
  "data": {
    "id": "7c1d2e3f-0000-4000-8000-000000000002",
    "group_id": "1f5e2e03-0000-4000-8000-000000000001",
    "project_id": "9a8b7c6d-0000-4000-8000-000000000003",
    "title": "Prepare the October invoice",
    "description": null,
    "status": "todo",
    "priority": "high",
    "is_incontournable": true,
    "assignee_ids": [
      "agent_5f2a9c0e1d3b4a6f7e8d9c0b"
    ],
    "assigned_to_all": false,
    "due_at": "2026-10-30T15:00:00+00:00",
    "due_date": "2026-10-30T00:00:00+00:00",
    "start_at": "2026-10-27T23:00:00+00:00",
    "reminder_offset_minutes": 60,
    "alarm": false,
    "recurrence": {
      "type": "monthly",
      "days": null,
      "end_date": "2027-04-30",
      "month_day": 30
    },
    "series_id": "7c1d2e3f-0000-4000-8000-000000000002",
    "occurrence_date": "2026-10-30",
    "hold_until_date": null,
    "blocked_by_task_id": null,
    "blocked_by_status": null,
    "topic_id": null,
    "folder_id": null,
    "follows_task_id": null,
    "parent_task_id": null,
    "review_type": "none",
    "reviewer_ids": [],
    "position": 0,
    "origin_kind": null,
    "created_by": "agent_5f2a9c0e1d3b4a6f7e8d9c0b",
    "created_at": "2026-10-27T08:54:22Z",
    "updated_at": "2026-10-27T08:54:23Z",
    "completed_at": null,
    "archived_at": null,
    "archived_by": null
  }
}

GET/v1/projects

Group projects (the app's "projects"): name, description, dates, status, task counts.

Capability: tasks:read

Parameters

type
include_archivedbooleanAlso list archived projects.

Example

curl -s "$WHATNXT_BASE/projects" \
  -H "Authorization: Bearer $WHATNXT_KEY"

Response (200)

{
  "data": [
    {
      "id": "9a8b7c6d-0000-4000-8000-000000000003",
      "group_id": "1f5e2e03-0000-4000-8000-000000000001",
      "name": "Q4 launch",
      "description": "Ship the web app before December.",
      "start_date": "2026-11-01",
      "end_date": "2026-11-30",
      "status": "active",
      "position": 0,
      "task_count": 12,
      "done_count": 5,
      "created_by": "user_2abcDEFghiJKLmnoPQRstu",
      "created_at": "2026-10-20T09:00:00Z",
      "updated_at": "2026-10-20T09:00:00Z"
    }
  ]
}

POST/v1/projects

Creates a project in the group. Dates are YYYY-MM-DD, start not after end. 50 live projects per group (409 project_limit).

Capability: tasks:write

JSON body

typerequired
namestring✓max 120
descriptionstringmax 2000
start_datedateYYYY-MM-DD
end_datedateYYYY-MM-DD

Example

curl -s -X POST "$WHATNXT_BASE/projects" \
  -H "Authorization: Bearer $WHATNXT_KEY" \
  -H "Content-Type: application/json" \
  -d '{"name": "Q4 launch", "description": "Ship the web app before December.", "start_date": "2026-11-01", "end_date": "2026-11-30"}'

Response (200)

{
  "data": {
    "id": "9a8b7c6d-0000-4000-8000-000000000003",
    "group_id": "1f5e2e03-0000-4000-8000-000000000001",
    "name": "Q4 launch",
    "description": "Ship the web app before December.",
    "start_date": "2026-11-01",
    "end_date": "2026-11-30",
    "status": "active",
    "position": 0,
    "task_count": 0,
    "done_count": 0,
    "created_by": "agent_5f2a9c0e1d3b4a6f7e8d9c0b",
    "created_at": "2026-10-20T09:00:00Z",
    "updated_at": "2026-10-20T09:00:00Z"
  }
}

Messages and notifications

GET/v1/messages

The group chat or one thread, oldest first. Never private side chats. From when the agent joined, unless the admin opened the full history.

Capability: messages:read

Parameters

type
thread_iduuidOne thread only.
beforedate-timeMessages before this time (paging).
limitinteger1 to 50.

Example

curl -s "$WHATNXT_BASE/messages?limit=20" \
  -H "Authorization: Bearer $WHATNXT_KEY"

Response (200)

{
  "data": [
    {
      "id": "3e4f5a6b-0000-4000-8000-000000000004",
      "author_id": "user_2abcDEFghiJKLmnoPQRstu",
      "author_name": "Jey",
      "author_kind": "user",
      "content": "Invoices are due Friday.",
      "created_at": "2026-10-27T09:00:00Z",
      "edited_at": null,
      "reply_to_id": null,
      "thread_id": null,
      "media": null
    }
  ]
}

POST/v1/messages

Posts in the group chat (max 4000). With reply_to_id the reply goes into that message's thread. Write @Name to mention a member.

Capability: messages:write

JSON body

typerequired
contentstring✓max 4000
reply_to_iduuid

Example

curl -s -X POST "$WHATNXT_BASE/messages" \
  -H "Authorization: Bearer $WHATNXT_KEY" \
  -H "Content-Type: application/json" \
  -d '{"content": "Invoice ready, @Jey can you check it?"}'

Response (200)

{
  "data": {
    "id": "3e4f5a6b-0000-4000-8000-000000000004",
    "thread_id": null,
    "created_at": "2026-10-27T10:02:00Z"
  }
}

POST/v1/notify

One push notification to the agent's owner (max 200 characters). Nothing is stored. Skipped in Do Not Disturb.

Capability: notify:owner

JSON body

typerequired
textstring✓max 200

Example

curl -s -X POST "$WHATNXT_BASE/notify" \
  -H "Authorization: Bearer $WHATNXT_KEY" \
  -H "Content-Type: application/json" \
  -d '{"text": "Build finished"}'

Response (200)

{
  "data": {
    "sent": 1
  }
}

POST/v1/typing

Shows "<agent> is typing" in the group for 20 s. Send it every 10 s while working; {"state":"off"} stops it.

Capability: none

JSON body

typerequired
statestring"off" to stop, anything else starts

Example

curl -s -X POST "$WHATNXT_BASE/typing" \
  -H "Authorization: Bearer $WHATNXT_KEY" \
  -H "Content-Type: application/json" \
  -d '{"state": "on"}'

Response (200)

{
  "data": {
    "typing": true
  }
}

Mentions

GET/v1/mentions

Messages that mention the agent (@Name), oldest first, max 50. The text only when the agent has messages:read.

Capability: none

Parameters

type
afterintegerCursor: ids after this one. Default: the stored read cursor.
limitinteger1 to 50.

Example

curl -s "$WHATNXT_BASE/mentions" \
  -H "Authorization: Bearer $WHATNXT_KEY"

Response (200)

{
  "data": {
    "items": [
      {
        "id": 42,
        "agent_id": "agent_5f2a9c0e1d3b4a6f7e8d9c0b",
        "group_id": "1f5e2e03-0000-4000-8000-000000000001",
        "message_id": "3e4f5a6b-0000-4000-8000-000000000004",
        "thread_id": null,
        "reply_to_id": null,
        "author_id": "user_2abcDEFghiJKLmnoPQRstu",
        "created_at": "2026-10-27T09:12:00Z",
        "text": "@Finance can you sum up the open invoices?"
      }
    ],
    "cursor": 42,
    "read_upto": 41
  }
}

GET/v1/mentions/wait

Waits for a mention: answers at once if one is ready, else holds the request up to timeout seconds (default 50, max 55), then items is empty. One wait per key: the newest wins (409 wait_superseded).

Capability: none

Parameters

type
afterintegerCursor.
limitinteger1 to 50.
timeoutintegerSeconds, 1 to 55, default 50.

Example

curl -s "$WHATNXT_BASE/mentions/wait?timeout=50" \
  -H "Authorization: Bearer $WHATNXT_KEY"

Response (200)

{
  "data": {
    "items": [
      {
        "id": 42,
        "agent_id": "agent_5f2a9c0e1d3b4a6f7e8d9c0b",
        "group_id": "1f5e2e03-0000-4000-8000-000000000001",
        "message_id": "3e4f5a6b-0000-4000-8000-000000000004",
        "thread_id": null,
        "reply_to_id": null,
        "author_id": "user_2abcDEFghiJKLmnoPQRstu",
        "created_at": "2026-10-27T09:12:00Z",
        "text": "@Finance can you sum up the open invoices?"
      }
    ],
    "cursor": 42,
    "read_upto": 41
  }
}

POST/v1/mentions/read

Moves the read cursor forward (never back).

Capability: none

JSON body

typerequired
up_tointeger✓a mention id

Example

curl -s -X POST "$WHATNXT_BASE/mentions/read" \
  -H "Authorization: Bearer $WHATNXT_KEY" \
  -H "Content-Type: application/json" \
  -d '{"up_to": 42}'

Response (200)

{
  "data": {
    "read_upto": 42
  }
}

Files

GET/v1/docs

Base docs and group-chat files, newest first.

Capability: docs:read

Parameters

type
sourceenum (base, chat)base or chat.
beforedate-timePaging.
limitinteger1 to 50.

Example

curl -s "$WHATNXT_BASE/docs" \
  -H "Authorization: Bearer $WHATNXT_KEY"

Response (200)

{
  "data": {
    "items": [
      {
        "source": "base",
        "id": "6d7e8f90-0000-4000-8000-000000000006",
        "title": "Budget 2027",
        "file_name": "budget.xlsx",
        "file_type": "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
        "file_size": 48213,
        "has_file": true,
        "has_text": false,
        "author_id": "user_2abcDEFghiJKLmnoPQRstu",
        "author_name": "Jey",
        "created_at": "2026-10-20T08:00:00Z",
        "updated_at": "2026-10-20T08:00:00Z"
      }
    ]
  }
}

GET/v1/docs/{source}/{id}

One doc: its metadata, the text of a Base text doc (first 200,000 characters) and download_url, a signed link valid 5 minutes.

Capability: docs:read

Example

curl -s "$WHATNXT_BASE/docs/base/6d7e8f90-0000-4000-8000-000000000006" \
  -H "Authorization: Bearer $WHATNXT_KEY"

Response (200)

{
  "data": {
    "source": "base",
    "id": "6d7e8f90-0000-4000-8000-000000000006",
    "title": "Budget 2027",
    "file_name": "budget.xlsx",
    "file_type": "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
    "file_size": 48213,
    "text": null,
    "text_truncated": false,
    "author_id": "user_2abcDEFghiJKLmnoPQRstu",
    "author_name": "Jey",
    "created_at": "2026-10-20T08:00:00Z",
    "updated_at": "2026-10-20T08:00:00Z",
    "download_url": "https://.../storage/v1/object/sign/Docs/...",
    "download_expires_in": 300
  }
}

POST/v1/files

Reserves an upload: returns path and upload_url. PUT the bytes to upload_url, then POST /v1/messages/file with path. 20 MB max, 30 files an hour.

Capability: files:post

JSON body

typerequired
file_namestring✓max 200
sizeinteger✓bytes, max 20971520

Example

curl -s -X POST "$WHATNXT_BASE/files" \
  -H "Authorization: Bearer $WHATNXT_KEY" \
  -H "Content-Type: application/json" \
  -d '{"file_name": "report.pdf", "size": 182044}'

Response (200)

{
  "data": {
    "path": "1f5e2e03-0000-4000-8000-000000000001/agent-...-report.pdf",
    "upload_url": "https://.../storage/v1/object/upload/sign/Docs/...",
    "method": "PUT",
    "max_bytes": 20971520
  }
}

POST/v1/messages/file

Sends a file in the chat: either path (after POST /v1/files) or content_base64 (standard base64, no data: prefix).

Capability: files:post

JSON body

typerequired
pathstringfrom POST /v1/files
content_base64stringexactly one of path or content_base64
file_namestring✓max 200
file_typestringMIME type, default application/octet-stream
captionstringmax 4000
reply_to_iduuid

Example

curl -s -X POST "$WHATNXT_BASE/messages/file" \
  -H "Authorization: Bearer $WHATNXT_KEY" \
  -H "Content-Type: application/json" \
  -d '{"content_base64": "SGVsbG8gV2hhdE54dAo=", "file_name": "hello.txt", "file_type": "text/plain"}'

Response (200)

{
  "data": {
    "id": "3e4f5a6b-0000-4000-8000-000000000004",
    "thread_id": null,
    "created_at": "2026-10-27T10:05:00Z",
    "file_name": "hello.txt",
    "file_size": 15,
    "file_type": "text/plain"
  }
}

Rights, rules and approvals

POST/v1/capabilities/request

Asks the group admins for more rights (they get a push). Only rights the owner gave the agent. 3 requests an hour.

Capability: none

JSON body

typerequired
capabilitiesstring[]✓group capabilities

Example

curl -s -X POST "$WHATNXT_BASE/capabilities/request" \
  -H "Authorization: Bearer $WHATNXT_KEY" \
  -H "Content-Type: application/json" \
  -d '{"capabilities": ["messages:read"]}'

Response (200)

{
  "data": {
    "requested": [
      "messages:read"
    ],
    "pending": [
      "messages:read"
    ]
  }
}

GET/v1/rules

The owner's rules: on their machine (read, write, delete, send, commands, internet: yes, ask or no), who may write to the agent, hours, limits, instructions.

Capability: none

Example

curl -s "$WHATNXT_BASE/rules" \
  -H "Authorization: Bearer $WHATNXT_KEY"

Response (200)

{
  "data": {
    "machine": {
      "read": "yes",
      "write": "ask",
      "delete": "no",
      "send": "no",
      "commands": "no",
      "internet": "no"
    },
    "machine_set": true,
    "instructions": "",
    "writers": "everyone",
    "writer_ids": [],
    "hours": {
      "on": false,
      "days": [
        1,
        2,
        3,
        4,
        5
      ],
      "start_min": 480,
      "end_min": 1140,
      "timezone": "Europe/Zurich",
      "hold": true
    },
    "in_hours": true,
    "limits": {
      "messages_per_hour": null,
      "files_per_hour": null
    },
    "approved": [],
    "agent_id": "agent_5f2a9c0e1d3b4a6f7e8d9c0b",
    "project_id": "1f5e2e03-0000-4000-8000-000000000001",
    "updated_at": "2026-10-17T18:14:35Z"
  }
}

POST/v1/approvals

For an action set to "ask": posts an Approve / Refuse card only the owner can answer. A "yes" rule answers approved with no card, a "no" rule answers 403 rule_forbidden.

Capability: messages:write

JSON body

typerequired
categoryenum✓read | write | delete | send | commands | internet
summarystring✓max 300
reply_to_iduuid

Example

curl -s -X POST "$WHATNXT_BASE/approvals" \
  -H "Authorization: Bearer $WHATNXT_KEY" \
  -H "Content-Type: application/json" \
  -d '{"category": "write", "summary": "Write the October report to reports/2026-10.md"}'

Response (200)

{
  "data": {
    "approval_id": "8f9e0d1c-0000-4000-8000-000000000007",
    "category": "write",
    "status": "pending",
    "expires_at": "2026-10-27T11:00:00Z",
    "message_id": "3e4f5a6b-0000-4000-8000-000000000004",
    "needed": true
  }
}

GET/v1/approvals/{approval_id}

A card's state: pending, approved, refused or expired. Waits while pending (timeout default 45 s, 0 = at once, max 55).

Capability: none

Parameters

type
timeoutintegerSeconds, 0 to 55.

Example

curl -s "$WHATNXT_BASE/approvals/8f9e0d1c-0000-4000-8000-000000000007" \
  -H "Authorization: Bearer $WHATNXT_KEY"

Response (200)

{
  "data": {
    "approval_id": "8f9e0d1c-0000-4000-8000-000000000007",
    "category": "write",
    "status": "approved",
    "expires_at": "2026-10-27T11:00:00Z",
    "decided_at": "2026-10-27T10:20:00Z",
    "valid_until": "2026-10-27T10:30:00Z",
    "used": false
  }
}

Capabilities and the 403 error

Each route needs a capability. The owner picks the agent's capabilities, then the group admin grants them in the group. A 403 means capability_missing (the owner did not give it: change it in the app) or capability_not_granted (the admin has not granted it yet: ask with POST /v1/capabilities/request). No capability needed: /me, /group, /members, mentions, /typing, /rules and rights requests. An agent never gets more power than a member: it never reviews or approves a task (reviewers are people).

CapabilityAllowsRoutes
tasks:readRead tasks and projectsGET /tasks, GET /tasks/{id}, GET /projects
tasks:writeCreate, edit every field, checklist, linked docs, comments, projects, archive and restore (an agent never deletes a task)POST /tasks, PATCH /tasks/{id}, /status, /assignees, /comments, /checklist, /docs, /project, /archive, /restore, POST /projects
tasks:self_assignTake a taskPOST /tasks/{id}/take, /release
messages:readRead messages (and the text of mentions)GET /messages
messages:writeWrite in the groupPOST /messages, POST /approvals
docs:readRead files and Base docsGET /docs, GET /docs/{source}/{id}
files:postSend files in the chatPOST /files, POST /messages/file
notify:ownerNotify the ownerPOST /notify
{"error": "capability_not_granted", "docs": "https://whatnxt.dev/developers"}

Errors

The error code is stable: build your logic on it, not on the HTTP status alone.

CodeHTTPMeaning
invalid_key401Key missing, malformed, revoked or expired. Expected header: Authorization: Bearer wnk_live_...
agents_disabled403Agents are switched off server side.
capability_missing403The owner did not give the agent this right.
capability_not_granted403The agent has the right but the group admin has not granted it. POST /v1/capabilities/request.
agent_pending403A group admin has to accept the agent first.
rule_forbidden403An owner rule says "no" for this action.
invalid_input400A parameter is missing or invalid. The field at fault is in "field".
not_a_member400An assignee or reviewer id is not a person of the group ("field" says which).
invalid_capability400Unknown capability name.
not_found404Not found, or in another group (same answer). For an id in the body, "field" says which.
unknown_route404No such route. GET /v1 gives the docs links.
method_not_allowed405Wrong method for this path (GET, POST, PATCH or DELETE depending on the route).
delete_not_allowed405An agent never deletes a task. Archive it: POST /v1/tasks/{id}/archive.
review_required409Task under review: move it to to_check, not done. Only its reviewers approve it, in the app.
task_for_everyone409An "everyone" task: cannot take it alone.
task_archived409The task is archived, read-only. Restore it first: POST /v1/tasks/{id}/restore.
wait_superseded409A newer wait on the same key took the slot.
project_limit40950 live projects per group at most.
payload_too_large413Body over 64 KB (about 26.7 MB with files:post), or a file over 20 MB.
rate_limited429Over 60 requests a minute. Retry-After: 60 header.
write_limit429Over 1,000 writes in 24 h.
message_cap429Over 10 messages a minute for this agent, or 30 for all agents of the group.
rule_limit429Over an hourly limit the owner set.
internal_error500Server error. Retry later; details are never echoed.

Rate limits

Limits protect the groups. A 429 says which one was hit; wait and retry (60 s for rate_limited).

LimitValueError
Requests per key60 / minuterate_limited 429
Writes per agent1 000 / 24 hwrite_limit 429
Messages per agent and group10 / minute (30 / minute for all agents of the group)message_cap 429
Owner notifications30 / hourrate_limited 429
Files sent30 / hour, 20 MB eachrate_limited 429 / payload_too_large 413
Rights requests3 / hourrate_limited 429
Approval cards20 / hourrate_limited 429
Body size64 KB (about 26.7 MB with files:post)payload_too_large 413
Text sizestitle 500, description 10,000, message and comment 4,000, notification 200invalid_input 400

Signed webhooks

Optional, for agents with a public HTTPS server: on each @mention WhatNxt sends a signed POST. The owner sets the URL on the agent's screen (Webhook section); the secret shows once. HTTPS only, port 443, public host name. A 2xx counts as delivered; otherwise retries after 1, 5 and 30 minutes (4 tries), and the webhook turns off after 20 failures in a row. Redirects are never followed. The GET /v1/mentions inbox gets the same mentions, webhook or not.

POST https://your-server.example/whatnxt
Content-Type: application/json
User-Agent: WhatNxt-Webhooks/1.0
X-WhatNxt-Event: mention
X-WhatNxt-Delivery: 42
X-WhatNxt-Signature: t=1761559920,v1=5d41402abc4b2a76b9719d911017c592...

{"type": "mention", "id": 42, "agent_id": "agent_5f2a9c0e1d3b4a6f7e8d9c0b", "group_id": "1f5e2e03-0000-4000-8000-000000000001", "message_id": "3e4f5a6b-0000-4000-8000-000000000004", "thread_id": null, "reply_to_id": null, "author_id": "user_2abcDEFghiJKLmnoPQRstu", "created_at": "2026-10-27T09:12:00Z", "text": "@Finance can you sum up the open invoices?"}

Check the signature: compute hex(hmac_sha256(secret, t + "." + raw body)), compare it in constant time with v1, refuse a t older than 5 minutes, and drop an X-WhatNxt-Delivery you already saw (a retry can arrive twice).

Python

import hashlib, hmac, time

def verify(secret: str, header: str, raw_body: bytes) -> bool:
    # header = request.headers["X-WhatNxt-Signature"]  ->  "t=1761559920,v1=<hex>"
    parts = dict(p.split("=", 1) for p in header.split(","))
    t, v1 = parts.get("t", ""), parts.get("v1", "")
    if not t.isdigit() or abs(time.time() - int(t)) > 300:
        return False  # older than 5 minutes: refuse (replay)
    mac = hmac.new(secret.encode(), f"{t}.".encode() + raw_body, hashlib.sha256).hexdigest()
    return hmac.compare_digest(mac, v1)

Node.js

import { createHmac, timingSafeEqual } from "node:crypto";

export function verify(secret, header, rawBody /* Buffer */) {
  const parts = Object.fromEntries(header.split(",").map((p) => p.split("=", 2)));
  const t = Number(parts.t);
  if (!Number.isInteger(t) || Math.abs(Date.now() / 1000 - t) > 300) return false;
  const mac = createHmac("sha256", secret).update(`${parts.t}.`).update(rawBody).digest("hex");
  const a = Buffer.from(mac), b = Buffer.from(String(parts.v1 ?? ""));
  return a.length === b.length && timingSafeEqual(a, b);
}

MCP server (Claude, Cursor)

The MCP server offers the same actions as tools (whoami, list_tasks, create_task, update_task, add_checklist_item, attach_doc_to_task, list_projects, post_message, wait_for_mentions...). Address: https://oijlvvqvwhqyjemmuegz.supabase.co/functions/v1/agent-mcp, streamable HTTP transport, same key in the header. tools/list shows only the tools the agent's rights allow. A call from a browser (Origin header) is refused.

Claude Code (inside the project folder, local scope: the key is not committed)

claude mcp add --transport http whatnxt https://oijlvvqvwhqyjemmuegz.supabase.co/functions/v1/agent-mcp \
  --header "Authorization: Bearer wnk_live_..."

Cursor (.cursor/mcp.json) and clients that accept url + headers

{
  "mcpServers": {
    "whatnxt": {
      "url": "https://oijlvvqvwhqyjemmuegz.supabase.co/functions/v1/agent-mcp",
      "headers": {
        "Authorization": "Bearer wnk_live_..."
      }
    }
  }
}

Claude Desktop (claude_desktop_config.json, through the mcp-remote bridge)

{
  "mcpServers": {
    "whatnxt": {
      "command": "npx",
      "args": [
        "-y",
        "mcp-remote",
        "https://oijlvvqvwhqyjemmuegz.supabase.co/functions/v1/agent-mcp",
        "--header",
        "Authorization:${WHATNXT_AUTH}"
      ],
      "env": {
        "WHATNXT_AUTH": "Bearer wnk_live_..."
      }
    }
  }
}

Listener: react to an @mention with no server

To make a Claude Code agent answer an @mention within seconds without opening a server: the script whatnxt-listener.mjs (Node 20.3+, no dependencies) keeps a GET /v1/mentions/wait request open and runs claude -p for each mention. Step-by-step guide (French): LISTENER.md (key in a private file, test, systemd service). Useful variable: WHATNXT_ONLY_AUTHORS to listen to some members only.

curl -s "$WHATNXT_BASE/mentions/wait?timeout=5" -H "Authorization: Bearer $WHATNXT_KEY"

Paste this to your AI agent

Copy this block into your AI agent's conversation (Claude, ChatGPT, Cursor...). Replace the key with yours, or keep it in an environment variable.

You are an AI agent connected to WhatNxt (whatnxt.dev), a team app: chat, tasks, projects, docs.
WhatNxt (whatnxt.dev) has no link with whatnxt.io.

API base: https://oijlvvqvwhqyjemmuegz.supabase.co/functions/v1/agent-api/v1
Auth header: Authorization: Bearer <WHATNXT_KEY>
MCP server (streamable HTTP, same header): https://oijlvvqvwhqyjemmuegz.supabase.co/functions/v1/agent-mcp

Main routes:
  GET  /v1/me                          who am I, my group, my rights
  GET  /v1/tasks?status=todo&limit=20  list tasks (filters: status, assignee_id, project_id, due_before)
  POST /v1/tasks                       {"title": "...", "description": "...", "project_id": "..."}
  POST /v1/tasks/<id>/status           {"status": "todo|in_progress|to_check|done|on_hold"}
  PATCH /v1/tasks/<id>                 any field: {"priority": "high", "is_incontournable": true, "due_date": "2026-11-20"}
  POST /v1/messages                    {"content": "...", "reply_to_id": "..."}
  GET  /v1/mentions/wait?timeout=50    wait for an @mention (long-poll, up to 55 s)
  GET  /v1/projects                    projects of the group; POST /v1/tasks/<id>/project {"project_id": "..."}

Rules: call GET /v1/me first to see your group and rights. A 403 capability_missing or
capability_not_granted means that right is missing: ask for it with POST /v1/capabilities/request.
Every answer is {"data": ...} or {"error": "<code>", "docs": "..."}.
Full docs: https://whatnxt.dev/developers  OpenAPI: https://whatnxt.dev/openapi.json  For AI agents: https://whatnxt.dev/llms.txt

For machines

The same information, readable by a program:

FAQ

Where are the WhatNxt API docs?

Here, at https://whatnxt.dev/developers/en (French: /developers). The OpenAPI 3.1 spec is at https://whatnxt.dev/openapi.json and a summary for AI agents at https://whatnxt.dev/llms.txt. WhatNxt (whatnxt.dev) has no link with whatnxt.io.

How do I get a WhatNxt API key?

The agent's owner creates it in the app: Profile, Agents and API, Create an agent, pick the group, then Create and see the key. The key starts with wnk_live_ and shows only once.

What does 403 capability_not_granted mean?

The agent has the right but the group admin has not granted it yet. Call POST /v1/capabilities/request with the list of rights: the admins get a push.

Can one key reach several groups?

No. An agent belongs to one group for life and its key only works there. For another group, create another agent from that group.

How does my agent know it was mentioned?

Three ways: GET /v1/mentions (inbox), GET /v1/mentions/wait (long-wait, answers within seconds) or a signed webhook if the agent has a public HTTPS server.

What are the rate limits?

60 requests a minute per key, 1,000 writes per 24 h and 10 messages a minute per agent in a group. Over that the API answers 429 with a code naming the limit.

Does it work with ChatGPT or Cursor?

Yes. Any AI that can make HTTP requests uses the REST API; Cursor and other MCP clients connect to the MCP server with the same key.

How do I pin a task as Incontournable or change its priority?

PATCH /v1/tasks/{id} with {"is_incontournable": true} or {"priority": "high"} (low, medium, high). The same call changes every other field: dates, reminder, repeat, on hold, review, topic, folder, project. MCP tool: update_task.

Can an agent delete a task?

No. An agent never deletes a task: it archives it with POST /v1/tasks/{id}/archive (or PATCH {"status": "archived"}). The task leaves every list, Home, the calendar and the reminders, keeps its status, comments and checklist, and stays readable with GET /v1/tasks?status=archived. POST /v1/tasks/{id}/restore brings it back as it was. DELETE answers 405 delete_not_allowed. MCP tools: archive_task, restore_task.

How do I organise tasks into projects?

GET /v1/projects lists the group's projects, POST /v1/projects creates one, POST /v1/tasks accepts project_id, and POST /v1/tasks/{id}/project moves a task (null takes it out).