{"openapi":"3.1.0","info":{"title":"LaTeX API","version":"main-533879f","description":"Compile LaTeX projects to PDF over HTTP: papers, CVs, brochures, posters and reports. Every compile runs in an isolated container with pdflatex, xelatex or lualatex from TeX Live 2026.","license":{"name":"MIT","url":"https://github.com/jibaru/latex-api/blob/main/LICENSE"},"contact":{"name":"latex-api","url":"https://github.com/jibaru/latex-api"}},"servers":[{"url":"https://latex-api.crafter.run","description":"This server"}],"tags":[{"name":"Compile","description":"Synchronous compilation"},{"name":"Jobs","description":"Asynchronous jobs, artifacts and live events"},{"name":"Templates","description":"Ready-to-use starter projects"},{"name":"Account","description":"Identity, personal API tokens and CLI sign-in"},{"name":"Meta","description":"Limits, health and statistics"}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","description":"A personal API token (`lta_...`) from the dashboard or `latex-api auth login`. Also accepted in the `X-API-Key` header."}},"schemas":{"Limits":{"type":"object","properties":{"maxUploadBytes":{"type":"number"},"maxUnpackedBytes":{"type":"number"},"maxFiles":{"type":"number"},"maxFileBytes":{"type":"number"},"syncTimeoutMs":{"type":"number"},"jobTimeoutMs":{"type":"number"},"jobTimeoutMaxMs":{"type":"number"},"jobMemoryBytes":{"type":"number"},"jobCpus":{"type":"number"},"artifactTtlHours":{"type":"number"},"rateLimitPerKeyPerHour":{"type":"number"},"rateLimitConcurrentPerKey":{"type":"number"},"engines":{"type":"array","items":{"type":"string"}}},"required":["maxUploadBytes","maxUnpackedBytes","maxFiles","maxFileBytes","syncTimeoutMs","jobTimeoutMs","jobTimeoutMaxMs","jobMemoryBytes","jobCpus","artifactTtlHours","rateLimitPerKeyPerHour","rateLimitConcurrentPerKey","engines"]},"Stats":{"type":"object","properties":{"byStatus":{"type":"object","additionalProperties":{"type":"number"}},"last24h":{"type":"object","properties":{"total":{"type":"number"},"succeeded":{"type":"number"},"failed":{"type":"number"},"cached":{"type":"number"}},"required":["total","succeeded","failed","cached"]},"durationMs":{"type":"object","properties":{"p50":{"type":"number"},"p95":{"type":"number"}},"required":["p50","p95"]},"queueDepth":{"type":"number"},"storage":{"type":"object","properties":{"usedBytes":{"type":"number"},"freeBytes":{"type":"number"}},"required":["usedBytes"]},"compilerVersion":{"type":"string"}},"required":["byStatus","last24h","durationMs","queueDepth","storage","compilerVersion"]},"Problem":{"type":"object","properties":{"type":{"type":"string"},"title":{"type":"string"},"status":{"type":"number"},"detail":{"type":"string"},"instance":{"type":"string"},"code":{"type":"string"}},"required":["type","title","status","code"],"additionalProperties":{},"description":"RFC 9457 problem details."},"Health":{"type":"object","properties":{"status":{"type":"string","enum":["ok","degraded"]},"version":{"type":"string"},"checks":{"type":"object","additionalProperties":{"type":"object","properties":{"ok":{"type":"boolean"},"detail":{"type":"string"}},"required":["ok"]}}},"required":["status","version","checks"]},"DemoCompileRequest":{"type":"object","properties":{"source":{"type":"string","minLength":1,"maxLength":200000,"description":"Single-file document source."},"files":{"type":"array","items":{"$ref":"#/components/schemas/ProjectFile"},"maxItems":20},"entrypoint":{"type":"string"},"engine":{"$ref":"#/components/schemas/Engine"}}},"ProjectFile":{"type":"object","properties":{"path":{"type":"string","minLength":1,"maxLength":1024,"example":"main.tex","description":"Relative POSIX path inside the project."},"content":{"type":"string","description":"File content, UTF-8 text or base64 when `encoding` is `base64`."},"encoding":{"type":"string","enum":["utf8","base64"],"example":"utf8"}},"required":["path","content"]},"Engine":{"type":"string","enum":["pdflatex","xelatex","lualatex"],"description":"TeX engine. Detected from a `% !TEX program = ...` magic comment when omitted; defaults to pdflatex."},"Me":{"type":"object","properties":{"user":{"$ref":"#/components/schemas/User"},"principal":{"type":"object","properties":{"name":{"type":"string"},"kind":{"type":"string","enum":["user","key","demo","anonymous"]},"via":{"type":"string","enum":["token","session","env"]},"tokenId":{"type":"string"}},"required":["name","kind"]}},"required":["user","principal"]},"User":{"type":["object","null"],"properties":{"id":{"type":"string"},"email":{"type":"string"}},"required":["id"]},"ApiToken":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"prefix":{"type":"string","example":"lta_Ab12Cd34"},"origin":{"type":"string","enum":["dashboard","cli","api"]},"status":{"type":"string","enum":["active","expired","revoked"]},"createdAt":{"type":"string"},"expiresAt":{"type":"string"},"lastUsedAt":{"type":"string"},"revokedAt":{"type":"string"}},"required":["id","name","prefix","origin","status","createdAt"]},"CreatedApiToken":{"type":"object","properties":{"token":{"type":"string","description":"The secret. Shown once; store it now."},"apiToken":{"$ref":"#/components/schemas/ApiToken"}},"required":["token","apiToken"]},"CreateApiTokenRequest":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":80,"example":"GitHub Actions"},"expiresInDays":{"type":["integer","null"],"minimum":1,"maximum":3650,"description":"Omit or null for a token that never expires."}},"required":["name"]},"Job":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"status":{"type":"string","enum":["queued","running","succeeded","failed","timed_out","cancelled"]},"mode":{"type":"string","enum":["sync","async","demo"]},"engine":{"$ref":"#/components/schemas/Engine"},"entrypoint":{"type":"string"},"templateId":{"type":"string"},"createdAt":{"type":"string","format":"date-time"},"startedAt":{"type":"string","format":"date-time"},"finishedAt":{"type":"string","format":"date-time"},"expiresAt":{"type":"string","format":"date-time"},"options":{"type":"object","properties":{"timeoutMs":{"type":"number"},"bibliography":{"$ref":"#/components/schemas/BibliographyMode"},"webhookUrl":{"type":"string"}},"required":["timeoutMs","bibliography"]},"result":{"$ref":"#/components/schemas/JobResult"},"error":{"type":"object","properties":{"reason":{"type":"string","enum":["compile_failed","timeout","cancelled","internal"]},"message":{"type":"string"}},"required":["reason","message"]},"links":{"type":"object","properties":{"self":{"type":"string"},"events":{"type":"string"},"pdf":{"type":"string"},"log":{"type":"string"}},"required":["self"]}},"required":["id","status","mode","engine","entrypoint","createdAt","expiresAt","options","links"]},"BibliographyMode":{"type":"string","enum":["auto","bibtex","biber","none"],"description":"`auto` runs bibtex/biber only when the document needs it."},"JobResult":{"type":"object","properties":{"cached":{"type":"boolean"},"durationMs":{"type":"number"},"exitCode":{"type":["number","null"]},"errors":{"type":"number"},"warnings":{"type":"number"},"pages":{"type":"number"},"pdfBytes":{"type":"number"},"pdfUrl":{"type":"string"},"logUrl":{"type":"string"},"diagnostics":{"type":"array","items":{"$ref":"#/components/schemas/Diagnostic"}}},"required":["cached","durationMs","exitCode","errors","warnings","logUrl","diagnostics"]},"Diagnostic":{"type":"object","properties":{"severity":{"type":"string","enum":["error","warning","info"]},"message":{"type":"string"},"file":{"type":"string"},"line":{"type":"integer"},"context":{"type":"string"},"source":{"type":"string"}},"required":["severity","message"]},"DeviceAuthorizationStart":{"type":"object","properties":{"deviceCode":{"type":"string"},"userCode":{"type":"string","example":"WDJB-MJHT"},"verificationUri":{"type":"string"},"verificationUriComplete":{"type":"string"},"expiresIn":{"type":"number"},"interval":{"type":"number"}},"required":["deviceCode","userCode","verificationUri","verificationUriComplete","expiresIn","interval"]},"DeviceToken":{"type":"object","properties":{"token":{"type":"string"},"tokenId":{"type":"string"},"name":{"type":"string"},"expiresAt":{"type":"string"},"user":{"$ref":"#/components/schemas/User"}},"required":["token","tokenId","name","user"]},"DeviceAuthorization":{"type":"object","properties":{"userCode":{"type":"string"},"status":{"type":"string","enum":["pending","approved","denied","consumed","expired"]},"clientName":{"type":"string"},"hostname":{"type":"string"},"platform":{"type":"string"},"createdAt":{"type":"string"},"expiresAt":{"type":"string"}},"required":["userCode","status","clientName","createdAt","expiresAt"]},"JobEnvelope":{"type":"object","properties":{"job":{"$ref":"#/components/schemas/Job"}},"required":["job"]},"CompileFailedProblem":{"allOf":[{"$ref":"#/components/schemas/Problem"},{"type":"object","properties":{"code":{"type":"string","enum":["compile_failed"]},"jobId":{"type":"string"},"diagnostics":{"type":"array","items":{"$ref":"#/components/schemas/Diagnostic"}},"logUrl":{"type":"string"},"pdfUrl":{"type":"string"}},"required":["jobId","diagnostics","logUrl"],"additionalProperties":{}}],"description":"RFC 9457 problem details."},"CompileRequest":{"type":"object","properties":{"files":{"type":"array","items":{"$ref":"#/components/schemas/ProjectFile"},"minItems":1,"maxItems":1000},"entrypoint":{"type":"string","example":"main.tex","description":"Main .tex file. Guessed when there is a single .tex or a main.tex."},"engine":{"$ref":"#/components/schemas/Engine"},"options":{"$ref":"#/components/schemas/CompileOptions"}},"required":["files"],"example":{"files":[{"path":"main.tex","content":"\\documentclass{article}\\begin{document}Hello\\end{document}"}],"engine":"pdflatex"}},"CompileOptions":{"type":"object","properties":{"timeoutMs":{"type":"integer","exclusiveMinimum":0,"example":60000,"description":"Capped by the server limits."},"bibliography":{"$ref":"#/components/schemas/BibliographyMode"},"webhookUrl":{"type":"string","format":"uri","description":"Async jobs only: POSTed with the job when it finishes."},"force":{"type":"boolean","description":"Skip the content-addressed cache."}}},"Template":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"description":{"type":"string"},"category":{"type":"string","enum":["paper","cv","brochure","poster","report","letter","other"]},"engine":{"$ref":"#/components/schemas/Engine"},"entrypoint":{"type":"string"},"tags":{"type":"array","items":{"type":"string"}},"license":{"type":"string"},"source":{"type":"string"},"variables":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string"},"description":{"type":"string"},"default":{"type":"string"}},"required":["name","description"]}},"files":{"type":"array","items":{"$ref":"#/components/schemas/TemplateFile"}},"links":{"type":"object","properties":{"self":{"type":"string"},"archive":{"type":"string"},"preview":{"type":"string"},"compile":{"type":"string"}},"required":["self","archive","preview","compile"]}},"required":["id","name","description","category","engine","entrypoint","tags","license","variables","files","links"]},"TemplateFile":{"type":"object","properties":{"path":{"type":"string"},"size":{"type":"number"},"editable":{"type":"boolean"}},"required":["path","size"]},"TemplateCompileRequest":{"type":"object","properties":{"files":{"type":"array","items":{"$ref":"#/components/schemas/ProjectFile"},"description":"Files that replace or extend the template files."},"entrypoint":{"type":"string"},"engine":{"$ref":"#/components/schemas/Engine"},"options":{"$ref":"#/components/schemas/CompileOptions"}}}},"parameters":{}},"paths":{"/v1/limits":{"get":{"tags":["Meta"],"summary":"Effective server limits","responses":{"200":{"description":"Limits","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Limits"}}}}}}},"/v1/stats":{"get":{"tags":["Meta"],"summary":"Usage statistics","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Stats","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Stats"}}}},"401":{"description":"Unauthorized","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/health":{"get":{"tags":["Meta"],"summary":"Health check","responses":{"200":{"description":"Healthy","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Health"}}}},"503":{"description":"Degraded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Health"}}}}}}},"/v1/demo/compile":{"post":{"tags":["Compile"],"summary":"Compile without an API key (playground)","description":"Heavily rate limited per IP and restricted to small JSON projects. Returns the same responses as `/v1/compile`.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DemoCompileRequest"}}}},"responses":{"200":{"description":"PDF or job envelope","content":{"application/pdf":{"schema":{"type":"string","format":"binary"}}}},"422":{"description":"LaTeX reported errors","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Rate limited","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/v1/me":{"get":{"tags":["Account"],"summary":"Who am I","description":"Returns the identity behind the credential. Useful to validate a token.","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Identity","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Me"}}}},"401":{"description":"Missing or invalid credential","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/v1/tokens":{"get":{"tags":["Account"],"summary":"List your personal API tokens","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Tokens, newest first. Secrets are never returned.","content":{"application/json":{"schema":{"type":"object","properties":{"tokens":{"type":"array","items":{"$ref":"#/components/schemas/ApiToken"}}},"required":["tokens"]}}}},"403":{"description":"Operator keys have no personal tokens","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}},"post":{"tags":["Account"],"summary":"Create a personal API token","description":"The secret is returned once. Tokens last until revoked or until `expiresInDays`.","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateApiTokenRequest"}}}},"responses":{"201":{"description":"Created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreatedApiToken"}}}},"403":{"description":"Operator keys cannot create personal tokens","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"Too many active tokens","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/v1/tokens/{id}":{"delete":{"tags":["Account"],"summary":"Revoke a personal API token","security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string"},"required":true,"name":"id","in":"path"}],"responses":{"200":{"description":"Revoked","content":{"application/json":{"schema":{"type":"object","properties":{"apiToken":{"$ref":"#/components/schemas/ApiToken"}},"required":["apiToken"]}}}},"404":{"description":"Unknown token","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/v1/jobs":{"get":{"tags":["Jobs"],"summary":"List your recent jobs","security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"integer","minimum":1,"maximum":100,"example":20},"required":false,"name":"limit","in":"query"}],"responses":{"200":{"description":"Jobs, newest first","content":{"application/json":{"schema":{"type":"object","properties":{"jobs":{"type":"array","items":{"$ref":"#/components/schemas/Job"}}},"required":["jobs"]}}}}}},"post":{"tags":["Jobs"],"summary":"Create an asynchronous compile job","description":"Accepts the same bodies as `/v1/compile` and returns immediately with a job you can poll, stream (`/events`) or get notified about through `options.webhookUrl`.","security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string"},"required":false,"name":"engine","in":"query"},{"schema":{"type":"string"},"required":false,"name":"entrypoint","in":"query"},{"schema":{"type":"string"},"required":false,"name":"timeoutMs","in":"query"},{"schema":{"type":"string"},"required":false,"name":"bibliography","in":"query"},{"schema":{"type":"string"},"required":false,"name":"force","in":"query"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CompileRequest"}},"multipart/form-data":{"schema":{"type":"object","properties":{"files":{"type":"array","items":{"type":"string","format":"binary"},"description":"One part per file; the filename may contain a relative path."},"project":{"type":"string","format":"binary","description":"A zip archive with the whole project."},"entrypoint":{"type":"string"},"engine":{"type":"string","enum":["pdflatex","xelatex","lualatex"]},"options":{"type":"string","description":"JSON-encoded CompileOptions."}}}},"application/zip":{"schema":{"type":"string","format":"binary"}},"text/x-tex":{"example":"\\documentclass{article}\\begin{document}Hello\\end{document}","schema":{"type":"string"}}}},"responses":{"202":{"description":"Job accepted (or served from cache, in which case it is already finished).","headers":{"Location":{"schema":{"type":"string"},"required":true}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/JobEnvelope"}}}},"400":{"description":"Invalid project or request","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Missing or invalid API key","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"413":{"description":"Payload too large","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Rate limited","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/v1/auth/device":{"post":{"tags":["Account"],"summary":"Start a CLI sign-in (device flow)","description":"Returns a `userCode` to show in the terminal and a `deviceCode` to poll with. The user approves at `verificationUriComplete` while signed in.","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"clientName":{"type":"string","maxLength":60},"hostname":{"type":"string","maxLength":120},"platform":{"type":"string","maxLength":60}}}}}},"responses":{"200":{"description":"Started","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeviceAuthorizationStart"}}}},"429":{"description":"Too many sign-in attempts from this IP","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/v1/auth/device/token":{"post":{"tags":["Account"],"summary":"Exchange an approved device code for a token","description":"Poll every `interval` seconds. While pending the response is 428 with code `authorization_pending` (or `slow_down`). Denied → 400 `access_denied`; expired or reused → 400 `expired_token`.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"deviceCode":{"type":"string","minLength":20,"maxLength":200}},"required":["deviceCode"]}}}},"responses":{"200":{"description":"Approved","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeviceToken"}}}},"400":{"description":"access_denied or expired_token","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"428":{"description":"authorization_pending or slow_down","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/v1/auth/device/{code}":{"get":{"tags":["Account"],"summary":"Inspect a pending CLI sign-in (browser session only)","security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string","minLength":8,"maxLength":12,"example":"WDJB-MJHT"},"required":true,"name":"code","in":"path"}],"responses":{"200":{"description":"Device request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeviceAuthorization"}}}},"403":{"description":"Requires a browser session","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Unknown code","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/v1/auth/device/{code}/approve":{"post":{"tags":["Account"],"summary":"Approve a CLI sign-in (browser session only)","security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string","minLength":8,"maxLength":12,"example":"WDJB-MJHT"},"required":true,"name":"code","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"tokenName":{"type":"string","maxLength":80},"expiresInDays":{"type":["integer","null"],"minimum":1,"maximum":3650}}}}}},"responses":{"200":{"description":"Approved","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeviceAuthorization"}}}},"403":{"description":"Requires a browser session","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"Already handled","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/v1/auth/device/{code}/deny":{"post":{"tags":["Account"],"summary":"Deny a CLI sign-in (browser session only)","security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string","minLength":8,"maxLength":12,"example":"WDJB-MJHT"},"required":true,"name":"code","in":"path"}],"responses":{"200":{"description":"Denied","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeviceAuthorization"}}}},"403":{"description":"Requires a browser session","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/v1/compile":{"post":{"tags":["Compile"],"summary":"Compile a project synchronously","description":"Compiles and waits for the result (up to the synchronous timeout). Send JSON, multipart files, a zip or a raw .tex body. Returns the PDF by default; send `Accept: application/json` to get the job envelope with diagnostics instead. Query parameters `engine`, `entrypoint`, `timeoutMs`, `bibliography` and `force` apply to zip and raw bodies.","security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string"},"required":false,"name":"engine","in":"query"},{"schema":{"type":"string"},"required":false,"name":"entrypoint","in":"query"},{"schema":{"type":"string"},"required":false,"name":"timeoutMs","in":"query"},{"schema":{"type":"string"},"required":false,"name":"bibliography","in":"query"},{"schema":{"type":"string"},"required":false,"name":"force","in":"query"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CompileRequest"}},"multipart/form-data":{"schema":{"type":"object","properties":{"files":{"type":"array","items":{"type":"string","format":"binary"},"description":"One part per file; the filename may contain a relative path."},"project":{"type":"string","format":"binary","description":"A zip archive with the whole project."},"entrypoint":{"type":"string"},"engine":{"type":"string","enum":["pdflatex","xelatex","lualatex"]},"options":{"type":"string","description":"JSON-encoded CompileOptions."}}}},"application/zip":{"schema":{"type":"string","format":"binary"}},"text/x-tex":{"example":"\\documentclass{article}\\begin{document}Hello\\end{document}","schema":{"type":"string"}}}},"responses":{"200":{"description":"The compiled PDF, or the job envelope when JSON is requested.","headers":{"X-Job-Id":{"schema":{"type":"string"},"required":true},"X-Compile-Cached":{"schema":{"type":"string"},"required":true},"X-Compile-Warnings":{"schema":{"type":"string"},"required":true}},"content":{"application/pdf":{"schema":{"type":"string","format":"binary"}},"application/json":{"schema":{"$ref":"#/components/schemas/JobEnvelope"}}}},"400":{"description":"Invalid project or request","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Missing or invalid API key","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"408":{"description":"Compilation exceeded the timeout","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"413":{"description":"Payload too large","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"422":{"description":"LaTeX reported errors. The problem includes structured diagnostics and a link to the full log.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/CompileFailedProblem"}}}},"429":{"description":"Rate limited","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/v1/jobs/{id}":{"get":{"tags":["Jobs"],"summary":"Get a job","security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string","format":"uuid","example":"7f1c7f9e-3b1e-4d2a-9a1a-2f0c1b7e5d11"},"required":true,"name":"id","in":"path"}],"responses":{"200":{"description":"The job","content":{"application/json":{"schema":{"$ref":"#/components/schemas/JobEnvelope"}}}},"404":{"description":"Unknown job","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}},"delete":{"tags":["Jobs"],"summary":"Cancel a queued or running job","security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string","format":"uuid","example":"7f1c7f9e-3b1e-4d2a-9a1a-2f0c1b7e5d11"},"required":true,"name":"id","in":"path"}],"responses":{"200":{"description":"The job after cancellation","content":{"application/json":{"schema":{"$ref":"#/components/schemas/JobEnvelope"}}}},"404":{"description":"Unknown job","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"Job already finished","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/v1/jobs/{id}/pdf":{"get":{"tags":["Jobs"],"summary":"Download the PDF of a job","security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string","format":"uuid","example":"7f1c7f9e-3b1e-4d2a-9a1a-2f0c1b7e5d11"},"required":true,"name":"id","in":"path"},{"schema":{"type":"string"},"required":false,"name":"download","in":"query"}],"responses":{"200":{"description":"PDF","content":{"application/pdf":{"schema":{"type":"string","format":"binary"}}}},"404":{"description":"No PDF for this job","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/v1/jobs/{id}/log":{"get":{"tags":["Jobs"],"summary":"Download the full LaTeX log of a job","security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string","format":"uuid","example":"7f1c7f9e-3b1e-4d2a-9a1a-2f0c1b7e5d11"},"required":true,"name":"id","in":"path"}],"responses":{"200":{"description":"Log","content":{"text/plain":{"schema":{"type":"string"}}}},"404":{"description":"No log for this job","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/v1/jobs/{id}/events":{"get":{"tags":["Jobs"],"summary":"Stream job events (Server-Sent Events)","description":"Emits `queued`, `running`, `log` (compiler output chunks), and finally `done` or `error`. The stream closes after the terminal event. Reconnecting clients receive the recent history first.","security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string","format":"uuid","example":"7f1c7f9e-3b1e-4d2a-9a1a-2f0c1b7e5d11"},"required":true,"name":"id","in":"path"}],"responses":{"200":{"description":"SSE stream","content":{"text/event-stream":{"schema":{"type":"string"}}}},"404":{"description":"Unknown job","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/v1/templates":{"get":{"tags":["Templates"],"summary":"List templates","responses":{"200":{"description":"Template catalog","content":{"application/json":{"schema":{"type":"object","properties":{"templates":{"type":"array","items":{"$ref":"#/components/schemas/Template"}}},"required":["templates"]}}}}}}},"/v1/templates/{id}":{"get":{"tags":["Templates"],"summary":"Get a template and its file list","parameters":[{"schema":{"type":"string","pattern":"^[a-z0-9][a-z0-9-]{1,63}$","example":"ieee-conference"},"required":true,"name":"id","in":"path"}],"responses":{"200":{"description":"Template","content":{"application/json":{"schema":{"type":"object","properties":{"template":{"$ref":"#/components/schemas/Template"}},"required":["template"]}}}},"404":{"description":"Unknown template","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/v1/templates/{id}/files/{path}":{"get":{"tags":["Templates"],"summary":"Read one template file","parameters":[{"schema":{"type":"string","pattern":"^[a-z0-9][a-z0-9-]{1,63}$","example":"ieee-conference"},"required":true,"name":"id","in":"path"},{"schema":{"type":"string","example":"main.tex","description":"URL-encoded relative path."},"required":true,"description":"URL-encoded relative path.","name":"path","in":"path"}],"responses":{"200":{"description":"File content","content":{"application/octet-stream":{"schema":{"type":"string","format":"binary"}}}},"404":{"description":"Unknown template or file","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/v1/templates/{id}/archive":{"get":{"tags":["Templates"],"summary":"Download the template as a zip","parameters":[{"schema":{"type":"string","pattern":"^[a-z0-9][a-z0-9-]{1,63}$","example":"ieee-conference"},"required":true,"name":"id","in":"path"}],"responses":{"200":{"description":"Zip archive","content":{"application/zip":{"schema":{"type":"string","format":"binary"}}}},"404":{"description":"Unknown template","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/v1/templates/{id}/preview":{"get":{"tags":["Templates"],"summary":"Rendered PDF of the untouched template","description":"Compiles the template on first request and serves the cached PDF afterwards.","parameters":[{"schema":{"type":"string","pattern":"^[a-z0-9][a-z0-9-]{1,63}$","example":"ieee-conference"},"required":true,"name":"id","in":"path"}],"responses":{"200":{"description":"PDF","content":{"application/pdf":{"schema":{"type":"string","format":"binary"}}}},"404":{"description":"Unknown template","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"422":{"description":"The template failed to compile","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/v1/templates/{id}/compile":{"post":{"tags":["Templates"],"summary":"Compile a template with your changes (synchronous)","description":"Files you send replace the template files with the same path or are added to the project. Multipart and zip bodies work like `/v1/compile`.","security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string","pattern":"^[a-z0-9][a-z0-9-]{1,63}$","example":"ieee-conference"},"required":true,"name":"id","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TemplateCompileRequest"}},"multipart/form-data":{"schema":{"type":"object","properties":{"files":{"type":"array","items":{"type":"string","format":"binary"}}}}}}},"responses":{"200":{"description":"PDF or job envelope","content":{"application/pdf":{"schema":{"type":"string","format":"binary"}},"application/json":{"schema":{"$ref":"#/components/schemas/JobEnvelope"}}}},"404":{"description":"Unknown template","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"422":{"description":"LaTeX reported errors","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/v1/templates/{id}/jobs":{"post":{"tags":["Templates"],"summary":"Compile a template with your changes (asynchronous)","security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string","pattern":"^[a-z0-9][a-z0-9-]{1,63}$","example":"ieee-conference"},"required":true,"name":"id","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TemplateCompileRequest"}},"multipart/form-data":{"schema":{"type":"object","properties":{"files":{"type":"array","items":{"type":"string","format":"binary"}}}}}}},"responses":{"202":{"description":"Job accepted","content":{"application/json":{"schema":{"$ref":"#/components/schemas/JobEnvelope"}}}},"404":{"description":"Unknown template","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}}},"webhooks":{}}