<!-- Source: https://useworkloom.com/dev/creative/ · Workloom API v1 -->

# Documents, videos and designs

Documents, videos and designs, made the way the app makes them. Start a document from a team template with its gaps filled, export it as an accessible PDF, apply the video editor’s operations, or start a design. Each runs the app’s own checks, and a problem comes back in words.

Scopes: `creative:read`, `creative:write`.

## Endpoints

### List documents

`GET /documents`

Your workspace’s documents. `templates=true` lists only team templates, the ones `POST /documents` can start from.

Scope: `creative:read`

**Query parameters**

- `templates` (boolean): Only team templates.
- `q` (string): Titles containing this.

**Request**

```bash
curl "https://api.useworkloom.com/api/public/v1/documents" \
  -H "Authorization: Bearer $WORKLOOM_KEY"
```

```javascript
const res = await fetch("https://api.useworkloom.com/api/public/v1/documents", {
  method: "GET",
  headers: {
    Authorization: `Bearer ${process.env.WORKLOOM_KEY}`
  }
});
const data = await res.json();
```

```python
import os, requests

res = requests.get(
    "https://api.useworkloom.com/api/public/v1/documents",
    headers={"Authorization": f"Bearer {os.environ['WORKLOOM_KEY']}"},
)
data = res.json()
```

**Response (sample, 200)**

```json
{
  "object": "list",
  "data": [
    {
      "id": "6700a1b2e4b0a1b2c3d4d001",
      "title": "Proposal for [COMPANY]",
      "kind": "proposal",
      "template": true,
      "gaps": 3,
      "updated_at": "2026-10-08T15:20:00.000Z"
    }
  ]
}
```

**Errors**

- 400: `invalid_request`, `unknown_fields`, `reason_required` or `unsupported_version`.
- 401: `authentication_required` or `invalid_key`.
- 403: `missing_scope`, `forbidden`, `seat_inactive` or `organisation_inactive`.
- 429: `rate_limited`. Wait `Retry-After` seconds.
- 500: `internal_error`.

### Make a document

`POST /documents`

From a team template with its gaps filled by `fields`, or a new one of a kind. It shows in Documents as “Made with the API · key …”.

Scope: `creative:write`

**Header parameters**

- `Idempotency-Key` (string): Any unique string, up to 255 characters. Send the same key when you retry and the request runs once; the first answer comes back with `Idempotent-Replayed: true`. Kept 24 hours.

**Body parameters**

- `template_id` (string, nullable): A team template (a document marked as a template in Workloom).
- `kind` (string): The kind, when there is no template.
- `title` (string, nullable): Its title.
- `fields` (object): Values for its gaps, by name.

**Request**

```bash
curl -X POST "https://api.useworkloom.com/api/public/v1/documents" \
  -H "Authorization: Bearer $WORKLOOM_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{
  "template_id": "6700a1b2e4b0a1b2c3d4d001",
  "fields": {
    "COMPANY": "Brightline",
    "FIRST NAME": "Priya"
  }
}'
```

```javascript
const res = await fetch("https://api.useworkloom.com/api/public/v1/documents", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${process.env.WORKLOOM_KEY}`,
    "Content-Type": "application/json",
    "Idempotency-Key": crypto.randomUUID()
  },
  body: JSON.stringify({
    "template_id": "6700a1b2e4b0a1b2c3d4d001",
    "fields": {
      "COMPANY": "Brightline",
      "FIRST NAME": "Priya"
    }
  })
});
const data = await res.json();
```

```python
import os, uuid, requests

res = requests.post(
    "https://api.useworkloom.com/api/public/v1/documents",
    headers={"Authorization": f"Bearer {os.environ['WORKLOOM_KEY']}", "Idempotency-Key": str(uuid.uuid4())},
    json={
      "template_id": "6700a1b2e4b0a1b2c3d4d001",
      "fields": {
        "COMPANY": "Brightline",
        "FIRST NAME": "Priya"
      }
    },
)
data = res.json()
```

**Response (sample, 201)**

```json
{
  "data": {
    "id": "6700a1b2e4b0a1b2c3d4d0a7",
    "title": "Proposal for Brightline",
    "kind": "proposal",
    "gaps_left": [
      "DATE"
    ]
  },
  "livemode": true
}
```

**Errors**

- 400: `invalid_request`, `unknown_fields`, `reason_required` or `unsupported_version`.
- 401: `authentication_required` or `invalid_key`.
- 403: `missing_scope`, `forbidden`, `seat_inactive` or `organisation_inactive`.
- 409: `duplicate`, `conflict` or `idempotency_key_in_use`.
- 422: `idempotency_key_reused`.
- 429: `rate_limited`. Wait `Retry-After` seconds.
- 500: `internal_error`.

### Export a document as PDF

`POST /documents/{id}/export`

Makes the PDF (accessible by default) and keeps it with the workspace’s PDFs. Returns a link to download it, valid for a few hours.

Scope: `creative:write`

**Path parameters**

- `id` (string, required): The document’s id.

**Body parameters**

- `mode` (string): Accessible (tagged) by default; plain where the document engine is not installed.

**Request**

```bash
curl -X POST "https://api.useworkloom.com/api/public/v1/documents/6700a1b2e4b0a1b2c3d4d001/export" \
  -H "Authorization: Bearer $WORKLOOM_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "mode": "accessible"
}'
```

```javascript
const res = await fetch("https://api.useworkloom.com/api/public/v1/documents/6700a1b2e4b0a1b2c3d4d001/export", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${process.env.WORKLOOM_KEY}`,
    "Content-Type": "application/json"
  },
  body: JSON.stringify({
    "mode": "accessible"
  })
});
const data = await res.json();
```

```python
import os, requests

res = requests.post(
    "https://api.useworkloom.com/api/public/v1/documents/6700a1b2e4b0a1b2c3d4d001/export",
    headers={"Authorization": f"Bearer {os.environ['WORKLOOM_KEY']}"},
    json={
      "mode": "accessible"
    },
)
data = res.json()
```

**Response (sample, 200)**

```json
{
  "data": {
    "mode": "accessible",
    "pages": 4,
    "bytes": 182344,
    "url": "https://files.useworkloom.com/pdfs/6700a1b2e4b0a1b2c3d4d0a7.pdf?sig=…",
    "warnings": [],
    "gaps_left": []
  },
  "livemode": true
}
```

**Errors**

- 400: `invalid_request`, `unknown_fields`, `reason_required` or `unsupported_version`.
- 401: `authentication_required` or `invalid_key`.
- 403: `missing_scope`, `forbidden`, `seat_inactive` or `organisation_inactive`.
- 404: `not_found`.
- 409: `duplicate`, `conflict` or `idempotency_key_in_use`.
- 429: `rate_limited`. Wait `Retry-After` seconds.
- 500: `internal_error`.

### Edit a video

`POST /videos/{id}/edit`

Applies the editor’s operations, checked as the editor checks them, and saves a new version, which Workloom renders. A problem comes back as a problem in words; nothing half-applied is saved.

Scope: `creative:write`

**Path parameters**

- `id` (string, required): The video’s id.

**Header parameters**

- `Idempotency-Key` (string): Any unique string, up to 255 characters. Send the same key when you retry and the request runs once; the first answer comes back with `Idempotent-Replayed: true`. Kept 24 hours.

**Body parameters**

- `ops` (array of object, required): Operations, for example `{ "op": "cut", "from": 12.5, "to": 18 }` or `{ "op": "add_text", "at": 0, "end": 3, "kind": "title", "text": "Your rollout plan" }`.
- `base_revision` (integer, nullable, required): The version you are changing.

**Request**

```bash
curl -X POST "https://api.useworkloom.com/api/public/v1/videos/6700b2c3e4b0a1b2c3d4b001/edit" \
  -H "Authorization: Bearer $WORKLOOM_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{
  "ops": [
    {
      "op": "cut",
      "from": 12.5,
      "to": 18
    },
    {
      "op": "add_text",
      "at": 2,
      "end": 6,
      "kind": "title",
      "text": "Rollout plan for Brightline"
    }
  ],
  "base_revision": 3
}'
```

```javascript
const res = await fetch("https://api.useworkloom.com/api/public/v1/videos/6700b2c3e4b0a1b2c3d4b001/edit", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${process.env.WORKLOOM_KEY}`,
    "Content-Type": "application/json",
    "Idempotency-Key": crypto.randomUUID()
  },
  body: JSON.stringify({
    "ops": [
      {
        "op": "cut",
        "from": 12.5,
        "to": 18
      },
      {
        "op": "add_text",
        "at": 2,
        "end": 6,
        "kind": "title",
        "text": "Rollout plan for Brightline"
      }
    ],
    "base_revision": 3
  })
});
const data = await res.json();
```

```python
import os, uuid, requests

res = requests.post(
    "https://api.useworkloom.com/api/public/v1/videos/6700b2c3e4b0a1b2c3d4b001/edit",
    headers={"Authorization": f"Bearer {os.environ['WORKLOOM_KEY']}", "Idempotency-Key": str(uuid.uuid4())},
    json={
      "ops": [
        {
          "op": "cut",
          "from": 12.5,
          "to": 18
        },
        {
          "op": "add_text",
          "at": 2,
          "end": 6,
          "kind": "title",
          "text": "Rollout plan for Brightline"
        }
      ],
      "base_revision": 3
    },
)
data = res.json()
```

**Response (sample, 200)**

```json
{
  "data": {
    "id": "6700b2c3e4b0a1b2c3d4b001",
    "revision": 4,
    "changes": [
      "Cut 0:12 to 0:18 · 6 s shorter",
      "Added “Rollout plan for Brightline”"
    ],
    "status": "rendering"
  },
  "livemode": true
}
```

**Errors**

- 400: `invalid_request`, `unknown_fields`, `reason_required` or `unsupported_version`.
- 401: `authentication_required` or `invalid_key`.
- 403: `missing_scope`, `forbidden`, `seat_inactive` or `organisation_inactive`.
- 404: `not_found`.
- 409: `duplicate`, `conflict` or `idempotency_key_in_use`.
- 422: `idempotency_key_reused`.
- 429: `rate_limited`. Wait `Retry-After` seconds.
- 500: `internal_error`.

### Make a design

`POST /designs`

A blank design of a format or size, with a link to open it in Workloom’s image editor.

Scope: `creative:write`

**Header parameters**

- `Idempotency-Key` (string): Any unique string, up to 255 characters. Send the same key when you retry and the request runs once; the first answer comes back with `Idempotent-Replayed: true`. Kept 24 hours.

**Body parameters**

- `format` (string, nullable): A format id, for example `beam_thumbnail` or `linkedin_post`.
- `width` (integer, nullable): Width in pixels, 16 to 4096.
- `height` (integer, nullable): Height in pixels, 16 to 4096.
- `name` (string, nullable): Its name.

**Request**

```bash
curl -X POST "https://api.useworkloom.com/api/public/v1/designs" \
  -H "Authorization: Bearer $WORKLOOM_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{
  "format": "linkedin_post",
  "name": "Brightline case study"
}'
```

```javascript
const res = await fetch("https://api.useworkloom.com/api/public/v1/designs", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${process.env.WORKLOOM_KEY}`,
    "Content-Type": "application/json",
    "Idempotency-Key": crypto.randomUUID()
  },
  body: JSON.stringify({
    "format": "linkedin_post",
    "name": "Brightline case study"
  })
});
const data = await res.json();
```

```python
import os, uuid, requests

res = requests.post(
    "https://api.useworkloom.com/api/public/v1/designs",
    headers={"Authorization": f"Bearer {os.environ['WORKLOOM_KEY']}", "Idempotency-Key": str(uuid.uuid4())},
    json={
      "format": "linkedin_post",
      "name": "Brightline case study"
    },
)
data = res.json()
```

**Response (sample, 201)**

```json
{
  "data": {
    "id": "6700c3d4e4b0a1b2c3d4c001",
    "name": "Brightline case study",
    "width": 1200,
    "height": 1200,
    "open_url": "https://app.useworkloom.com/designs/6700c3d4e4b0a1b2c3d4c001"
  },
  "livemode": true
}
```

**Errors**

- 400: `invalid_request`, `unknown_fields`, `reason_required` or `unsupported_version`.
- 401: `authentication_required` or `invalid_key`.
- 403: `missing_scope`, `forbidden`, `seat_inactive` or `organisation_inactive`.
- 409: `duplicate`, `conflict` or `idempotency_key_in_use`.
- 422: `idempotency_key_reused`.
- 429: `rate_limited`. Wait `Retry-After` seconds.
- 500: `internal_error`.

## From an AI assistant (MCP)

The same four actions are an MCP server at `https://api.useworkloom.com/api/public/v1/mcp` (JSON-RPC over HTTP), with the same keys: `creative:read` to connect, `creative:write` for a tool that makes or changes something. Its tools are `workloom.document.create`, `workloom.document.export`, `workloom.video.edit` and `workloom.design.create`; `tools/list` describes their inputs. A problem comes back as the tool’s result with `isError: true` and the reason in words.

**tools/call**

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "workloom.document.create",
    "arguments": {
      "template_id": "6700a1b2e4b0a1b2c3d4d001",
      "fields": {
        "COMPANY": "Brightline"
      }
    }
  }
}
```
