---
title: "Developer API and MCP - Workflow Documents"
description: "API keys, the REST API and the MCP server: manage templates and branding and generate PDF documents from your own code or an AI agent."
canonical: "https://docs.workflow-documents.app/developer-api-and-mcp"
---

# Developer API and MCP

What you do in the app, you can also do from your own code or from an AI agent. Workflow Documents has a **REST API** and an **MCP server**, both on the **Developer** page. Use them to manage templates, change your branding, read the document history and generate documents.

## API keys

On **Developer**, tab **API keys**, select **Create API key**, give it a name and pick the access level:

- **Read only** - list and read templates and documents.
- **Read & write** - also create, update and delete templates, and generate documents.

The full key is shown **once**, together with a test request and ready setup commands for AI clients. Store it securely: only a fingerprint of the key is kept, so a lost key is replaced, not recovered. You can have up to 20 active keys and revoke a key at any time. Give each system its own key, so you can revoke one without touching the others.

Send the key as a Bearer token on every request:

```text
Authorization: Bearer wdk_your_key_here
```

## REST API

The base URL is shown on the Developer page as **REST API base URL**. It ends in `/api/v1`. The examples below use `https://shopify.workflow-documents.app/api/v1`.

| Method | Path | Purpose |
| --- | --- | --- |
| GET | `/me` | Check the key and see its level |
| GET | `/plan` | Your plan, allowance, usage of the last 30 days, what is left of it and the PDF retention |
| GET | `/templates` | List templates, without their HTML |
| POST | `/templates` | Create a template from `name`, `resource` and `html`, or from a ready-made one with `starter` |
| GET | `/templates/:id` | One template with its HTML and CSS |
| PATCH | `/templates/:id` | Change the given fields of a template |
| DELETE | `/templates/:id` | Delete a template |
| GET | `/branding` | Your branding and the fonts it may choose from |
| PATCH | `/branding` | Change the given branding fields |
| GET | `/documents` | The document history, with `status`, `trigger`, `templateId`, `q`, `page` and `limit` as query parameters |
| POST | `/documents` | Generate a document |
| GET | `/documents/:id` | One document. Add `?link=1` for a fresh 7-day download link while the PDF is stored |

A quick check that your key works:

```bash
curl https://shopify.workflow-documents.app/api/v1/me \
  -H "Authorization: Bearer wdk_your_key_here"
```

### Generate a document

Send the template, by `templateId` or `templateName`, and `resourceId`: the id of the order, product or customer the template renders. A plain number or a Shopify gid both work. `language` is optional and picks one of the template's languages. Without it the customer's language is used.

```bash
curl -X POST https://shopify.workflow-documents.app/api/v1/documents \
  -H "Authorization: Bearer wdk_your_key_here" \
  -H "Content-Type: application/json" \
  -d '{ "templateName": "Invoice", "resourceId": "gid://shopify/Order/1234567890", "language": "de" }'
```

The PDF is rendered within the request, which takes a few seconds. The answer carries the document with its download link:

```json
{
  "document": {
    "id": "1042",
    "filename": "Invoice-1001.pdf",
    "sizeBytes": 48213,
    "url": "https://...",
    "expiresAt": "2026-10-11T09:30:00.000Z",
    "resourceName": "#1001"
  }
}
```

The link is valid for 7 days. Errors come back with a message and one of these statuses:

| Status | Meaning |
| --- | --- |
| 400 | The request is incomplete, for example no id for the resource the template renders |
| 402 | Your plan's documents for the last 30 days are used up |
| 404 | The template, or the order, product or customer, was not found |
| 409 | The template is turned off |
| 422 | The document could not be generated, for example a template error |
| 429 | Rate limit reached, with a retry time |
| 503 | A temporary problem. Retry |

### Create and update templates

A template takes `name`, `resource` (order, product or customer), `html`, and optionally `css`, `filename`, `paperSize`, `landscape`, `marginMm`, `enabled`, `description`, `defaultLocale` and `branding`. To copy a ready-made template, send only `starter` with one of `invoice`, `packing-slip`, `product-sheet`, `customer-summary` or `blank`.

As in the editor, a template is only stored when it renders with sample data. Otherwise the call is refused with the error and the field it belongs to.

`branding` on a template is the template's own override of colors, fonts and font size. It replaces the stored override as a whole: send an empty object to go back to your brand.

Templates list their added languages in `languages`. Languages themselves are added and edited in the app.

### Branding

`PATCH /branding` accepts `primaryColor`, `accentColor`, `textColor`, `mutedColor`, `borderColor`, `headingFont`, `bodyFont`, `fontSize`, `logoWidth`, `companyName`, `address`, `taxId` and `footerText`. Fonts are ids from the `fonts` list of `GET /branding`. The logo and custom font files are uploaded in the app.

## MCP server

The MCP server lets an AI agent (Claude, Cursor, VS Code, Gemini CLI, OpenAI Codex and others) manage your templates and generate documents. The **MCP** tab shows the server URL, which ends in `/api/mcp`, and a connect command per client. After you create a key, the same commands come with the key already filled in.

The tools mirror the REST API:

| Tool | Access |
| --- | --- |
| `list_templates`, `get_template` | Read |
| `list_documents`, `get_document` | Read |
| `get_branding` | Read |
| `create_template`, `update_template`, `delete_template` | Read & write |
| `update_branding` | Read & write |
| `generate_document` | Read & write |

A read-only key only gets the read tools.

## API and MCP documents count toward your plan

A document generated through the API or MCP counts toward your plan like one from Shopify Flow, and appears in **Documents** with the source **API**. A failed document is not counted. Reading templates, documents and branding is free. When your allowance is used up, generating is refused with `402` until the rolling 30-day window frees up or you change to a larger plan. See [Plans and pricing](https://docs.workflow-documents.app/plans-and-pricing.md).

## Rate limits

A leaky bucket per key, the same model Shopify uses: bursts of up to 300 requests, refilling 5 per second. Generating documents has its own bucket of 60, refilling 1 per second. Over the limit you get `429` with a retry time: back off and retry. Limits are the same on every plan.

The API is versioned in the path (`/api/v1`). A breaking change would ship as `/api/v2` with notice.

## Next steps

- [Template variables and Liquid](https://docs.workflow-documents.app/template-variables-and-liquid.md) - what a template can print.
- [Templates in several languages](https://docs.workflow-documents.app/languages.md) - how the `language` of a document is chosen.
- [Document history and downloads](https://docs.workflow-documents.app/document-history.md) - documents generated through the API.
