Order & reorder tasks
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.
The placement vocabulary
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. |
1. Reposition one task
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 — put a task directly below another
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" }'
JavaScript (fetch)
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" }),
});
Python (requests)
import requests
requests.post(
"https://api.sortd.com/v2/tasks/tsk_b/reorder",
headers={"Authorization": "Bearer sk_live_…"},
json={"after_task_id": "tsk_a"},
)
2. Trust the response, not your request
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.
3. Impose a whole new order (AI prioritisation)
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.
JavaScript — apply a ranked order to a 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;
}
}
Python — same walk
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.
4. Place a task when creating or moving it
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.
Which endpoint when?
| 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.