Plank help · updated 2026-07-27

Public API & API keys

Create an API key and read or write your Plank workspace files from your own tools — scripts, integrations, or a coding assistant like Claude Code.

Agents: fetch the raw markdown of this page at /en/help/public-api.md

Public API & API keys

Your Plank files don't have to stay inside the app. With an API key you can read — and, if you choose, write — the documents in your workspaces from your own tools: a script, an integration, or a coding assistant like Claude Code running on your laptop.

The API is the same one the Plank app uses, exposed as a stable, versioned surface under /v1 so you can build against it without it shifting under you.

Create a key

Go to Settings → API keys and click Create key. You choose:

  • Name — a label so you remember where it's used ("My laptop", "Reporting script").
  • Workspaces — which workspaces the key can reach: one, several, or all of your workspaces. A key can never reach a workspace you aren't a member of.
  • AccessRead-only (list, read, search, download) or Read & write (also create, overwrite, move, delete).
  • Expiry (optional) — a date after which the key stops working.

The key is shown once, right after you create it — copy it then. Plank stores only a secure hash, so it can't show it to you again. If you lose it, revoke it and make a new one. You can revoke any key at any time from the same screen, and it stops working immediately.

A key looks like plank_pat_…. Treat it like a password: anyone holding it has the access you granted.

Use a key

Send the key as a bearer header on every request:

Authorization: Bearer plank_pat_xxxxxxxx

Always start with whoami to discover which workspaces the key can see and their ids — you pass a workspace id into every file call.

# Discover your access
curl -H "Authorization: Bearer $PLANK_API_TOKEN" \
  https://api.plank.md/v1/whoami
# → { "user_id": "...", "token": { "can_write": true },
#     "workspaces": [ { "id": "ws_123", "slug": "q1-reports", "name": "Q1 Reports" } ] }

Then read, list, search, and write files in a workspace. Paths are relative to the workspace root (e.g. reports/q1.md).

WS=ws_123
BASE=https://api.plank.md/v1/workspaces/$WS
AUTH="Authorization: Bearer $PLANK_API_TOKEN"

# List a directory
curl -H "$AUTH" "$BASE/files?path=reports"

# Read a file
curl -H "$AUTH" "$BASE/files/content?path=reports/q1.md"

# Search
curl -H "$AUTH" "$BASE/search?q=revenue"

# The whole file tree
curl -H "$AUTH" "$BASE/tree"

# Write (create or overwrite) — needs a read & write key
curl -X PUT -H "$AUTH" -H "Content-Type: application/json" \
  "$BASE/files/content?path=reports/draft.md" \
  -d '{ "content": "# Draft\n\nHello." }'

# Move / rename
curl -X POST -H "$AUTH" -H "Content-Type: application/json" \
  "$BASE/files/move" -d '{ "source": "reports/draft.md", "dest": "reports/final.md" }'

# Delete
curl -X DELETE -H "$AUTH" "$BASE/files?path=reports/final.md"

PDFs, images and other binary files

Text files go through the API as-is. Binary files — PDFs, images, Word and Excel documents — must be sent and fetched as base64, otherwise the bytes get mangled on the way through.

# Download a binary file to disk
curl -H "$AUTH" -H "Accept: application/octet-stream" \
  "$BASE/files/content?path=acts/scan.pdf" -o scan.pdf

# ...or as base64 inside the normal JSON response
curl -H "$AUTH" "$BASE/files/content?path=acts/scan.pdf&encoding=base64"

# Upload a binary file
curl -X PUT -H "$AUTH" -H "Content-Type: application/json" \
  "$BASE/files/content?path=acts/scan.pdf" \
  -d "{\"content\": \"$(base64 < scan.pdf | tr -d '\n')\", \"encoding\": \"base64\"}"

A few things worth knowing:

  • If the base64 contains invalid characters, or mixes the two base64 alphabets, the request fails with 400.
  • Validation cannot detect a payload that was cleanly truncated, so for large uploads compare the size from a follow-up read against your file.
  • Uploads are limited to about 18 MB per file (the 25 MB request limit, minus base64 overhead).
  • Downloads with Accept: application/octet-stream are limited to 100 MB; the ?encoding=base64 form is limited to 25 MB, because base64 has to be held in memory as text.
  • Leave encoding off entirely for ordinary text files; nothing changes for them.

Your workspace database

Some agent-built dashboards and CRMs in Plank store their data in real tables — the workspace database ("Lightweight Apps"). Your key can read and manage those tables too, with the same access level you gave it for files: read-only keys can list, describe, and query rows; read & write keys can also create tables and insert, update, or delete rows.

BASE=https://api.plank.md/v1/workspaces/$WS
AUTH="Authorization: Bearer $PLANK_API_TOKEN"

# List the tables in this workspace
curl -H "$AUTH" "$BASE/app-data/tables"

# Describe a table's columns
curl -H "$AUTH" "$BASE/app-data/tables/invoices"

# Query rows — filter and sort with JSON query params
curl -H "$AUTH" "$BASE/app-data/tables/invoices/rows?where={\"status\":\"open\"}&orderBy={\"column\":\"total\",\"direction\":\"desc\"}&limit=25"

# Create a table — needs a read & write key
curl -X POST -H "$AUTH" -H "Content-Type: application/json" \
  "$BASE/app-data/tables" \
  -d '{ "name": "invoices", "columns": [ { "name": "customer", "type": "text" }, { "name": "total", "type": "numeric" } ] }'

# Insert a row
curl -X POST -H "$AUTH" -H "Content-Type: application/json" \
  "$BASE/app-data/tables/invoices/rows" \
  -d '{ "customer": "Acme Co", "total": 199.50 }'

# Update a row by id
curl -X PATCH -H "$AUTH" -H "Content-Type: application/json" \
  "$BASE/app-data/tables/invoices/rows/<row-id>" \
  -d '{ "status": "paid" }'

# Delete a row by id
curl -X DELETE -H "$AUTH" "$BASE/app-data/tables/invoices/rows/<row-id>"

A quick reference:

  • List tablesGET .../app-data/tables
  • Describe a tableGET .../app-data/tables/:table (columns + types)
  • Read rowsGET .../app-data/tables/:table/rows (optionally filter with where and sort with orderBy, both JSON)
  • Create a tablePOST .../app-data/tables
  • Insert / update / delete a rowPOST / PATCH / DELETE on .../app-data/tables/:table/rows[/:id]

You can create new tables from your own tools, but changing the shape of an existing table — adding, renaming, or dropping a column, or adding a relationship between tables — is done by the agent inside Plank, not through this API.

Using it with Claude Code

Drop a snippet like this into your project's CLAUDE.md so the assistant knows how to reach your Plank files:

## Plank file access

My Plank business documents are available over the Plank public API.
- Base URL: https://api.plank.md/v1
- Auth: send header `Authorization: Bearer $PLANK_API_TOKEN` (the key is in my environment).
- First call `GET /whoami` to discover my workspace ids.
- For PDFs, images, or Office files add `&encoding=base64` when reading and send
  `{ "content": "<base64>", "encoding": "base64" }` when writing. Plain text needs neither.
- Then read files with `GET /workspaces/<id>/files/content?path=<relative/path>`,
  list with `/files?path=`, search with `/search?q=`, and (if needed) write with
  `PUT /workspaces/<id>/files/content?path=`.

Set the key in your shell so it never lands in the repo (the variable name is yours to choose — PLANK_API_TOKEN is just what these examples use):

export PLANK_API_TOKEN=plank_pat_xxxxxxxx

Limits & good practice

  • Scope tightly. Give a key only the workspaces and the access (read vs write) it actually needs. A read-only key can't change anything, which makes a leak far less costly.
  • Rotate and revoke. If a key might be exposed, revoke it and issue a new one — it's instant.
  • Rate limits. Requests are rate-limited per key; if you're batching heavy work, pace it and handle 429 responses by retrying after a moment.
  • Full reference. The complete, always-current endpoint reference (OpenAPI) is published at /v1/docs, with the raw spec at /v1/openapi.json — point codegen tools at that.