Read cards
Read cards with an API key that has the read permission. You can list cards from a board or a single list, narrow them by label, or fetch one card by ID. Cards you cannot access return 404 without revealing their contents.
List cards
GET /api/v1/cards
Pass a boardId or a listId, then optionally narrow the result to one label, such as Bug. Find board and list IDs with Get one board.
| Field | Type | Required | Description |
|---|---|---|---|
boardId | string | One of boardId or listId | Read cards across all lists on this board. |
listId | string | One of boardId or listId | Read cards in this list (column or category). If you also pass boardId, the list must be on that board. |
labelId | string | No | Only cards with this label. The label must belong to the board's project. |
limit | integer | No | Page size, from 1 to 100. Defaults to 50. |
cursor | string | No | The nextCursor from the previous response. Omit it for the first page. |
curl -G "https://projavo.com/api/v1/cards" \
-H "Authorization: Bearer $PROJAVO_API_KEY" \
--data-urlencode "boardId=<board-id>" \
--data-urlencode "listId=<list-id>" \
--data-urlencode "labelId=<label-id>" \
--data-urlencode "limit=50"
const url = new URL("https://projavo.com/api/v1/cards");
url.searchParams.set("listId", "<list-id>");
url.searchParams.set("labelId", "<label-id>");
const res = await fetch(url, {
headers: { Authorization: `Bearer ${process.env.PROJAVO_API_KEY}` },
});
const { cards, nextCursor } = await res.json();
Response
Response 200:
{
"cards": [
{
"id": "card_example",
"title": "Vehicle spawns underground near Legion",
"description": "When spawning the Adder near the fountain, it clips through the map.\n\nRepro: /car adder near the fountain.",
"priority": "HIGH",
"position": 0,
"dueDate": null,
"listId": "list_example",
"boardId": "board_example",
"createdAt": "2026-10-01T12:00:00.000Z",
"updatedAt": "2026-10-01T12:00:00.000Z",
"list": { "id": "list_example", "name": "Backlog / Ideas", "boardId": "board_example" },
"labels": [{ "id": "label_example", "name": "Bug", "color": "#EF4444" }],
"assignees": []
}
],
"nextCursor": null
}
Titles and Markdown descriptions are returned in full. An empty result is { "cards": [], "nextCursor": null }.
To read every matching card, repeat the same filters with cursor set to the previous nextCursor. Stop when nextCursor is null.
Pages are ordered by card ID, not by column position. Moving or deleting the last card on a page does not break its cursor. Results reflect the current state, so a card created or relabeled during a scan may need a new scan. To show cards in board order, sort each listId group by position after you collect all pages.
Get one card
GET /api/v1/cards/:cardId
Read a card again before you work on it or confirm a move.
curl "https://projavo.com/api/v1/cards/<card-id>" \
-H "Authorization: Bearer $PROJAVO_API_KEY"
Response 200 is { "card": { ... } }, with the same card fields as the list response.
Errors
Both read endpoints return these errors. See Errors for the full reference.
| Status | Code | Meaning |
|---|---|---|
401 | missing_key, invalid_key, unauthorized | The key is missing, invalid, or revoked, or the owner is no longer active. |
403 | insufficient_scope | The key does not have the read permission. |
404 | not_found | The board, list, or card does not exist or is not accessible. |
422 | validation_error | The query is invalid, for example a missing boardId and listId, or a limit outside 1 to 100. |
422 | invalid_label | The labelId does not belong to the board's project. |
429 | RATE_LIMITED | More than 60 requests per minute from this key. Wait and retry. |
Both endpoints send Cache-Control: private, no-store, so clients always get current card data.
To place a resolved issue in a completion column, see Move a card.