Skip to main content

Flipbooker for developers

Put flipbooks in your own workflow

A REST API for turning PDFs into tracked flipbooks: upload documents, read per-reader analytics, export leads and receive webhooks — without anyone opening the dashboard.

57 endpoints · OpenAPI 3.1 · API keys and OAuth

Your first request
curl https://app.flipbooker.com/api/v1/books \
  -H "Authorization: Bearer $FLIPBOOKER_API_KEY"

Quickstart

Three steps from zero to a converted flipbook.

  1. 1

    Create an API key

    Sign in to Flipbooker, open Account → API Keys and create a key. Pick only the scopes your integration needs.

    The key is displayed once. Copy it into your secret store — it cannot be retrieved later, only rotated.

    Store it as an environment variable
    export FLIPBOOKER_API_KEY="wsk_live_..."
  2. 2

    List your flipbooks

    Confirm the key works by listing the workspace's flipbooks. A 200 with a data array means you are connected.

    A 401 means the key is wrong or revoked; a 403 means it is missing the books:read scope.

    GET /books
    curl https://app.flipbooker.com/api/v1/books \
      -H "Authorization: Bearer $FLIPBOOKER_API_KEY"
  3. 3

    Upload a PDF

    Post the document as multipart/form-data under the files[] field — one file per request. PDF, Word, Excel, PowerPoint, JPG and PNG are accepted.

    Conversion runs in the background, so the response is 202 Accepted with a batch id rather than a finished flipbook. Poll GET /batches/{batchId} until it reports done, then read the created book.

    POST /books
    curl -X POST https://app.flipbooker.com/api/v1/books \
      -H "Authorization: Bearer $FLIPBOOKER_API_KEY" \
      -F "files[][email protected]"

Authentication

Every request needs a workspace API key, sent as a bearer token. Keys are created in the app under Account → API Keys and are shown once at creation — Flipbooker only stores a hash, so store yours in a secret manager before closing the dialog.

Live keys are prefixed wsk_live_ and test keys wsk_test_. A key belongs to one workspace and every request is scoped to it — there is no workspace parameter to pass.

The API also accepts an OAuth 2 bearer token, which is how the Canva and Adobe integrations connect. Both auth methods honour the same scopes.

Keep keys server-side
An API key carries the full access of its scopes. Never ship one in browser or mobile code. Passing it as an ?api_key= query parameter also works, but leaks the key into server and proxy logs — prefer the Authorization header.
Authenticated request
export FLIPBOOKER_API_KEY="wsk_live_..."

curl https://app.flipbooker.com/api/v1/books \
  -H "Authorization: Bearer $FLIPBOOKER_API_KEY"

Scopes

Grant a key only what it needs. A key with * gets everything.

  • analytics:read
  • books:read
  • books:write
  • brand:read
  • brand:write
  • catalogs:read
  • catalogs:write
  • exports:read
  • subscribers:read
  • subscribers:write
  • tracked-links:read
  • tracked-links:write
  • webhooks:read
  • webhooks:write

Calling an endpoint without its scope returns 403, and the response lists the scopes your key actually has.

How the API behaves

The conventions below hold across every endpoint.

Response envelope

Successful responses wrap the payload in data. Endpoints that paginate or add context also return a meta object.

Errors replace both with a single error object carrying a human-readable message, a stable type, and — for validation failures — field-level details. Branch on the HTTP status and type, not the message text.

Success and error
// 200 OK
{
  "data": [ { "id": 42, "name": "Quarterly report" } ],
  "meta": { "next_cursor": "eyJpZCI6NDJ9", "has_more": true }
}

// 422 Unprocessable Entity
{
  "error": {
    "message": "The given data was invalid.",
    "type": "ValidationException",
    "details": { "file": ["The file field is required."] }
  }
}

Rate limits

Authenticated traffic is limited to 1,000 requests per minute per workspace, with a second limit of 100 requests per minute per endpoint so one hot path cannot starve the rest of your integration.

Unauthenticated requests are limited to 10 per minute per IP. Exceeding a limit returns 429 with a Retry-After header — back off for that many seconds rather than retrying immediately.

Handling 429
async function call(url, init, attempt = 0) {
  const res = await fetch(url, init)
  if (res.status !== 429 || attempt >= 5) return res

  const wait = Number(res.headers.get('Retry-After') ?? 1)
  await new Promise(r => setTimeout(r, wait * 1000))
  return call(url, init, attempt + 1)
}

Idempotency

Send an Idempotency-Key header on writes so a retry after a timeout cannot create a duplicate. Use a fresh UUID per logical operation.

The first successful (2xx) response for a key is cached for 24 hours. Replays return that stored response together with X-Idempotent-Replay: true, so you can tell a replay from fresh work. Failed responses are not cached — those retries execute normally.

Safe retries
curl -X POST https://app.flipbooker.com/api/v1/books \
  -H "Authorization: Bearer $FLIPBOOKER_API_KEY" \
  -H "Idempotency-Key: 5b8f0a7e-2a1e-4f6a-9c3d-7e2b1f4a8c60" \
  -F "files[][email protected]"

Browse every endpoint

Parameters, scopes, response shapes and example requests for all 57 endpoints — plus the OpenAPI 3.1 document.