REST API
Hypertask’s public REST API is available at https://app.hypertask.ai/api/v1. Use it to list projects, create and update tasks, manage comments, assign users, read inbox notifications, and manage task drafts.
Authentication
Section titled “Authentication”Send an API key in the Authorization header:
Authorization: Bearer htk_...Create API keys in the Hypertask app with Ctrl+K -> REST API. Each user can have up to 10 active keys. The full key is shown once when it is created, and keys can be revoked from the same modal.
export HT_API_KEY=htk_...
curl -s -H "Authorization: Bearer $HT_API_KEY" \ "https://app.hypertask.ai/api/v1/user/context"Error responses use this general shape:
{ "success": false, "error": "Validation error", "message": "project_id must be a positive integer", "details": { "field": "project_id", "code": "invalid_type" }}Session-validated identity
Section titled “Session-validated identity”Previously, several public API routes accepted an unsigned nookies_user cookie as the authenticated user identity. This has been tightened to prevent account takeover via forged cookies:
- Routes that set
nookies_user.idnow require a valid, matching signedht_sessioncookie with the sameidvalue to succeed. - The following route families are affected:
- Auth routes (e.g.,
/api/auth/*) - MCP routes (
/api/mcp/*) - Other 64 public sub-paths previously relying on unsigned nookies_user
- All associated webhook and logged-out call sites
- Auth routes (e.g.,
Verified live on production: forging nookies_user={"id":6} now returns 401 instead of 200+ full data, and forging {"id":1} for any other user also returns 401.
Compatibility: The consensus across the auth, MCP, public, webhook, logged-out, and Bearer-auth request families is that this change does not affect existing integrations or tools:
- Auth requests with standard
Authorization: Bearer $HT_API_KEYcontinue to work. - MCP tools retain their same param schema.
- Public integrations that already manage
ht_sessionvia the app workload continue untouched. - Work that previously shipped
nookies_userdirectly (e.g., via server-to-server calls) should now explicitly sign or addht_sessionwith the sameid, but it is a rare pattern in practice.
If your pattern relies on unsigned nookies_user outside these call sites, see /api/session/verify to validate the signed session instead.
createMention API
Section titled “createMention API”The createMention API endpoint now requires a verified authentication session. Mentions are no longer an open push channel that trusts caller-supplied identifiers:
- All requests to
POST /api/v1/commentswith amentionsarray now require verification against the signedht_session. - The
mentionedByfield in the request is ignored; it is derived automatically from the authenticated user’s session. - The endpoint validates that the task, the initiator, and the recipient all belong to the same board before creating the mention.
- Attempting to forge mentions or cross-board mentions returns an
401 Unauthorizedresponse.
API user routes require authentication
Section titled “API user routes require authentication”The following API routes have been secured to require authentication:
POST /api/resetUser— admin tool for resetting user state. Takes the samex-admin-passwordheader check as thereset-trialendpoint.GET /api/users/search— searches available users by name or email. Requires a signedht_sessioncookie.GET /api/users/getByEmails— returns users matching one or more email addresses. Requires a signedht_sessioncookie.
These routes were previously accessible without an authenticated session. Requests made without valid authentication now receive 401 Unauthorized.
Deprecated and removed endpoints
Section titled “Deprecated and removed endpoints”The following endpoints have been removed as they were not actively used by any client:
GET /api/comments/getAll— useGET /api/v1/commentsinstead.GET /api/comments/single— useGET /api/v1/commentswith a specificticket_numberortask_id.POST /api/notifications/oneOffUpdateScript— use the standard notification management endpoints under/api/v1/notifications/or the app’s ability to schedule notification preferences.
Knowing these endpoints were already unused, this change does not affect integrations.
Webhooks
Section titled “Webhooks”Webhooks let external systems subscribe to events on your Hypertask tasks. When an event occurs (such as a task being created, assigned, or updated), Hypertask sends a POST request to your configured webhook URL with the event payload.
Event Types
Section titled “Event Types”Webhook events travel through your subscription’s metadata and are emitted when tasks in that subscription are created, assigned, or updated.
| Event name | Description |
|---|---|
task.created | Fired when a new task is created. |
task.assigned | Fired when a task is assigned to a user or agent. |
task.updated | Fired when a task is modified (title, description, priority, sections, etc.). |
Payload Shape
Section titled “Payload Shape”Each webhook event payload follows this shape:
{ "event": "task.created | task.assigned | task.updated", "task_id": 789, "ticket_number": "ENG-42", "project_id": 123, "data": { // Event-specific metadata }, "timestamp": "2026-08-08T10:30:00Z"}Subscriptions
Section titled “Subscriptions”Create or update a subscription to define which webhook events to listen to. The subscription’s metadata field is used to signal the relevant task lifecycle events for that subscription through headers such as:
X-Event-Type: task.createdX-Event-Type: task.assignedX-Event-Type: task.updated
When metadata is set correctly on a subscription, Hypertask emits task lifecycle events to your webhook endpoint for tasks within that subscription’s scope.
Example Subscription Update
Section titled “Example Subscription Update”To enable task lifecycle events on a subscription, update its metadata to include signal headers:
curl -s -X PATCH \ -H "Authorization: Bearer $HT_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "metadata": { "X-Event-Type": ["task.created", "task.assigned", "task.updated"] } }' \ "https://app.hypertask.ai/api/v1/webhook/subscriptions/SUB_ID"Deliveries
Section titled “Deliveries”- Each event is delivered once per subscription when the corresponding task state changes.
- Events are queued and sent when subscribed to; updating subscription metadata provides visibility into which events are active.
- The payload includes explicit
task_id,ticket_number, andproject_idfor routing.
Calling the API Directly from Agents
Section titled “Calling the API Directly from Agents”The Hypertask CLI is a thin wrapper around the REST API. Every CLI command ultimately calls a route under https://app.hypertask.ai/api/mcp/*. You can call those same routes directly with curl or any HTTP client, bypassing the Node.js process startup cost.
Measured from a VPS, the difference is substantial:
| Method | Typical latency |
|---|---|
curl direct to REST API | ~0.21 s |
hypertask CLI | ~0.84 – 1.06 s |
The gap is almost entirely Node.js cold-start time. For agents that issue many sequential calls, this adds up quickly.
How the routes map:
- The
api/v1routes documented on this page are the public, versioned REST API — use these for integrations and scripts. - The
api/mcp/*routes are the same operations that the CLI and MCP server use internally. They accept the same authentication header (Authorization: Bearer htk_...).
For agent workloads that currently shell out to the CLI, switching to direct curl calls against either the api/v1 or api/mcp/* routes is a straightforward way to cut per-operation latency by ~4×.
Saved view subtask display
Section titled “Saved view subtask display”Create or update a saved view through the MCP-compatible REST routes to control the same five-mode subtask setting available from the board’s Ctrl+K menu:
# Create a view that shows subtasks as rows and on parent cardscurl -s -X POST \ -H "Authorization: Bearer $HT_API_KEY" \ -H "Content-Type: application/json" \ -d '{"project_id":15,"title":"All subtasks","subtask_setting":"Flattened_Card"}' \ "https://app.hypertask.ai/api/mcp/view"
# Change only the subtask display mode; other view settings stay unchangedcurl -s -X PATCH \ -H "Authorization: Bearer $HT_API_KEY" \ -H "Content-Type: application/json" \ -d '{"subtask_setting":"Parent"}' \ "https://app.hypertask.ai/api/mcp/view/VIEW_ID"Accepted values are None, Parent, Flattened, Card, and Flattened_Card. View responses report the effective value as board_subtask_setting.
Task Identifiers
Section titled “Task Identifiers”Routes that operate on a specific task usually accept exactly one task identifier:
Use the internal task ID:
{ "task_id": 789 }Use the project ticket number. Add project_id when ticket numbers may be ambiguous.
{ "ticket_number": "ENG-42", "project_id": 123 }Use the project-scoped task index with project_id.
{ "project_id": 123, "unique_index": 42 }Get User Context
Section titled “Get User Context”Return the authenticated user, accessible teams, projects, and agents.
Endpoint: GET /api/v1/user/context
Parameters: None
Example request:
curl -s -H "Authorization: Bearer $HT_API_KEY" \ "https://app.hypertask.ai/api/v1/user/context"Response shape:
{ "success": true, "user": { "id": 6, "email": "valentin@example.com", "displayName": "Valentin" }, "connected_agent": null, "teams": [ { "id": "team_uuid", "title": "Product" } ], "projects": [ { "id": 123, "title": "Engineering", "labels": [], "sections": [] } ], "all_agents": [ { "id": "agent_uuid", "displayName": "Release Agent" } ]}Projects
Section titled “Projects”List Projects
Section titled “List Projects”List projects the API key owner can access.
Endpoint: GET /api/v1/projects
Query parameters:
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
status | string | No | Normal | Filter by Normal, Archive, or Deleted |
search | string | No | — | Search project title, name, or description |
limit | number | No | 50 | Max results, capped at 100 |
offset | number | No | 0 | Pagination offset |
sort_by | string | No | title | title, createdAt, or updatedAt |
sort_order | string | No | asc | asc or desc |
Example request:
curl -s -H "Authorization: Bearer $HT_API_KEY" \ "https://app.hypertask.ai/api/v1/projects?status=Normal&limit=20"Response shape:
{ "success": true, "projects": [ { "id": 123, "title": "Engineering", "description": "Product engineering work", "memberCount": 5, "taskCount": 42, "sections": [ { "id": 456, "section_title": "Todo" } ], "labels": [ { "id": "label_uuid", "name": "Customer" } ], "status": "Normal", "createdAt": "2026-03-10T12:00:00.000Z" } ], "total": 1, "limit": 20, "offset": 0}List Project Sections
Section titled “List Project Sections”List sections for a project board.
Endpoint: GET /api/v1/projects/{projectId}/sections
Path parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
projectId | number | Yes | Project ID |
Query parameters:
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
include_hidden | boolean | No | false | Include hidden sections |
Example request:
curl -s -H "Authorization: Bearer $HT_API_KEY" \ "https://app.hypertask.ai/api/v1/projects/123/sections?include_hidden=false"Response shape:
{ "success": true, "sections": [ { "id": 456, "section_title": "Todo", "projectId": 123, "visibility": true, "deleted": false, "ranking": "a0", "taskCount": 12 } ], "projectId": 123}Create Project Section
Section titled “Create Project Section”Create a section in a project.
Endpoint: POST /api/v1/projects/{projectId}/sections
Path parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
projectId | number | Yes | Project ID |
Body parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
title | string | Yes | Section name, 1 to 200 characters |
after_section_id | number | No | Insert the new section after this section ID |
Example request:
curl -s -X POST -H "Authorization: Bearer $HT_API_KEY" \ -H "Content-Type: application/json" \ -d '{"title":"QA","after_section_id":456}' \ "https://app.hypertask.ai/api/v1/projects/123/sections"Response shape:
{ "success": true, "section": { "id": 457, "section_title": "QA", "projectId": 123, "taskCount": 0 }, "message": "Section created successfully"}Update Project Section
Section titled “Update Project Section”Rename or reorder a section.
Endpoint: PATCH /api/v1/projects/{projectId}/sections/{sectionId}
Path parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
projectId | number | Yes | Project ID |
sectionId | number | Yes | Section ID |
Body parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
title | string | No | New section name |
move_after_section_id | number | No | Move the section after this section ID |
Provide at least one body parameter.
Example request:
curl -s -X PATCH -H "Authorization: Bearer $HT_API_KEY" \ -H "Content-Type: application/json" \ -d '{"title":"Ready for QA"}' \ "https://app.hypertask.ai/api/v1/projects/123/sections/456"Response shape:
{ "success": true, "section": { "id": 456, "section_title": "Ready for QA", "projectId": 123, "taskCount": 4 }, "message": "Section updated successfully"}Delete Project Section
Section titled “Delete Project Section”Delete a section and move its tasks to the first remaining section.
Endpoint: DELETE /api/v1/projects/{projectId}/sections/{sectionId}
Path parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
projectId | number | Yes | Project ID |
sectionId | number | Yes | Section ID |
Example request:
curl -s -X DELETE -H "Authorization: Bearer $HT_API_KEY" \ "https://app.hypertask.ai/api/v1/projects/123/sections/456"Response shape:
{ "success": true, "message": "Section deleted successfully"}Create Project Label
Section titled “Create Project Label”Create a label in a project.
Endpoint: POST /api/v1/projects/{projectId}/labels
Path parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
projectId | number | Yes | Project ID |
Body parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
name | string | Yes | Label name, 1 to 100 characters. Must be unique in the project. |
Example request:
curl -s -X POST -H "Authorization: Bearer $HT_API_KEY" \ -H "Content-Type: application/json" \ -d '{"name":"Customer"}' \ "https://app.hypertask.ai/api/v1/projects/123/labels"Response shape:
{ "success": true, "label": { "id": "label_uuid", "name": "Customer" }, "message": "Label \"Customer\" created successfully"}List Project Members
Section titled “List Project Members”List project members for mentions and assignment.
Endpoint: GET /api/v1/projects/{projectId}/members
Path parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
projectId | number | Yes | Project ID |
Example request:
curl -s -H "Authorization: Bearer $HT_API_KEY" \ "https://app.hypertask.ai/api/v1/projects/123/members"Response shape:
{ "success": true, "members": [ { "id": 6, "email": "valentin@example.com", "displayName": "Valentin" } ], "projectId": 123}Add Project Member
Section titled “Add Project Member”Invite or add a project member by email or user ID.
Endpoint: POST /api/v1/projects/{projectId}/members
Path parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
projectId | number | Yes | Project ID |
Body parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
userToAdd | string or number | Yes | Email address or positive integer user ID |
Example request:
curl -s -X POST -H "Authorization: Bearer $HT_API_KEY" \ -H "Content-Type: application/json" \ -d '{"userToAdd":"teammate@example.com"}' \ "https://app.hypertask.ai/api/v1/projects/123/members"Response shape:
{ "success": true, "projectId": 123}Remove Project Member
Section titled “Remove Project Member”Remove a project member by email or user ID.
Endpoint: DELETE /api/v1/projects/{projectId}/members
Path parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
projectId | number | Yes | Project ID |
Body parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
userToRemove | string or number | Yes | Email address or positive integer user ID |
Example request:
curl -s -X DELETE -H "Authorization: Bearer $HT_API_KEY" \ -H "Content-Type: application/json" \ -d '{"userToRemove":"teammate@example.com"}' \ "https://app.hypertask.ai/api/v1/projects/123/members"Response shape:
{ "success": true, "projectId": 123, "message": "Member removed successfully"}Create Team Board
Section titled “Create Team Board”Create a board under a team from a structured manifest. Find team IDs with GET /api/v1/user/context.
Endpoint: POST /api/v1/teams/{teamId}/boards
Path parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
teamId | string | Yes | Team UUID |
Headers:
| Header | Required | Description |
|---|---|---|
Idempotency-Key | No | Replays with the same key and same body return the cached successful response for 24 hours |
Body parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
title | string | Yes | Board title, 1 to 200 characters |
description | string | No | Board description |
sections | object[] | Yes | 1 to 50 sections. Each item: { "title": string } |
labels | object[] | No | Up to 100 labels. Each item: { "name": string, "color"?: string }. color is accepted but not persisted. |
tasks | object[] | No | Up to 500 starter tasks |
tasks[].title | string | Yes | Task title, 1 to 500 characters |
tasks[].description | string | No | HTML task description |
tasks[].section_index | number | Conditional | Zero-based section index. Provide this or section_title, not both. |
tasks[].section_title | string | Conditional | Section title. Provide this or section_index, not both. |
tasks[].label_names | string[] | No | Label names defined in the same manifest |
tasks[].priority | number | No | 0 No Priority, 1 Urgent, 2 High, 3 Medium, 4 Low |
tasks[].estimate | number | No | 0 none, 2 XS, 3 S, 4 M, 5 L, 6 XL |
tasks[].due_date | string | No | ISO 8601 date or datetime |
Example request:
curl -s -X POST -H "Authorization: Bearer $HT_API_KEY" \ -H "Content-Type: application/json" \ -H "Idempotency-Key: board-import-001" \ -d '{ "title": "Launch", "sections": [ { "title": "Todo" }, { "title": "Done" } ], "labels": [ { "name": "Docs" } ], "tasks": [ { "title": "Draft launch plan", "section_index": 0, "label_names": ["Docs"], "priority": 2 } ] }' \ "https://app.hypertask.ai/api/v1/teams/team_uuid/boards"Response shape:
{ "success": true, "team_id": "team_uuid", "board": { "id": 123, "title": "Launch" }, "sections": [ { "id": 456, "title": "Todo" } ], "labels": [ { "id": "label_uuid", "name": "Docs" } ], "tasks": [ { "id": 789, "ticketNumber": "ENG-42", "title": "Draft launch plan" } ], "message": "Board created successfully"}Writing markdown instead of HTML
Section titled “Writing markdown instead of HTML”Descriptions and comments are stored as HTML, and hand-building that HTML is the single most common thing agents get wrong. Send content_type: "markdown" and the API converts it for you.
It is accepted on three routes:
| Route | Field converted |
|---|---|
POST /api/mcp/comments | text |
POST /api/mcp/tasks/create | description |
POST /api/mcp/tasks/update | description |
content_type is optional and takes "html" or "markdown". Omit it and nothing changes: the field is treated as HTML exactly as before. Any other value returns 400.
curl -X POST https://app.hypertask.ai/api/mcp/comments \ -H "Authorization: Bearer htk_..." \ -H "Content-Type: application/json" \ -d '{ "project_id": 15, "unique_index": 4467, "content_type": "markdown", "text": "Shipped. **Two** things changed:\n\n- the parser\n- the docs" }'GitHub Flavored Markdown is supported, so tables, fenced code and task lists all work.
Two conversions are deliberate and worth knowing before you rely on them:
- Images become links.
renders as an anchor, never an<img>. Inline images crash the editor, so this is not negotiable. An image with no URL falls back to its alt text. - Raw HTML in markdown source is escaped, not rendered. Writing
<script>in a markdown body produces the visible text<script>, not a live tag. If you want real HTML, sendcontent_type: "html".