---
title: Tasks
description: Read and manage the to-do items on the /tasks list.
product: signal
section: api
order: 18
---

# Tasks

The `/tasks` endpoints manage a to-do list of items with a title, due date, priority and status, linked to a Deal, Contact, Account or prospect contact.

**Looking for Actions?** Signal's Actions are [activities](activities.md) with `type_id` `rat_action`. To create an Action that appears in Signal's Actions list, use `POST /activities`. Items created with `/tasks` are stored separately: they show on a linked prospect contact's page in Signal, not in the Actions list.


## The task object

| Field | Type | Notes |
| --- | --- | --- |
| `id` | string | 25-character ID. |
| `title` | string | |
| `description` | string or null | |
| `due_at` | string or null | ISO 8601 timestamp. |
| `priority` | string or null | Defaults to `medium`. |
| `is_completed` | boolean | |
| `completed_at` | string or null | Set when the item is marked complete. |
| `status_id` | string or null | See [Status IDs](#status-ids). |
| `account_id` | string or null | |
| `contact_id` | string or null | |
| `deal_id` | string or null | |
| `prospect_id` | string or null | |
| `owner_id` | string or null | User ID of the person responsible. |
| `created_at` | string | ISO 8601 timestamp. |
| `updated_at` | string | ISO 8601 timestamp. |

```json
{
  "id": "cm3k9x7r20011qz8fb4e2c9d1",
  "title": "Call back about pricing",
  "description": null,
  "due_at": "2026-11-15T17:00:00.000Z",
  "priority": "high",
  "is_completed": false,
  "completed_at": null,
  "status_id": "rts_todo",
  "account_id": null,
  "contact_id": null,
  "deal_id": null,
  "prospect_id": "e4b7c1d9-2f6a-4b3e-9c8d-5a1f7e2b4c63",
  "owner_id": "5b8d1f3a-7e2c-4a9b-b6d4-1c3e5f7a9b20",
  "created_at": "2026-11-12T09:30:00.000Z",
  "updated_at": "2026-11-12T09:30:00.000Z"
}
```

## Status IDs

| `status_id` | Status |
| --- | --- |
| `rts_todo` | To Do |
| `rts_in_progress` | In Progress |
| `rts_blocked` | Blocked |
| `rts_done` | Done |
| `rts_cancelled` | Cancelled |

`status_id` and `is_completed` are separate fields. Setting one doesn't change the other.

---

## List tasks

`GET /tasks` · Scope: `tasks:read`

Returns items newest first.

### Query parameters

| Parameter | Type | Required | Notes |
| --- | --- | --- | --- |
| `deal_id` | string | No | |
| `contact_id` | string | No | |
| `account_id` | string | No | |
| `prospect_id` | string | No | |
| `owner_id` | string | No | |
| `is_completed` | string | No | `true` for completed items only. Any other value returns open items only. Leave out for both. |
| `limit` | integer | No | 1 to 100. Default 20. |
| `cursor` | string | No | `meta.cursor` from the previous page. |

### Example

```bash
curl "https://crm.empiraa.app/api/v1/tasks?owner_id=5b8d1f3a-7e2c-4a9b-b6d4-1c3e5f7a9b20&is_completed=false" \
  -H "Authorization: Bearer YOUR_API_KEY"
```

```js
const url = new URL("https://crm.empiraa.app/api/v1/tasks");
url.searchParams.set("owner_id", "5b8d1f3a-7e2c-4a9b-b6d4-1c3e5f7a9b20");
url.searchParams.set("is_completed", "false");
const res = await fetch(url, { headers: { Authorization: "Bearer YOUR_API_KEY" } });
```

### Response `200`

An array of [task objects](#the-task-object) in `data`; `meta` has `cursor` and `hasMore`.

---

## Create a task

`POST /tasks` · Scope: `tasks:write`

### Request body

| Field | Type | Required | Notes |
| --- | --- | --- | --- |
| `title` | string | Yes | |
| `description` | string or null | No | |
| `due_at` | string or null | No | ISO 8601 timestamp. |
| `priority` | string or null | No | Defaults to `medium`. |
| `status_id` | string or null | No | See [Status IDs](#status-ids). |
| `account_id` | string or null | No | |
| `contact_id` | string or null | No | |
| `deal_id` | string or null | No | |
| `prospect_id` | string or null | No | |
| `owner_id` | string or null | No | A user ID from `GET /users`. |

The linked records must be in your workspace and `owner_id` must be an active member, or the request answers `404 NOT_FOUND`. See [Linked records](../conventions.md#linked-records).

### Example

```bash
curl -X POST https://crm.empiraa.app/api/v1/tasks \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"title": "Call back about pricing", "due_at": "2026-11-15T17:00:00Z", "priority": "high", "prospect_id": "e4b7c1d9-2f6a-4b3e-9c8d-5a1f7e2b4c63"}'
```

```js
await fetch("https://crm.empiraa.app/api/v1/tasks", {
  method: "POST",
  headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json" },
  body: JSON.stringify({
    title: "Call back about pricing",
    due_at: "2026-11-15T17:00:00Z",
    priority: "high",
    prospect_id: "e4b7c1d9-2f6a-4b3e-9c8d-5a1f7e2b4c63",
  }),
});
```

### Response `201`

The new [task object](#the-task-object) in `data`.

### Errors

| Status | Code | When |
| --- | --- | --- |
| 400 | `INVALID_REQUEST` | `title` is missing, `due_at` isn't a date, or a linked id isn't a string or `null`. |
| 404 | `NOT_FOUND` | A linked Account, Contact, Deal or prospect contact isn't in this workspace (`title` says which), or `owner_id` isn't an active member of the workspace. |

**Webhook events:** none. Starts any Autopilot workflows that run when a task is created.

---

## Get a task

`GET /tasks/{id}` · Scope: `tasks:read`

### Example

```bash
curl https://crm.empiraa.app/api/v1/tasks/cm3k9x7r20011qz8fb4e2c9d1 \
  -H "Authorization: Bearer YOUR_API_KEY"
```

```js
await fetch("https://crm.empiraa.app/api/v1/tasks/cm3k9x7r20011qz8fb4e2c9d1", {
  headers: { Authorization: "Bearer YOUR_API_KEY" },
});
```

### Response `200`

The [task object](#the-task-object) in `data`.

### Errors

| Status | Code | When |
| --- | --- | --- |
| 404 | `NOT_FOUND` | No task with that ID in this workspace. |

---

## Update a task

`PATCH /tasks/{id}` · Scope: `tasks:write`

Send only the fields you want to change: any field from [create](#create-a-task), plus `is_completed` (boolean). Setting `is_completed` to `true` sets `completed_at` to now; `false` clears it.

### Example

```bash
curl -X PATCH https://crm.empiraa.app/api/v1/tasks/cm3k9x7r20011qz8fb4e2c9d1 \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"is_completed": true, "status_id": "rts_done"}'
```

```js
await fetch("https://crm.empiraa.app/api/v1/tasks/cm3k9x7r20011qz8fb4e2c9d1", {
  method: "PATCH",
  headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json" },
  body: JSON.stringify({ is_completed: true, status_id: "rts_done" }),
});
```

### Response `200`

The updated [task object](#the-task-object) in `data`.

### Errors

| Status | Code | When |
| --- | --- | --- |
| 400 | `INVALID_REQUEST` | `due_at` isn't a date, or a linked id isn't a string or `null`. |
| 404 | `NOT_FOUND` | No task with that ID in this workspace, a linked record isn't in it, or `owner_id` isn't an active member of the workspace. |

**Webhook events:** none. Starts any Autopilot workflows that run when a task is updated or completed.

---

## Delete a task

`DELETE /tasks/{id}` · Scope: `tasks:write`

Deletes the item permanently.

### Example

```bash
curl -X DELETE https://crm.empiraa.app/api/v1/tasks/cm3k9x7r20011qz8fb4e2c9d1 \
  -H "Authorization: Bearer YOUR_API_KEY"
```

```js
await fetch("https://crm.empiraa.app/api/v1/tasks/cm3k9x7r20011qz8fb4e2c9d1", {
  method: "DELETE",
  headers: { Authorization: "Bearer YOUR_API_KEY" },
});
```

### Response `204`

No body.

### Errors

| Status | Code | When |
| --- | --- | --- |
| 404 | `NOT_FOUND` | No task with that ID in this workspace. |

**Webhook events:** none. Starts any Autopilot workflows that run when a task is deleted.
