Boards and visibility
A board is the top-level Kanban resource: it belongs to exactly one workspace, owns its columns and cards, and defines who can see and change everything inside it.
The board representation is documented in the
API reference. The fields that drive access are
is_public, created_by, and version; archived_at is set when a board
is archived.
Public and private boards
Board access follows the same rules as the FileTag web app:
- Public boards (
is_public: true, the default at creation) are visible and writable to every active member of the workspace. - Private boards (
is_public: false) are visible only to the board creator and users with an explicit board membership.
Visibility is changed with
PUT /boards/{board_id}/visibility,
which requires the kanban:admin scope, the board-creator permission, and an
If-Match header. Explicit members are managed with the
board member endpoints (also
creator-only for writes); the
workspace member directory gives
you the valid user_id values to add. The creator cannot be removed through
the membership endpoint.
Inaccessible means 404, not 403
A board you cannot access — because it is private, belongs to another
workspace, or simply does not exist — always returns 404 not_found. The
API never answers 403 for a resource-access failure, so an integration can
never probe whether a given board ID exists. Treat 404 as "not available
to this token" and nothing more. (403 is reserved for scope and
management-permission failures — see
Authentication.)
Listing and reading boards
GET /boards returns the boards visible to
the represented user, cursor-paginated, active boards by default. Pass
archived=true to list archived boards instead. Board detail is
GET /boards/{board_id}.
cURL:
curl -sS "$KANBAN_API_BASE_URL/boards?archived=false&limit=50" \
-H "Authorization: Bearer $KANBAN_API_TOKEN"
JavaScript:
const baseUrl =
process.env.KANBAN_API_BASE_URL ?? "https://app.filetag.ai/api/kanban/v1";
const token = process.env.KANBAN_API_TOKEN;
async function main() {
const response = await fetch(`${baseUrl}/boards?archived=false&limit=50`, {
headers: { Authorization: `Bearer ${token}` },
});
const payload = await response.json();
if (!response.ok) {
throw new Error(
`${payload.error.code}: ${payload.error.message} (request ${payload.error.request_id})`
);
}
for (const board of payload.data) {
console.log(board.id, board.name, board.is_public ? "public" : "private");
}
}
main().catch((error) => {
console.error(error);
process.exit(1);
});
Python:
import json
import os
import urllib.request
BASE_URL = os.environ.get(
"KANBAN_API_BASE_URL", "https://app.filetag.ai/api/kanban/v1"
)
TOKEN = os.environ["KANBAN_API_TOKEN"]
request = urllib.request.Request(
f"{BASE_URL}/boards?archived=false&limit=50",
headers={"Authorization": f"Bearer {TOKEN}"},
)
with urllib.request.urlopen(request) as response:
payload = json.load(response)
for board in payload["data"]:
kind = "public" if board["is_public"] else "private"
print(board["id"], board["name"], kind)
Creating and changing boards
POST /boardscreates the board and its default To Do, Doing, and Done columns in a single transaction. It requireskanban:writeand anIdempotency-Key.PATCH /boards/{board_id}updatesname,description, orcover_color(at least one field), guarded byIf-Match.DELETE /boards/{board_id}permanently deletes the board and everything in it. It requireskanban:admin, is version-guarded withIf-Match, and cannot be undone.
The board version moves with its content
The board's version (returned in the ETag header on reads) covers more
than the board's own metadata: activity on the board's descendants also bumps
it. A PATCH to board metadata can therefore fail with
412 precondition_failed right after unrelated card activity — re-read the
board, take the fresh ETag, and retry. See
Optimistic concurrency.