Move or copy a card to another board

How-toUpdated 9 min read
View as Markdown
On this page

A card can go to another board in two ways. Transfer moves the card itself: it keeps its id, comments, history, links and pull request, takes a new number on the target board, and its old number still opens it. Copy makes a second, independent card on the target board with its own number, linked to the original, which stays where it is. Both are available as REST routes, as opvs tasks transfer and opvs tasks copy in the CLI, and as the agent methods transferTask and copyTask.

Before you call

Every route takes a personal access token, Authorization: Bearer $OPVS_PAT, with the board:write scope. Both boards must belong to the workspace the token belongs to; a board of another workspace answers exactly like a board that does not exist.

Value

Accepts

task_id (path)

a card ref such as OPS-142, a UUID prefix of 8 or more hex characters, or a full UUID

board_id (body)

a board key such as OPS, a UUID prefix, or a full UUID

column_id (body)

a column name on the target board, case-insensitive, or a column UUID

Transfer or copy?

Transfer

Copy

Card id

kept

new

Card number

new number on the target board; the old ref keeps opening the card

new number on the target board

Title, description, brief, labels, priority, visible fields, routing

kept

carried over

Status, assignee

kept

not carried; the copy starts unassigned, with the status of its column

Comments, activity history, files

kept

not carried

Pull request, branch, dependencies, subtasks

kept

not carried

GitHub issue sync

follows the card to the new board

none; no issue is filed for the copy

Column when column_id is omitted

the column with the same name on the target board, otherwise the target's default column

the target board's default column

The original

is the card that moved

stays where it was; both cards get a system comment naming the other, and a related task link joins them

Neither route puts a card in a claimable column such as Ready unless column_id names it, so a move or a copy never hands work to a builder by accident.

Transfer a card

POST /api/v1/board/tasks/{task_id}/transfer

Moves the card to board_id. Returns 200 and the full task object on its new board.

Parameters

Name

In

Type

Required

Description

task_id

path

string

yes

The card to move

board_id

body

string

yes

The target board

column_id

body

string

no

The target column; see the defaults above

Example

curl -X POST "https://api.opvs.ai/api/v1/board/tasks/OPS-142/transfer" \
  -H "Authorization: Bearer $OPVS_PAT" \
  -H "Content-Type: application/json" \
  -d '{"board_id": "WEB"}'

# Response 200, application/json (trimmed to the fields that change)
# {"id": "ae0a05de-b41c-4e7f-823c-b13586b7f93b", "ref": "WEB-4", "number": 4,
#  "board_id": "244f9deb-0da1-4ddf-8354-a654f4347af8",
#  "column": {"name": "To Do", "slug": "todo", "mapped_status": "pending"},
#  "status": "pending", "comment_count": 2}
#
# GET /api/v1/board/tasks/OPS-142 now returns the same card, ref "WEB-4".
# 409 {"detail": "Card is already on the target board"} if it is already there.

Errors

Status

detail

When

Resolution

401

Not authenticated

no token, or the token is revoked or expired

send a valid Authorization: Bearer token

403

a scope message

the token lacks board:write

request a token that carries board:write

403

max_tasks_per_board

the target board is at its card limit

make room on the target board, or raise the plan limit

404

Task not found

the card does not exist or you cannot read it

check the ref; refs are board key plus number

404

Board not found

the target board does not exist or belongs to another workspace

check board_id; list boards with GET /api/v1/board/boards

404

Column '<name>' not found on this board.

column_id names no column on the target board

list the target's columns; names are matched on the target, not the source

422

board_id must be a non-empty string

the body has no board_id

send {"board_id": "…"}

422

Target board is archived

the target board is archived

unarchive it, or choose another board

422

Target board has a different board type

the boards are of different types, such as tasks and contacts

transfer only between boards of the same type

409

Card is already on the target board

board_id is the card's own board

to change column, use POST /api/v1/board/tasks/{task_id}/move

409

Cards in progress cannot be transferred

the card's status is in_progress

wait until it leaves in_progress, or copy it instead

409

Cards waiting on an answer cannot be transferred

the card is waiting_on_answer

answer the question on the card, then transfer

409

A build has just claimed this card

a builder claimed the card moments ago

wait for the build to finish or release

409

Ship Line cards move only when the ledger moves

the card is a Ship Line review card

these cards are moved by the ship ledger, not by hand

409

A card with a parent cannot be transferred

the card is a subtask

transfer its parent

409

A card with subtasks cannot be transferred

the card has subtasks

move or detach the subtasks, then transfer

409

A card with stages cannot be transferred

the card has stages

copy it instead, or finish the stages

Copy a card

POST /api/v1/board/tasks/{task_id}/copy

Creates a new card on board_id from the card's authored fields. Returns 201 and the full task object of the new card. The original is not changed, apart from the system comment naming the copy.

Parameters

Name

In

Type

Required

Description

task_id

path

string

yes

The card to copy

board_id

body

string

yes

The target board; it may be the card's own board

column_id

body

string

no

The column for the copy; defaults to the target's default column

Fields the caller cannot see are not copied. A copy made by a token that cannot read a hidden field leaves that field empty on the new card.

Example

curl -X POST "https://api.opvs.ai/api/v1/board/tasks/OPS-142/copy" \
  -H "Authorization: Bearer $OPVS_PAT" \
  -H "Content-Type: application/json" \
  -d '{"board_id": "WEB", "column_id": "To Do"}'

# Response 201, application/json (trimmed to the fields that matter here)
# {"id": "fd0d3abd-0f36-49a3-95f4-c751593c0c62", "ref": "WEB-3", "number": 3,
#  "title": "Fix the login redirect loop", "priority": "high", "labels": ["bug", "auth"],
#  "column": {"name": "To Do", "slug": "todo", "mapped_status": "pending"},
#  "status": "pending", "comment_count": 1}
#
# The one comment is the system note "Copied from OPS-142".
# 404 {"detail": "Column 'Nope' not found on this board. Use list_columns or get_board
#      to see available columns."} for an unknown column.

Errors

Status

detail

When

Resolution

401

Not authenticated

no token, or the token is revoked or expired

send a valid Authorization: Bearer token

403

a scope message

the token lacks board:write

request a token that carries board:write

403

max_tasks_per_board

the target board is at its card limit

make room on the target board, or raise the plan limit

429

board_writes_per_day

the workspace used its daily board writes; a copy counts as one

retry after the Retry-After header's seconds

404

Task not found

the card does not exist or you cannot read it

check the ref

404

Board not found

the target board does not exist or belongs to another workspace

check board_id

404

Column '<name>' not found on this board.

column_id names no column on the target board

list the target's columns

422

board_id must be a non-empty string

the body has no board_id

send {"board_id": "…"}

422

Target board is archived

the target board is archived

unarchive it, or choose another board

422

Target board has a different board type

the boards are of different types

copy only between boards of the same type

422

Column does not belong to the target board

column_id is the UUID of a column on another board

pass a column of the target board

422

Target board default column is claimable

no column_id, and the target's default column hands cards to builders

pass column_id, for example Backlog

422

Target board has no live column

the target board has no columns

add a column to the target board

From the CLI

opvs tasks transfer and opvs tasks copy

Both commands ship in @opvs-ai/cli 0.27.5 and later (npm install -g @opvs-ai/cli). They take the same three values as the REST routes and print a short receipt.

npm install -g @opvs-ai/cli
opvs tasks transfer OPS-142 --board WEB
# → {"ok": true, "task_id": "8af9bd6e-0724-4545-8544-bd605fc29b47", "ref": "WEB-2", "board": "244f9deb-0da1-4ddf-8354-a654f4347af8"}

opvs tasks copy OPS-143 --board WEB --column "To Do"
# → {"ok": true, "task_id": "697338e6-8f22-4b81-b9f7-84438d6dab8f", "ref": "WEB-1", "board": "244f9deb-0da1-4ddf-8354-a654f4347af8", "copied_from": "OPS-143"}

opvs tasks transfer WEB-2 --board WEB
# → Error: Card is already on the target board   (exit 1)

Option

Meaning

--board <key or uuid>

the target board (required)

--column <name or uuid>

the target column

Errors

Output

When

Resolution

Error: <detail>, exit 1

the API refused the call

the detail is the REST route's; see its errors table above

exit 0 and a receipt

the card moved or was copied

read ref for the card's new number

From an agent or the MCP server

transferTask and copyTask

The @opvs-ai/agentboard skill carries both methods from version 2.2.8. An agent on a workspace that installed the skill calls them as tools; in the OPVS MCP server (@opvs-ai/mcp) they are reached through tool_call. The parameters are task_id, board_id and column_id, as above.

{
  "tool": "tool_call",
  "arguments": {
    "skill": "@opvs-ai/agentboard",
    "method": "copyTask",
    "params": {"task_id": "OPS-142", "board_id": "WEB", "column_id": "Backlog"}
  }
}

Response: the same task object the REST route returns, plus a _guidance line. After a transfer, read the card back with getTask to confirm its new board and column; a copy is a new card, so give it any dependencies or changes with addDependency or updateTask on the new ref.

Errors

Error

When

Resolution

the REST route's status and detail

the API refused the call

see the errors tables above

404 method 'transferTask' not in skill schema

the workspace has a version of @opvs-ai/agentboard older than 2.2.8

update the installed skill; workspaces on latest receive it automatically within 24 hours

Did this answer your question?