Documentation

Print your first document

Composa prints documents from a template. Your AI agent designs the template over MCP, you look it over in the editor, and your code prints one copy — or five hundred — per HTTP call, each with its own data.

Connect your agent

Add Composa’s MCP server to your agent. In Claude Code:

terminal
claude mcp add --transport http --scope user composa https://mcp.composa.dev/mcp

The first time it connects, your browser opens: sign in to Composa (or create an account), choose the team, and Allow. There is no key to paste. Cursor, VS Code, Codex, Claude Desktop and any other MCP client: MCP server → Connect.

Design a template

Ask your agent for the document, and name what changes from one copy to the next:

prompt
Make a one-page A4 certificate in Composa. The recipient's name and the course
change per copy: make them variables called customer_name and course.

It answers with a link to the editor, where you watch the page being built and can change anything by hand. A variable prints as {{customer_name}} until your data fills it. When it looks right, ask the agent to publish it — or press Publish in the editor. The API prints the published version, never the draft you are still editing.

The project’s id is in its editor link, /typeset/<project id>, and in the agent’s list_projects. That id is the template_id below.

Create an API key

Open Press Room → API keys, name the key after where it will live (“billing server”), and copy it: it is shown once. Keep it on your server, never in a browser or an app.

terminal
export COMPOSA_API_KEY="cmp_live_…"

Print it

One call, one document. The answer is the PDF itself:

curl -X POST https://composa.dev/api/v1/run \
  -H "Authorization: Bearer $COMPOSA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "template_id": "YOUR_PROJECT_ID",
    "data": { "customer_name": "Alice Moreau", "course": "Typography I" }
  }' \
  --fail-with-body --output certificate.pdf

A name you send that the template does not have is ignored; one you leave out prints the sample the template was designed with. Every field, format and answer: HTTP API.

Print many at once

Send items instead of data and each item becomes its own document, returned together as JSON (base64):

json
{
  "template_id": "YOUR_PROJECT_ID",
  "items": [
    { "name": "alice", "data": { "customer_name": "Alice Moreau" } },
    { "name": "bruno", "data": { "customer_name": "Bruno Lima" } }
  ]
}
  • Up to 500 items per call.
  • An item that fails carries its own error; the others still print, and the call answers 200.
  • Ask for compression (curl --compressed, Accept-Encoding: gzip): copies of one template compress very well.