Sortd Docs

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):

FieldEffect
"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 specificPOST /tasks with position / after_task_id
Send a task to another list, placedPOST /tasks/{id}/move with list_id + placement
Reposition within the same listPOST /tasks/{id}/reorder

A same-list move is a no-op — use reorder for that.

Next: classify a thread with AI.