LaTeX API

Quickstart

Compile a document in under a minute with curl, then with the SDK and the CLI.

Create a free account, then create a personal token under Dashboard → API tokens and put it in LATEX_API_TOKEN. With the CLI you can skip that step: latex-api auth login signs you in through the browser.

1. curl

Write a document:

main.tex
\documentclass{article}
\begin{document}
Hello from the cloud.
\end{document}

Send it as the raw body and save the PDF:

curl https://latex-api.crafter.run/v1/compile \
  -H "Authorization: Bearer $LATEX_API_TOKEN" \
  -H "Content-Type: text/x-tex" \
  --data-binary @main.tex \
  -o main.pdf

A successful response is 200 with the PDF and three headers:

X-Job-Id: 7f1c7f9e-3b1e-4d2a-9a1a-2f0c1b7e5d11
X-Compile-Cached: false
X-Compile-Warnings: 0

If LaTeX reports errors you get 422 with diagnostics instead. Add -w '%{http_code}' or use --fail-with-body to notice it in scripts. To see the diagnostics on success too, ask for JSON:

curl https://latex-api.crafter.run/v1/compile \
  -H "Authorization: Bearer $LATEX_API_TOKEN" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json" \
  -d '{"files":[{"path":"main.tex","content":"\\documentclass{article}\\begin{document}Hello\\end{document}"}]}'
{
  "job": {
    "id": "7f1c7f9e-3b1e-4d2a-9a1a-2f0c1b7e5d11",
    "status": "succeeded",
    "mode": "sync",
    "engine": "pdflatex",
    "entrypoint": "main.tex",
    "result": {
      "cached": false,
      "durationMs": 1830,
      "exitCode": 0,
      "errors": 0,
      "warnings": 0,
      "pages": 1,
      "pdfBytes": 13211,
      "pdfUrl": "https://latex-api.crafter.run/v1/jobs/7f1c7f9e-.../pdf",
      "logUrl": "https://latex-api.crafter.run/v1/jobs/7f1c7f9e-.../log",
      "diagnostics": []
    },
    "links": { "self": "https://latex-api.crafter.run/v1/jobs/7f1c7f9e-...", "pdf": "...", "log": "..." }
  }
}

2. TypeScript SDK

npm install @jibaru/latex-api-sdk
import { LatexApi } from "@jibaru/latex-api-sdk";
import { readFile, writeFile } from "node:fs/promises";

const api = new LatexApi({
  apiKey: process.env.LATEX_API_TOKEN!,
  baseUrl: "https://latex-api.crafter.run",
});

const pdf = await api.compile({
  engine: "pdflatex",
  files: [{ path: "main.tex", content: await readFile("main.tex", "utf8") }],
});

await writeFile("main.pdf", pdf); // Uint8Array

Long documents are better as jobs:

const job = await api.jobs.create({ files, options: { timeoutMs: 300_000 } });
const finished = await api.jobs.wait(job.id);
if (finished.status === "succeeded") console.log(finished.result?.pdfUrl);

More in SDK.

3. CLI

npx @jibaru/latex-api-cli auth login       # approve in the browser; the token goes to your OS keychain
npx @jibaru/latex-api-cli compile ./paper  # zips the folder, uploads it, writes paper.pdf
npx @jibaru/latex-api-cli compile ./paper --watch

--watch recompiles on every save and streams the compiler log over SSE. More in CLI.

Without an account

The landing page playground calls POST /v1/demo/compile, which needs no account but is limited to small single-file documents and a few compiles per minute. It is meant for trying things, not for production.

On this page