Texify

API docs

Render PDFs from LaTeX and templates.

Texify accepts raw LaTeX resources plus optional data, compiles documents in an isolated workspace, and returns PDF bytes. Agents can connect through the remote MCP server with no local install.

Quick render
curl -X POST https://api.texify.dev/render \
  -H "Content-Type: application/json" \
  --output invoice.pdf \
  --data '{
    "entrypoint": "main.tex",
    "resources": {
      "main.tex": "\\documentclass{article}\n\\begin{document}Invoice #123\\end{document}"
    }
  }'

Quickstart

Raw LaTeX endpoint. PDF bytes back.

Endpointhttps://api.texify.dev/render
MethodPOST
Inputapplication/json or multipart/form-data
Outputapplication/pdf

Send one main LaTeX file plus any files it imports. JSON works well when your app generates source strings. Multipart works better for existing files, images, or larger projects. Save the response body directly as a PDF.

entrypointstring

Optional. Relative path to the .tex file Texify should compile. Defaults to the first .tex file after resource names are sorted.

resourcesobject

Required for JSON requests. Keys are relative filenames. Values are file contents as strings.

dataobject

Optional for JSON requests. Values are available to [[ ]] templates inside resource contents.

JSON resources support Go text/template placeholders with [[ ... ]] delimiters. Missing keys fail the render. Strings are LaTeX-escaped by default; use [[ raw .field ]] only when you trust the value. Multipart uploads do not run data templating.

JSON resources body
POST /render HTTP/1.1
Host: api.texify.dev
Content-Type: application/json

{
  "entrypoint": "main.tex",
  "resources": {
    "main.tex": "\\documentclass{article}\n\\usepackage{booktabs}\n\\begin{document}\n\\input{sections/summary.tex}\n\\end{document}",
    "sections/summary.tex": "Revenue report for [[ .month ]]."
  },
  "data": {
    "month": "June 2026"
  }
}
Multipart file upload
curl -X POST https://api.texify.dev/render \
  -F "entrypoint=main.tex" \
  -F "main.tex=@main.tex;filename=main.tex" \
  -F "sections/summary.tex=@sections/summary.tex;filename=sections/summary.tex" \
  --output report.pdf
Python requests
import requests

payload = {
    "entrypoint": "invoice.tex",
    "resources": {
        "invoice.tex": r"""
\documentclass{article}
\begin{document}
Invoice #123
\end{document}
"""
    },
}

response = requests.post("https://api.texify.dev/render", json=payload, timeout=90)

if response.status_code != 200:
    body = response.json()
    raise RuntimeError(body["error"])

with open("invoice.pdf", "wb") as file:
    file.write(response.content)
Node fetch
import { readFile, writeFile } from "node:fs/promises";

const tex = await readFile("invoice.tex", "utf8");

const response = await fetch("https://api.texify.dev/render", {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  signal: AbortSignal.timeout(90_000),
  body: JSON.stringify({
    entrypoint: "invoice.tex",
    resources: { "invoice.tex": tex },
  }),
});

if (!response.ok) {
  const body = await response.json();
  throw new Error(body.error);
}

const pdf = Buffer.from(await response.arrayBuffer());
await writeFile("invoice.pdf", pdf);

Templates

Copy templates. Render them as resources.

Browse the template gallery, copy the LaTeX into your app, then POST it to /render as resources with optional data. Hosted template-ID endpoints are on the roadmap.

Endpointhttps://api.texify.dev/render
MethodPOST
Inputapplication/json
Outputapplication/pdf
Copied template render
curl -X POST https://api.texify.dev/render \
  -H "Content-Type: application/json" \
  --output invoice.pdf \
  --data '{
    "entrypoint": "invoice.tex",
    "resources": {
      "invoice.tex": "\\documentclass{article}\n\\begin{document}Invoice [[ .invoiceNumber ]] for [[ .client.name ]]\\end{document}"
    },
    "data": {
      "invoiceNumber": "INV-2026-042",
      "client": {
        "name": "Northwind Labs"
      }
    }
  }'

MCP

Connect agents without an install.

Texify exposes a remote MCP server at https://api.texify.dev/mcp using streamable HTTP. Add it to Claude Code or Cursor as a URL-backed server; no package install or local process is required.

Claude Code / Cursor MCP config
{
  "mcpServers": {
    "texify": {
      "url": "https://api.texify.dev/mcp"
    }
  }
}

Prefer an agent skill? Install the Texify skill from github.com/texifydotdev.

Install agent skill
opencode skill add https://github.com/texifydotdev

The MCP tool is render_latex. It accepts the same entrypoint, resources, and data shape as JSON REST requests. Successful tool calls return a download URL with a 60-second TTL; compile failures return the verbatim LaTeX log in the tool error.

render_latex success
{
  "status": "ok",
  "download_url": "https://api.texify.dev/d/pdf_abc123"
}

Errors

Use error snippets as repair input.

Bad REST requests return 400 with {"error":"..."}. If LaTeX runs but fails, REST returns 422 with a trimmed compile-log snippet in error; timeouts return {"error":"latex render timed out"}. Full verbatim logs are available through MCP tool errors.

422 compile error
HTTP/1.1 422 Unprocessable Entity
Content-Type: application/json

{
  "error": "latex render failed: ! Undefined control sequence.
l.12 \totl
The control sequence at the end of the top line was never \def'ed."
}

Limits

Operational limits for stable renders.

  • Beta limits may change as the API hardens.
  • Max request body: 20 MB.
  • Render timeout: 30 seconds per pdflatex pass.
  • Texify runs pdflatex twice so references, page numbers, and table of contents can settle.
  • Each render uses a fresh temporary workspace and returns Cache-Control: no-store.
  • Filenames must be relative. Absolute paths and parent traversal are rejected.
  • The entrypoint must end in .tex and must exist in resources or uploaded files.