Move a card
Move a card to another list on its current board, or change its position within a list. Moves use the same board, list, and label IDs that you read from Get one board.
Request
PATCH /api/v1/cards/:cardId
The key needs the move permission. The key owner must also have the card:update role permission, which owner, admin, and member roles have. Guests can read cards but cannot move them. Column names are chosen by the board owner, so look up the destination list ID before you move a card.
| Field | Type | Required | Description |
|---|---|---|---|
listId | string | Yes | Destination list on the card's current board. |
position | integer, 0 or greater | No | Zero-based position in the destination list, counted after the card is removed from its current position. Omit it to append to a different list. |
expectedListId | string | No | The list ID you saw when you read the card. If the card is now in a different list, the request returns 409 conflict and does not move it. |
curl -X PATCH "https://projavo.com/api/v1/cards/<card-id>" \
-H "Authorization: Bearer $PROJAVO_API_KEY" \
-H "Content-Type: application/json" \
-d '{"listId":"<done-list-id>","expectedListId":"<backlog-list-id>"}'
const res = await fetch(`https://projavo.com/api/v1/cards/${cardId}`, {
method: "PATCH",
headers: {
Authorization: `Bearer ${process.env.PROJAVO_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({ listId: doneListId, expectedListId: backlogListId }),
});
Response
Response 200:
{
"card": { "id": "card_example", "listId": "list_done", "position": 3 }
}
The move keeps positions contiguous in both lists. It records a CARD_MOVED activity under the key owner's name and broadcasts the same live board update as a drag in the web app. If any step fails, the whole move is rolled back.
Errors
| Status | Code | Meaning |
|---|---|---|
400 | invalid_body | The body is not valid JSON. |
401 | missing_key, invalid_key | The key is missing, invalid, or revoked, or the owner is no longer active. |
403 | insufficient_scope | The key does not have the move permission. |
403 | forbidden | The owner's role cannot move cards, or the owner is not a member of the card's organization. |
404 | not_found | The card does not exist or is not accessible, or the destination list is not on the card's board. |
409 | conflict | expectedListId no longer matches the card's current list. |
422 | validation_error | A field is missing or invalid, for example a negative position or a listId that is empty. |
422 | invalid_position | position is beyond the end of the destination list. |
429 | RATE_LIMITED | More than 60 requests per minute from this key. |
See Errors for the full reference.
Retries and conflicts
If you omit position and the card is already in the destination list, the card stays where it is. A retry without expectedListId does not reorder the card or add a second activity. An explicit position can still reorder a card within its current list.
If expectedListId no longer matches, the response is:
{
"error": {
"code": "conflict",
"message": "Card has moved since it was read; read it again before moving it"
}
}
After a 409 or an uncertain network response, read the card again with Get one card. If the card is already in the destination you intended, the earlier move succeeded. Otherwise, check its current state before you retry with a new expectedListId.
The expectedListId check compares lists only. It does not detect title or description edits within the same list.