Where a card sits in its list is part of the work — it's the team's priority order. This guide covers placing tasks when you create or move them, repositioning existing ones, and rewriting a whole list's order (say, from an AI prioritiser).
Everything here needs a key with tasks.write. See Authenticate first.
Three endpoints take the same two placement fields — POST /tasks (create), POST /tasks/{id}/move (to another list) and POST /tasks/{id}/reorder (within the current list):
| Field | Effect |
|---|---|
"position": "top" | Top of the list. The default for create and move — an API-created card behaves like an automation-created one. |
"position": "bottom" | Bottom of the list. |
"after_task_id": "tsk_…" | Directly below that task. Takes precedence over position, and it's the reliable way to build an exact order — an anchor stays correct even if other cards move, where a numeric index goes stale the moment anything else changes. |
POST /tasks/{id}/reorder moves a task within its current list. Send after_task_id or position (at least one; the anchor wins if both).
curl -X POST "https://api.sortd.com/v2/tasks/tsk_b/reorder" \
-H "Authorization: Bearer sk_live_…" \
-H "Content-Type: application/json" \
-d '{ "after_task_id": "tsk_a" }'
# curl — send a task to the bottom
curl -X POST "https://api.sortd.com/v2/tasks/tsk_b/reorder" \
-H "Authorization: Bearer sk_live_…" \
-H "Content-Type: application/json" \
-d '{ "position": "bottom" }'
await fetch("https://api.sortd.com/v2/tasks/tsk_b/reorder", {
method: "POST",
headers: { Authorization: "Bearer sk_live_…", "Content-Type": "application/json" },
body: JSON.stringify({ after_task_id: "tsk_a" }),
});
import requests
requests.post(
"https://api.sortd.com/v2/tasks/tsk_b/reorder",
headers={"Authorization": "Bearer sk_live_…"},
json={"after_task_id": "tsk_a"},
)
Reorders are serialised per list on the server, and the response reports the position the database actually recorded — which can differ from what you asked for if the anchor moved between your read and your write:
{
"data": {
"id": "tsk_b",
"after_task_id": "tsk_a", // where it really landed (null = top)
"position_index": 3,
"persisted": true // false = nothing was written; re-read and retry
},
"meta": { "request_id": "req_…" }
}
An agent rewriting an order should read these back rather than assume its own placement happened.
To make a list match a target order — for example, a model's priority ranking — walk the desired order front to back and anchor each task to the one before it. The first goes to the top; every next one goes after its predecessor. Anchors keep the walk correct even while other people (or automations) touch the list.
async function applyOrder(rankedTaskIds /* e.g. from your model */) {
const H = { Authorization: "Bearer sk_live_…", "Content-Type": "application/json" };
let previous = null;
for (const taskId of rankedTaskIds) {
const body = previous ? { after_task_id: previous } : { position: "top" };
const res = await fetch(`https://api.sortd.com/v2/tasks/${taskId}/reorder`, {
method: "POST", headers: H, body: JSON.stringify(body),
});
const { data } = await res.json();
if (!data.persisted) throw new Error(`reorder of ${taskId} did not persist — re-read the list`);
previous = taskId;
}
}
import requests
H = {"Authorization": "Bearer sk_live_…"}
def apply_order(ranked_task_ids):
previous = None
for task_id in ranked_task_ids:
body = {"after_task_id": previous} if previous else {"position": "top"}
res = requests.post(
f"https://api.sortd.com/v2/tasks/{task_id}/reorder",
headers=H, json=body,
)
if not res.json()["data"]["persisted"]:
raise RuntimeError(f"reorder of {task_id} did not persist")
previous = task_id
Read the list first with GET /tasks?list_id=lst_… to get the ids you're ranking. Boards render live over Socket.IO, so the user watches the list rearrange as the walk runs.
The same fields work at creation (both plain and from-email) and on a cross-list move — so you rarely need a separate reorder call after either:
# curl — create at the bottom (batches keep their order this way)
curl -X POST "https://api.sortd.com/v2/tasks" \
-H "Authorization: Bearer sk_live_…" -H "Content-Type: application/json" \
-d '{ "list_id": "lst_…", "title": "Step 1", "position": "bottom" }'
# curl — move to another list, landing below a specific card
curl -X POST "https://api.sortd.com/v2/tasks/tsk_…/move" \
-H "Authorization: Bearer sk_live_…" -H "Content-Type: application/json" \
-d '{ "list_id": "lst_other", "after_task_id": "tsk_anchor" }'
Watch out for reversed batches: the default placement is top, so creating N tasks in a loop without position: "bottom" stacks them newest-first — the opposite of the order you created them in.
| You want to… | Call |
|---|---|
| Create a task somewhere specific | POST /tasks with position / after_task_id |
| Send a task to another list, placed | POST /tasks/{id}/move with list_id + placement |
| Reposition within the same list | POST /tasks/{id}/reorder |
A same-list move is a no-op — use reorder for that.
Next: classify a thread with AI.