Slate Create a token

API

Authentication

Create a personal token under Settings, API tokens. Send it on every request. Tokens are read-only or read and write, are shown once, and can be revoked at any time. Limit: 120 requests a minute per token.

curl -H "Authorization: Bearer slt_YOUR_TOKEN" https://YOUR-DOMAIN/api/boards

Tokens cannot call /api/auth, /api/tokens or /api/admin. Writes need no CSRF header when a bearer token is used. Errors are JSON: {"error": "..."}.

Main endpoints

Method and pathPurpose
GET /api/boardsList boards (?scope=archived or templates)
POST /api/boardsCreate a board {title}
GET /api/boards/:idBoard with lists, cards and labels
POST /api/boards/:id/listsAdd a list {title}
POST /api/cardsCreate a card {list_id, title, description_md, due_at, start_at}
GET /api/cards/:idCard with checklists, comments, attachments
PATCH /api/cards/:idChange title, description_md, due_at, start_at
POST /api/cards/:id/moveMove {list_id, before_id, after_id}
POST /api/cards/:id/commentsComment {body_md}
GET /api/calendar/eventsCalendar events
GET /api/data/export.jsonFull export (also export.csv, export.ics, /api/data/boards/:id/export.json)
POST /api/data/import/trelloBody: the Trello JSON, up to 5 MB (also planka, slate)
POST /api/data/import/autoDetects Trello, Planka or Slate JSON and imports it
POST /api/calendar/moveShift cards or events by whole days {items:[{kind, id, delta_days}]}
POST /api/calendar/board-dueSet or clear a board's due date {board_id, date|null}
POST /api/boards/bulkRestore or delete archived boards {ids, action}
POST /api/bulk/restoreRestore archived cards {card_ids}
POST /api/bulk/deletePermanently delete archived cards {card_ids}
GET /api/embed-thumb/:provider?id=Cached video thumbnail (youtube, vimeo, framerate)

Webhooks

Add a URL under Settings, Webhooks. It must be https on a public hostname. Slate sends a POST with a 5 second timeout and retries once. The last 20 deliveries are visible in Settings. Events: card.created, card.moved, card.delivered, card.due_changed.

{
  "id": "delivery id",
  "event": "card.moved",
  "created_at": "2026-10-25T09:00:00.000Z",
  "data": {
    "card": { "id": "...", "title": "...", "board_id": "...", "list_id": "...", "due_at": null },
    "from_list": "To do", "to_list": "Doing",
    "actor": { "id": "...", "name": "..." }
  }
}

Headers: X-Slate-Event, X-Slate-Delivery, X-Slate-Timestamp (Unix seconds) and X-Slate-Signature, which is sha256= followed by the hex HMAC-SHA256 of timestamp, a full stop, then the raw body, keyed with your webhook secret. Reject deliveries whose timestamp is more than five minutes old.

// Node.js
import { createHmac, timingSafeEqual } from "node:crypto";
function verify(secret, headers, rawBody) {
  const ts = headers["x-slate-timestamp"];
  if (Math.abs(Date.now() / 1000 - Number(ts)) > 300) return false;
  const want = "sha256=" + createHmac("sha256", secret).update(ts + "." + rawBody).digest("hex");
  const got = headers["x-slate-signature"] || "";
  return got.length === want.length && timingSafeEqual(Buffer.from(got), Buffer.from(want));
}