FormaTex Python SDK
Official Python client for the FormaTex LaTeX-to-PDF API.
Installation
pip install FormaTex
Requires Python ≥ 3.9.
Quick Start
from FormaTex import FormaTexClient
with FormaTexClient("fx_your_api_key") as client:
result = client.compile(
r"\documentclass{article}\begin{document}Hello, world!\end{document}"
)
# result.pdf → bytes
# result.engine → "pdflatex"
# result.duration_ms → 412
with open("output.pdf", "wb") as f:
f.write(result.pdf)
Compilation
Sync (immediate response)
# Choose your engine
result = client.compile(latex, engine="pdflatex") # default
result = client.compile(latex, engine="xelatex") # Unicode + modern fonts
result = client.compile(latex, engine="lualatex") # Lua scripting
result = client.compile(latex, engine="latexmk") # automatic multi-pass
# Smart compile: auto-detects the right engine + attempts auto-fix
result = client.compile_smart(latex)
# Compile directly to a file
client.compile_to_file(latex, "output.pdf")
client.compile_to_file(latex, "output.pdf", engine="xelatex")
client.compile_to_file(latex, "output.pdf", smart=True)
Async (long-running documents)
from FormaTex import FormaTexClient
with FormaTexClient("fx_your_api_key") as client:
# Submit and get a job ID immediately
job = client.async_compile(latex, engine="pdflatex")
print(job.job_id, job.status) # "abc-123", "pending"
# Option 1: blocking wait (polls automatically)
result = client.wait_for_job(job.job_id)
with open("output.pdf", "wb") as f:
f.write(result.pdf)
# Option 2: manual polling loop
import time
while True:
status = client.get_job(job.job_id)
if status.status == "completed":
pdf = client.get_job_pdf(job.job_id) # one-time download
break
elif status.status == "failed":
print("Failed:", status.error)
break
time.sleep(2)
# Retrieve just the log
log = client.get_job_log(job.job_id)
# Clean up server-side (optional, PDF auto-deletes after download)
client.delete_job(job.job_id)
Multi-File Projects
Use file_entry to attach companion files (images, .bib, .cls, etc.):
from pathlib import Path
from FormaTex import FormaTexClient, file_entry
latex = r"""
\documentclass{article}
\usepackage{graphicx}
\begin{document}
\includegraphics[width=\linewidth]{logo.png}
\bibliography{refs}
\end{document}
"""
with FormaTexClient("fx_your_api_key") as client:
result = client.compile(
latex,
engine="pdflatex",
files=[
file_entry("logo.png", Path("assets/logo.png")), # auto-read from disk
file_entry("refs.bib", Path("references.bib")),
],
)
Path("output.pdf").write_bytes(result.pdf)
file_entry(name, content) accepts:
Path— reads the file automaticallybytes— raw binary data, base64-encoded for youstr— already base64-encoded content passed through as-is
Lint (Static Analysis)
Run chktex without consuming compilation quota:
from FormaTex import FormaTexClient
latex = r"""
\documentclass{article}
\begin{document}
Hello world.
\end{document}
"""
with FormaTexClient("fx_your_api_key") as client:
result = client.lint(latex)
print(f"Valid: {result.valid}")
print(f"Errors: {result.error_count}, Warnings: {result.warning_count}")
for d in result.diagnostics:
print(f" Line {d.line}:{d.column} [{d.severity}] {d.message}")
Integrate into CI:
result = client.lint(source)
if not result.valid:
raise SystemExit(f"LaTeX lint failed: {result.error_count} error(s)")
Convert to Word (DOCX)
with FormaTexClient("fx_your_api_key") as client:
result = client.convert(latex)
Path("document.docx").write_bytes(result.docx)
# Or write directly to a file
client.convert_to_file(latex, "document.docx")
Syntax Check
Free endpoint — does not count against your quota:
check = client.check_syntax(latex)
print(check.valid, check.errors)
Usage Stats & Engines
usage = client.get_usage()
print(f"{usage.compilations_used}/{usage.compilations_limit} compilations this month")
print(f"Overage: {usage.overage}")
engines = client.list_engines()
for e in engines:
print(e["name"], e["available"])
Error Handling
from FormaTex import (
FormaTexClient,
AuthenticationError,
CompilationError,
RateLimitError,
PlanLimitError,
)
with FormaTexClient("fx_your_api_key") as client:
try:
result = client.compile(latex)
except AuthenticationError:
print("Invalid API key")
except CompilationError as e:
print(f"Compilation failed: {e}")
print(f"Compiler log:\n{e.log}")
except RateLimitError as e:
print(f"Rate limited — retry after {e.retry_after}s")
except PlanLimitError:
print("Plan limit exceeded, upgrade at https://FormaTex.com/pricing")
Self-Hosted / Custom URL
client = FormaTexClient("fx_key", base_url="https://latex.your-company.com")
Type Reference
All types are importable directly from FormaTex:
| Type | Description |
|---|---|
CompileResult |
Sync compile result: pdf, engine, duration_ms, size_bytes, log, job_id |
AsyncJob |
Submitted async job: job_id, status |
JobResult |
Polled job state: job_id, status, log, duration_ms, error, success |
LintResult |
Lint output: diagnostics, duration_ms, error_count, warning_count, valid |
LintDiagnostic |
Single finding: line, column, severity, message, source, code |
SyntaxResult |
Syntax check: valid, errors |
ConvertResult |
DOCX output: docx (bytes), size_bytes |
UsageStats |
Quota: compilations_used, compilations_limit, overage, period_start, period_end |
Metadata
Release files for FormaTex 1.0.3
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| formatex-1.0.3.tar.gz | 16.4 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| formatex-1.0.3-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 27.0 kB
Release files / formatex-1.0.3.tar.gz
| Download URL | formatex-1.0.3.tar.gz |
|---|---|
| Size | 16.4 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
0ff0de8322172f4cc68c63b98c880a44575fa7aa228a0b67b92a052954e4dc06
|
|
BLAKE2b-256 checksum How to use checksums |
225bdb51b157f42f1b74a23a6c2ac99f02b7102f058b750447449d678ec7ff6d
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.7
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Feb 28, 2026.
Transparency logRelease files / formatex-1.0.3-py3-none-any.whl
| Download URL | formatex-1.0.3-py3-none-any.whl |
|---|---|
| Size | 10.6 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
b03fe5d08429c805ba94bbf77a2687efaf3edd0f350aaa7200c34b54f84a84f0
|
|
BLAKE2b-256 checksum How to use checksums |
300210ac51b3797254e6ab013594f56e8d44f316eee66f476bf911a3ed75a730
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.7
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Feb 28, 2026.
Transparency log