# Reorder board nodes

> Set the display order of every node on a board in one atomic write.

Canonical page: https://www.rundiffusion.com/docs/api/boards/nodes-reorder
Endpoint: PUT /api/v2/boards/{board_id}/nodes/position
Authorization: OAuth device flow or Personal API Access Token or Company API Access Token

---

Set the order of a board's nodes. You send the whole order, not one node's new
place, and the board is rewritten in a single write.

`PUT /api/v2/boards/{board_id}/nodes/position`

Authorization: OAuth device flow or Personal API Access Token or Company API Access Token

Needs edit access to the board, described under
[Who can edit a board](/docs/api/boards/update#who-can-edit-a-board).

## Request

**Headers**

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `Authorization` | string | Yes | Bearer token. This endpoint accepts an OAuth device flow token, a Personal API Access Token, or a Company API Access Token. See [Authentication](/docs/api/authentication). |

**Path parameters**

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `board_id` | string | Yes | The board to reorder. |

**Body**

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `node_ids` | array | Yes | Every node ID on the board, in the order you want them. The list must be complete and contain no duplicates: anything else is a 409, described below. |

Read the board, move the IDs, send them back:

cURL:

```bash
curl -X PUT https://api2.rundiffusion.com/api/v2/boards/$BOARD_ID/nodes/position \
  -H "Authorization: Bearer $RUNDIFFUSION_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"node_ids": ["Nd7mQp…", "Nd4kWs…"]}'
```

JavaScript:

```javascript
// Move the last node to the front.
const board = await fetch(
  `https://api2.rundiffusion.com/api/v2/boards/${boardId}`,
  { headers },
).then(r => r.json());

const ids = board.nodes.map(node => node.id);
ids.unshift(ids.pop());

const nodes = await fetch(
  `https://api2.rundiffusion.com/api/v2/boards/${boardId}/nodes/position`,
  {
    method: 'PUT',
    headers: { ...headers, 'Content-Type': 'application/json' },
    body: JSON.stringify({ node_ids: ids }),
  },
).then(r => r.json());
```

Python:

```python
# Move the last node to the front.
board = requests.get(
    f"{BASE}/boards/{board_id}",
    headers=HEADERS,
).json()

ids = [node["id"] for node in board["nodes"]]
ids.insert(0, ids.pop())

nodes = requests.put(
    f"{BASE}/boards/{board_id}/nodes/position",
    headers=HEADERS,
    json={"node_ids": ids},
).json()
```

## Response

`200 OK` with every node in its new order, each carrying its new
`position.list_view_index`. The array is the board, so you can render from it
without refetching.

```json
[
  {
    "id": "Nd7mQp…",
    "created_at": "2026-07-30T14:05:44+00:00",
    "title": "Upscale",
    "description": null,
    "tool_id": "Tl2cRn…",
    "position": { "list_view_index": 0 }
  },
  {
    "id": "Nd4kWs…",
    "created_at": "2026-07-30T14:03:02+00:00",
    "title": "Flux Dev",
    "description": "Text to image",
    "tool_id": "Tl9xBv…",
    "position": { "list_view_index": 1 }
  }
]
```

## Why the whole list

Sending one node's new index would look simpler and would be unsafe. An index only
means something against a particular set of nodes, so if somebody adds or removes
a node between your read and your write, "move this to index 3" lands somewhere you
did not intend, and nothing detects it.

The full list makes that impossible to miss. It has to match the board exactly, so
if the board changed under you the request is refused rather than applied to a
board you have not seen:

> **409 BOARD_CHANGED means refetch**
>
> `node_ids` must contain every node currently on the board, exactly once. A
> missing ID, an extra one, an unknown one, or a duplicate all answer
> `409 BOARD_CHANGED` and change nothing.
>
> In practice it means somebody added or removed a node since you read the board.
> Fetch the board again, reapply your move to the new list, and send that. Do not
> retry the same payload: it will keep failing for the same reason.

Every node is rewritten on each call, so the order is always dense and 0-based
afterwards, whatever state it was in before.

## Errors

**Status codes**

| Name | Type | Description |
| --- | --- | --- |
| `400` | INVALID_REQUEST | node_ids missing or empty. |
| `401` | TOKEN_INVALID | Missing or invalid credential. |
| `403` | PERMISSION_DENIED | You can see the board but may not change what is on it. |
| `404` | BOARD_NOT_FOUND | No such board, or not one this credential can see. |
| `409` | BOARD_CHANGED | node_ids is not exactly the board's current nodes. Refetch the board and retry with the new list. |
| `429` | RATE_LIMITED | Too many requests. See [Rate limits](/docs/api/rate-limits#boards). |
