Tasks live in a list, on a board, in a team. This walks that hierarchy and creates a task — for example to follow up on an email you're working.
Needs a key with tasks.write (and boards.read / lists.read to discover ids). See Authenticate first.
curl "https://api.sortd.com/v2/teams" \
-H "Authorization: Bearer sk_live_…"
# -> { "data": [ { "id": "<team_id>", "name": "Acme" } ], "meta": { … } }
curl "https://api.sortd.com/v2/boards?team_id=<team_id>" \
-H "Authorization: Bearer sk_live_…"
# -> { "data": [ { "id": "brd_…", "name": "Support", "board_type": "shared" } ], … }
curl "https://api.sortd.com/v2/boards/brd_…/lists" \
-H "Authorization: Bearer sk_live_…"
# -> { "data": [ { "id": "lst_…", "name": "To do", "board_id": "brd_…" } ], … }
Send list_id and title (required), plus optional notes and due_at. Include an Idempotency-Key so a retried request can't create a duplicate.
# curl
curl -X POST "https://api.sortd.com/v2/tasks" \
-H "Authorization: Bearer sk_live_…" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: <unique-key>" \
-d '{
"list_id": "lst_…",
"title": "Follow up with Acme re: renewal",
"notes": "Thread: \"Q3 renewal\" from jane@acme.com",
"due_at": "2026-06-15T09:00:00Z"
}'
// JavaScript (fetch)
const res = await fetch("https://api.sortd.com/v2/tasks", {
method: "POST",
headers: {
Authorization: "Bearer sk_live_…",
"Content-Type": "application/json",
"Idempotency-Key": crypto.randomUUID(),
},
body: JSON.stringify({
list_id: "lst_…",
title: "Follow up with Acme re: renewal",
notes: "Thread: \"Q3 renewal\" from jane@acme.com",
}),
});
const { data } = await res.json();
// C# (HttpClient)
using var client = new HttpClient();
client.DefaultRequestHeaders.Authorization =
new AuthenticationHeaderValue("Bearer", "sk_live_…");
client.DefaultRequestHeaders.Add("Idempotency-Key", Guid.NewGuid().ToString());
var content = new StringContent("""
{ "list_id": "lst_…", "title": "Follow up with Acme re: renewal" }
""", Encoding.UTF8, "application/json");
var res = await client.PostAsync("https://api.sortd.com/v2/tasks", content);
var json = await res.Content.ReadAsStringAsync();
# Python (requests)
import requests, uuid
res = requests.post(
"https://api.sortd.com/v2/tasks",
headers={
"Authorization": "Bearer sk_live_…",
"Idempotency-Key": str(uuid.uuid4()),
},
json={"list_id": "lst_…", "title": "Follow up with Acme re: renewal"},
)
task = res.json()["data"]
{
"data": {
"id": "tsk_…",
"title": "Follow up with Acme re: renewal",
"list_id": "lst_…",
"board_id": "brd_…",
"completed": false,
"due_at": "2026-06-15T09:00:00Z",
"created_at": "2026-06-09T12:00:00Z"
},
"meta": { "request_id": "req_…" }
}
When Sortd links a task to an email internally, the task's read-only first_thread object (subject, sender, received date) is returned on GET /tasks/{id}. Mark it done later with POST /tasks/{id}/complete, or move it with POST /tasks/{id}/move.
PATCH /tasks/{id} is a partial update — send only what changes. It supports the task colour (the shade field) as a named value; "none" clears it.
shade: red · orange · deep_orange · amber · yellow · yellow_green · lime · green · teal · cyan · light_blue · blue · indigo · purple · magenta · pink · brown · grey · dark_grey · black · none
# curl — set the task colour to red
curl -X PATCH "https://api.sortd.com/v2/tasks/tsk_…" \
-H "Authorization: Bearer sk_live_…" \
-H "Content-Type: application/json" \
-d '{ "shade": "red" }'
// JavaScript — clear the colour
await fetch("https://api.sortd.com/v2/tasks/tsk_…", {
method: "PATCH",
headers: { Authorization: "Bearer sk_live_…", "Content-Type": "application/json" },
body: JSON.stringify({ shade: "none" }),
});
# Python — set the colour to lime
import requests
requests.patch(
"https://api.sortd.com/v2/tasks/tsk_…",
headers={"Authorization": "Bearer sk_live_…"},
json={"shade": "lime"},
)
The response is the full updated task, with shade as a colour name.
Tags and status are custom fields, set through the same PATCH. First read the board's fields to get each field_id and, for tag/status/select fields, the option ids:
curl "https://api.sortd.com/v2/boards/brd_…/custom-fields" \
-H "Authorization: Bearer sk_live_…"
# -> { "data": [
# { "id": "cf_status", "name": "Status", "type": "status",
# "options": [ { "id": "opt_open", "label": "Open" }, { "id": "opt_done", "label": "Done" } ] },
# { "id": "cf_priority", "name": "Priority", "type": "tag",
# "options": [ { "id": "opt_hi", "label": "High" }, { "id": "opt_lo", "label": "Low" } ] }
# ], … }
Then set values by field_id. For tag/status/select, value is an array of option ids ([] clears it); for text/number/date it's the raw value. Needs the customfields.write scope.
Fields flagged "ai": true (managed by Sortd AI, e.g. Response Status) are read-only — setting them returns a 400.
# curl — set Status = Open and Priority = High
curl -X PATCH "https://api.sortd.com/v2/tasks/tsk_…" \
-H "Authorization: Bearer sk_live_…" \
-H "Content-Type: application/json" \
-d '{
"custom_fields": [
{ "field_id": "cf_status", "value": ["opt_open"] },
{ "field_id": "cf_priority", "value": ["opt_hi"] }
]
}'
// JavaScript — set a text custom field
await fetch("https://api.sortd.com/v2/tasks/tsk_…", {
method: "PATCH",
headers: { Authorization: "Bearer sk_live_…", "Content-Type": "application/json" },
body: JSON.stringify({ custom_fields: [{ field_id: "cf_ref", value: "ACME-1234" }] }),
});
# Python — change a colour and a custom field in one call
import requests
requests.patch(
"https://api.sortd.com/v2/tasks/tsk_…",
headers={"Authorization": "Bearer sk_live_…"},
json={
"shade": "red",
"custom_fields": [{"field_id": "cf_status", "value": ["opt_done"]}],
},
)
The updated task's custom_fields holds the stored values — option ids for tag/status; resolve their labels via the board's custom-fields endpoint above.
Next: classify a thread with AI.