Documentation
Public API
Cards API

Cards API

REST API reference for cards and every sub-resource (members, labels, checklist, comments, attachments, content links and statuses). For the product overview and UI walkthrough, see Cards.

Cards and every sub-resource are available via the Flokan public API. You can build custom intake forms, sync external tools, or automate moves and status updates from your own scripts.

Authentication

All requests require a workspace API key minted in Workspace Settings → API Keys. Pass the key in the Authorization header:

Authorization: Bearer flk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

The key must include the boards scope, and the workspace's plan must include the Boards & Sheets feature.

Base URL

https://app.flokan.com/api/v1

Resolving cards by short ID

Every endpoint that accepts a :cardId in the path also accepts the card's short ID (e.g. MKT-42) in place of the UUID. The same URL works for both human-readable links and machine-generated UUIDs.

Listing and creating cards

Cards live under a board, so list and create go through the board path:

GET /boards/:boardId/cards — List cards on a board

Query params

ParamTypeNotes
pageintegerDefault 1
per_pageintegerDefault 50, max 100
list_iduuidFilter to one list
archivedbooleanDefault false. Pass true to fetch archived cards.
searchstringCase-insensitive title match
due_beforeISO dateCards due on or before this date
due_afterISO dateCards due on or after this date
created_byuuidFilter by author
assigned_touuidFilter to cards assigned to one user
label_iduuidFilter to cards with one label

POST /boards/:boardId/cards — Create a card

Request body

FieldTypeRequiredNotes
titlestringyes1–500 characters
list_iduuidyesMust belong to the board
descriptionstringnoUp to 50000 characters
due_dateISO timestampno
started_atISO timestampno
estimated_hoursintegerno0–99999
actual_hoursintegerno0–99999
member_idsuuid[]noAssign these users on creation
label_idsuuid[]noApply these board labels on creation
checklistobject[]no[{ "text": "...", "completed": false }] — created in the given order

Returns the new card row (sub-resources are created but not echoed in the response — fetch the card detail to see them).

Single card

GET /cards/:cardId — Card detail

Returns the card plus enriched sub-resources in one payload:

{
  "success": true,
  "data": {
    "id": "...",
    "short_id": "MKT-42",
    "title": "Q2 launch trailer",
    "description": "...",
    "list_id": "...",
    "board_id": "...",
    "position": 3,
    "due_date": "2026-06-01T00:00:00.000Z",
    "archived": false,
    "completed_at": null,
    "completed_by": null,
    "started_at": null,
    "estimated_hours": 12,
    "actual_hours": null,
    "member_ids": ["..."],
    "label_ids": ["..."],
    "checklist": [
      { "id": "...", "text": "Storyboard", "completed": true, "position": 0 }
    ],
    "attachments": [],
    "content_links": [],
    "content_statuses": { "script": "approved" },
    "comment_count": 4,
    "created_at": "...",
    "updated_at": "..."
  }
}

PUT /cards/:cardId — Update a card

All fields optional. Allowed: title, description, list_id, due_date, started_at, estimated_hours, actual_hours, position, archived, completed.

  • Setting archived: true stamps archived_at and archived_by. Setting it to false clears both.
  • Setting completed: true stamps completed_at and completed_by. Setting it to false clears both.
  • Pass null for description, estimated_hours, or actual_hours to clear them.

DELETE /cards/:cardId — Delete a card

Hard-deletes the card and all its sub-resources.

POST /cards/:cardId/move — Move a card

Request body

FieldTypeRequiredNotes
list_iduuidyesTarget list. Cross-board moves are allowed when the target list belongs to a board in the same workspace.
positionintegernoOmit to drop the card at the bottom of the target list.

Members

GET /cards/:cardId/members

Returns each assigned user with their username and avatar_url.

POST /cards/:cardId/members

Body: { "user_id": "uuid" }. Returns 409 if already assigned.

DELETE /cards/:cardId/members/:userId

Labels

GET /cards/:cardId/labels

Returns each label as { id, name, color }.

POST /cards/:cardId/labels

Body: { "label_id": "uuid" }. The label must belong to the card's board. Returns 409 if already assigned.

DELETE /cards/:cardId/labels/:labelId

Checklist

GET /cards/:cardId/checklist

Returns items ordered by position.

POST /cards/:cardId/checklist

Body: { "text": "...", "completed": false }. Appended to the bottom.

PUT /cards/:cardId/checklist/:itemId

Allowed fields: text, completed, position.

DELETE /cards/:cardId/checklist/:itemId

Comments

Threaded one level deep — replies attach to root comments only.

GET /cards/:cardId/comments

Each comment is enriched with an author object (username, avatar_url).

POST /cards/:cardId/comments

Request body

FieldTypeRequiredNotes
contentstringyes1–2000 characters
parent_iduuidnoMust be a root comment on the same card

PUT /cards/:cardId/comments/:commentId

Body: { "content": "..." }. Only the user who created the API key can edit comments authored by the same user — returns 403 otherwise.

DELETE /cards/:cardId/comments/:commentId

Attachments

GET /cards/:cardId/attachments

POST /cards/:cardId/attachments

Request body

FieldTypeRequiredNotes
namestringyes1–500 characters
urlstringyes1–2000 characters
typestringnourl (default) or file

DELETE /cards/:cardId/attachments/:attachmentId

Content links and status

Content links group thumbnails, scripts, voiceovers, and other production artifacts on the card. Each content_type (e.g. script, thumbnail, video) carries its own review status.

GET /cards/:cardId/content

Returns links flat, grouped by type, and the status map:

{
  "success": true,
  "data": {
    "links": [
      { "id": "...", "content_type": "script", "link_url": "...", "name": "Draft v2", "created_by": "...", "created_at": "..." }
    ],
    "links_by_type": { "script": [ { "id": "...", "content_type": "script", "...": "..." } ] },
    "statuses": { "script": "approved" }
  }
}

POST /cards/:cardId/content

Request body

FieldTypeRequiredNotes
content_typestringyes1–100 characters (e.g. script, thumbnail, voiceover)
link_urlstringyes1–2000 characters
namestringno1–500 characters

Adding the first link of a given content_type automatically sets the status to needs_review.

DELETE /cards/:cardId/content?link_id=:linkId

Pass the link UUID via the link_id query parameter. If you remove the last link of a given content_type, its status row is also cleared.

PUT /cards/:cardId/content/status

Request body

FieldTypeRequiredNotes
content_typestringyesThe content type whose status you're setting
statusstringyesnone, needs_review, approved, or needs_revisions. Setting none clears the row.

Errors

All error responses use the envelope { "success": false, "error": "..." }. Common status codes:

CodeMeaning
400Validation error (bad UUID, missing required field, status not in the allowed set, …)
401Missing or invalid API key
403Missing boards scope, feature not enabled on the workspace plan, or editing another user's comment
404Card, list, label, member, attachment, or comment not found in this workspace
409Member or label already assigned to the card
429Rate limit exceeded — see Retry-After header and X-RateLimit-* headers
500Unexpected server error

Rate limits

Every response carries X-RateLimit-Limit, X-RateLimit-Remaining, and X-RateLimit-Reset headers. The per-minute limit is determined by the workspace's billing plan.