Skip to main content

API Conventions

Behaviors that hold across every Playbook API endpoint. If you are building an integration, or an AI agent, against Playbook, treat this page as ground truth.

Base URL

All REST endpoints are served under:

https://api.playbook.com/v1

Most endpoints are scoped to an organization (workspace) slug, for example /v1/{org}/assets.

Authentication

Every request authenticates with a Bearer token in the Authorization header:

Authorization: Bearer YOUR_TOKEN

Create and manage tokens yourself in the Playbook app, with no approval step. See Getting Started.

Scopes

Tokens carry scopes, enforced at the API layer:

  • read lists and fetches boards, assets, comments, and search results.
  • write creates, updates, moves, deletes, uploads, comments, shares, and publishes.

A write call made with a read-only token returns 403. Never ship a token in client-side code or paste it into a chat with an AI model. Configure it once as a request header.

Response envelope

Successful responses wrap the payload in a top-level data key:

{ "data": { "token": "abc123", "title": "Hero shot" } }

List endpoints return data as an array. Always read from data.

Status codes and errors

CodeMeaning
200Success.
401Authentication failed. Check your Bearer token.
403Permission denied. Check the token's read / write scopes.
404Not found. Check the organization slug, board token, or asset token.
406Invalid input (used by batch URL ingest validation).
422Validation error. The response body explains which field failed.
402Monthly request quota exhausted (see below).
429Rate limited. Back off and retry (see below).
5xxPlaybook API error. Retry with backoff.

Error responses include a human-readable message. Tokens are never echoed back in error bodies.

Every error body uses the same envelope, with a machine-readable code:

{
"errors": [
{
"message": "API quota exhausted: 20000/20000 requests this period",
"extensions": { "code": "api_quota_exceeded" }
}
]
}

Rate limiting

Requests are throttled per token at 120 requests per minute, the same for every plan. Exceeding it returns 429 Too Many Requests. Use the response headers instead of guessing a delay:

HeaderMeaning
Retry-AfterSeconds to wait before retrying.
RateLimit-LimitRequests allowed in the current short-term window.
RateLimit-RemainingRequests remaining; 0 on a throttled response.
RateLimit-ResetSeconds until the short-term window resets.

The JSON body also carries extensions.code: "rate_limit_exceeded" and includes the retry delay in its message. Wait at least Retry-After seconds before retrying; use exponential backoff only as additional protection for repeated 429 or 5xx responses.

Rate limiting is short-term and independent of the monthly quota below. A 429 clears within a minute; a 402 does not.

Monthly request quota

Every request to an organization-scoped endpoint (any path carrying a {slug}) counts against that organization's monthly allowance. Requests that fail validation or authorization still count — a client burning its allowance on malformed requests is generating real load.

PlanIncluded requests / monthCeiling with usage billing
Free1,000
Pro20,000200,000
Team200,0001,000,000
Business5,000,000
EnterpriseCustomCustom

See pricing for full plan details.

Quota headers

Every response from an organization-scoped endpoint carries the current state:

HeaderMeaning
X-API-Quota-LimitRequests included in the plan this period.
X-API-Quota-RemainingRequests left in the included allowance. Reaches 0 and stays there once usage crosses into the billed band.
X-API-Quota-ResetWhen the counter rolls over (ISO 8601).

Read X-API-Quota-Remaining and slow down before you hit zero rather than reacting to the 402.

When the quota runs out

Requests return 402 with the code api_quota_exceeded and a Retry-After header holding the seconds until the counter resets.

402 rather than 429 is deliberate: an exhausted monthly quota stays exhausted for days, so a client that treats it as a 429 and retries with backoff would hammer the API for the rest of the period without ever succeeding. Do not retry a 402 — either wait for X-API-Quota-Reset or raise the ceiling.

Usage billing

On Pro and Team, a workspace admin can lift the wall from the included allowance to the ceiling by enabling usage billing on the Developers tab in the Playbook app. It requires a payment method on file. Requests beyond the included allowance are then billed per request on the next invoice, alongside seats and storage — there is no separate invoice.

Until it is enabled, the included allowance is the wall. Nothing is ever billed without that explicit opt-in.

When the counter resets

The window follows the workspace's monthly billing date, so it is monthly even on an annual plan. Workspaces without a paid subscription reset on the first of the calendar month. X-API-Quota-Reset always carries the authoritative timestamp — do not assume the 1st.

Pagination

List endpoints accept page and per_page query parameters:

GET /v1/{org}/assets?page=2&per_page=50

GET /v1/{org}/assets also supports stable keyset pagination for a complete workspace crawl:

GET /v1/{org}/assets?cursor=true&per_page=100
GET /v1/{org}/assets?cursor=true&per_page=100&after_cursor=OPAQUE_VALUE

Read pagy.has_next_page to decide whether to continue, and pass pagy.after_cursor back unchanged. Cursor mode uses the default descending created_at order and cannot be combined with page or ascending sort. It is a full crawl and reconcile mechanism, not a change feed: it does not report deletions or only the records changed since the last crawl.

Async ingest

Uploads are asynchronous. Creating an asset (from a URL, a batch of URLs, or a signed upload) returns immediately with a skeleton asset. The row exists, but the bytes are still being fetched and processed.

Poll GET /v1/{org}/assets/{token} until is_skeleton is false, then check:

  • media_type populated means the asset processed successfully.
  • source_error non-null means ingest failed (the message is the latest worker error).
  • is_link: true means it was kept as a bare link (only when as_link: true was passed).

For batch URL ingest, pass a uuid per item to correlate each async result back to your request. See the Upload guide, Async Ingest Semantics for the full contract and recommended polling cadence.

Driving Playbook from an AI agent

Everything above is also available to AI assistants through the hosted MCP server, which exposes the same operations as tools, with the same scopes and the same async semantics, and can read these docs at runtime via read_documentation. See the MCP guide.