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

# Changelog

Every change to the API, newest first. Breaking changes only arrive in a new version.

### Documents, video edits and designs, and an MCP server (2026-10-09)

- Added: `GET /documents` lists your workspace’s documents; `templates=true` lists only team templates.
- Added: `POST /documents` makes a document 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 …”, and gaps nobody filled come back as `gaps_left`.
- Added: `POST /documents/{id}/export` makes the PDF (accessible by default), keeps it with the workspace’s PDFs and returns a download link valid for a few hours.
- Added: `POST /videos/{id}/edit` applies the video editor’s operations, checked as the editor checks them, and saves a new version for Workloom to render. Nothing half-applied is saved.
- Added: `POST /designs` makes a blank design of a format or size, with a link to open it in Workloom’s image editor.
- Added: Scopes `creative:read` and `creative:write`. A test key answers with what would happen and changes nothing.
- Added: An MCP server at `/api/public/v1/mcp` with the same four tools (`workloom.document.create`, `workloom.document.export`, `workloom.video.edit`, `workloom.design.create`), using the same keys: `creative:read` to connect, `creative:write` for a tool that makes or changes something.

### Developer sandboxes (2026-10-07)

- Added: A developer sandbox for every workspace on Starter and above: a separate workspace of fictional records (40 companies, 120 contacts, 28 deals, a list, a live weave, an active sequence) at `https://sandbox-api.useworkloom.com/api/public/v1`, with `wl_sbx_` keys made inside it. Writes are saved there; nothing is ever sent, called or charged. Make, open and reset it under Settings › API and webhooks.
- Added: Webhooks from a sandbox reach your server, signed and retried as from the live API.
- Added: `POST /sandbox/events` (sandbox only): make a reply, an open, a click, a bounce, a meeting, a booking, a form, a call, a Tell or an unsubscribe happen, to test your webhook handler.
- Added: Error codes: `sandbox_only` (the live API, for a sandbox-only endpoint) and `sandbox_key` (a `wl_sbx_` key sent to the live API).

### Sorting, and dated versions (2026-10-07)

- Added: `sort` on `GET /contacts`, `/companies` and `/deals`, and in the body of their searches: one field, with `-` in front for newest or largest first. Contacts sort by `created_at` or `updated_at`; companies also by `employee_count`; deals also by `amount`, `expected_close_date` and `closed_at`. Paging stays a cursor.
- Added: The `Workloom-Version` header. Keys and webhook endpoints are pinned to the version current when they were made (`workloom_version`), so a later breaking change never reaches them unasked. Every answer and every delivery says its version. The first version is `2026-10-07`.
- Added: `workloom_version` on webhook endpoints and in every delivery. Error code: `unsupported_version`.

### Pipelines, teammates, search, timelines, lists, enrolling and webhook endpoints (2026-10-07)

- Added: `GET /pipelines` (stages in order, and the lost, won and parked reasons) and `GET /seats` (teammates), so stage keys, reason keys and `owner_seat_id` can be looked up.
- Added: `custom_fields` on contacts, companies and deals, written with them and listed by `GET /custom-fields`.
- Added: `POST /contacts/search`, `/companies/search` and `/deals/search`, with filters on declared fields and your own fields.
- Added: `POST /contacts/upsert` (by email), `DELETE /contacts/{id}` (the contact stays suppressed) and `DELETE /deals/{id}`.
- Added: Timelines for contacts, companies and deals; notes; tasks.
- Added: Lists and their members: read, add and remove.
- Added: `GET /outreach`, `POST /weaves/{id}/enrol` and `POST /sequences/{id}/enrol`.
- Added: Webhook endpoints over the API (`webhooks:manage`), with the delivery log and resending a delivery.
- Added: Webhook events: `contact.updated`, `company.updated`, `deal.updated`, `contact.deleted`, `company.deleted`, `deal.deleted`, `contact.unsubscribed` and `email.sent`.
- Added: Scopes: `team:read`, `activity:read`, `activity:write`, `lists:read`, `lists:write`, `outreach:write`, `webhooks:manage`. Error codes: `suppressed`.
- Fixed: A deleted deal no longer stops its contact from getting a new deal in the same pipeline.

### Writes for contacts and companies, test keys, and a fixed webhook contract (2026-10-07)

- Added: `POST /contacts`, `PATCH /contacts/{id}`, `POST /companies` and `PATCH /companies/{id}`. The `contacts:write` and `companies:write` scopes now do something.
- Added: Test keys (`wl_test_`). They read the same records as a live key and change nothing: every write is checked and answered with `livemode: false`.
- Added: `Idempotency-Key` on POST requests. A retry with the same key returns the first answer.
- Added: A `code` on every error, from a published list.
- Added: The OpenAPI 3.1 file at `GET /openapi.json`, and `GET /events` listing every webhook event.
- Added: Deals now return `pipeline_id`, `probability`, `forecast_category`, `next_step`, `primary_contact_id`, `contacts` and `company_id`. Contacts return `full_name` and `location`. Companies return `employee_range`, `owner_seat_id` and `tags`. `GET /deals` takes `pipeline_id`.
- Changed: Webhooks use public event names (`deal.won`, `reply.received`), an envelope with `event_id`, `api_version` and `livemode`, and a fixed set of fields per event. `*` means every public event. Endpoints subscribed to the old internal names keep receiving those events, under the new names and with the new fields.
- Changed: A body field an endpoint does not accept is refused with `unknown_fields` instead of being ignored.
- Changed: The revenue report has a fixed shape.
- Fixed: Every retry of a webhook delivery now carries the same `X-Workloom-Delivery` id, so you can drop repeats.
- Fixed: A key acting for one person now sees only the companies that person can see.
- Fixed: Deleted contacts no longer appear in `GET /contacts`.
- Fixed: Company `created_at`, `updated_at`, `linkedin_url`, `employee_count` and `location` were empty or the wrong type.

### Service accounts and the Activity log stream (2026-09-23)

- Added: Service accounts: keys that act with a role, with a rotation date. Rotating keeps the old key working for 24 hours.
- Added: Webhooks can stream the Activity log. It is never part of `*`; subscribe to it by name.

### Version 1 (2026-09-20)

- Added: Read contacts, companies and deals; create, update and move deals; the revenue report.
- Added: API keys with scopes, made in Settings › API and webhooks. 300 requests a minute per key.
- Added: Signed webhooks with retries, a delivery log and a test button.

> Breaking changes come only as a new dated version, and reach a key or webhook endpoint only when someone moves it. An old version stops working only after 6 months’ notice here.
