Texify

Resumes

Classic resume PDF API

A LaTeX resume API template for polished, ATS-friendly one-page resumes generated from JSON. Best for job boards, career tools, and profile export features. Send this LaTeX template and JSON data to Texify in one /render request.

Classic resume PDF preview

JSON to resume PDF, without browser print bugs.

Use this template when your product stores structured profile data and needs a polished resume export. JSON data plus this LaTeX template becomes a deterministic PDF through /render, with real text, readable spacing, and predictable page breaks.

It is built for developer platforms, portfolio builders, job marketplaces, and AI agents that assemble candidate data into a finished resume PDF.

JSON schema

Fields this template expects.

FieldTypeRequiredDescription
namestringYesCandidate full name.
headlinestringYesShort professional summary.
contactobjectYesEmail, phone, location, website, and profiles.
experiencearrayYesRoles with company, dates, bullets, and impact metrics.
skillsarrayYesGrouped technical or professional skills.

API examples

POST LaTeX and JSON. Receive PDF bytes.

curl
cat > resume-classic-payload.json <<'JSON'
{
  "entrypoint": "main.tex",
  "resources": {
    "main.tex": "\\documentclass[10pt]{article}\n\\usepackage[margin=0.65in]{geometry}\n\\usepackage{array}\n\\pagestyle{empty}\n\\begin{document}\n\\begin{center}\n{\\LARGE\\bfseries [[ .name ]]}\\\\\n[[ .headline ]]\\\\[3pt]\n[[ .contact.email ]] \\quad [[ with .contact.phone ]][[ . ]] \\quad[[ end ]] [[ with .contact.location ]][[ . ]] \\quad[[ end ]] [[ with .contact.website ]][[ . ]][[ end ]]\n[[ with .contact.github ]]\\\\[[ . ]][[ end ]][[ with .contact.linkedin ]] \\quad [[ . ]][[ end ]]\n\\end{center}\n\\section*{Experience}\n[[ range .experience ]]\\noindent\\textbf{[[ .role ]]} --- [[ .company ]]\\hfill [[ .dates ]]\\\\\n\\begin{itemize}\n[[ range .bullets ]]\\item [[ . ]]\n[[ end ]]\\end{itemize}\n[[ end ]]\n[[ with .projects ]]\\section*{Projects}\n[[ range . ]]\\noindent\\textbf{[[ .name ]]} --- [[ .description ]]\\\\\n\\textit{[[ range .stack ]][[ . ]] [[ end ]]}\\\\[4pt]\n[[ end ]][[ end ]]\n\\section*{Skills}\n[[ range .skills ]]\\noindent\\textbf{[[ .group ]]}: [[ range .items ]][[ . ]] [[ end ]]\\\\\n[[ end ]]\\end{document}"
  },
  "data": {
    "name": "Taylor Brooks",
    "headline": "Product-minded backend engineer",
    "contact": {
      "email": "taylor@example.com",
      "phone": "",
      "location": "Toronto",
      "website": "taylor.dev",
      "github": "",
      "linkedin": ""
    },
    "experience": [
      {
        "company": "LedgerOps",
        "role": "Senior Software Engineer",
        "dates": "2023-2026",
        "bullets": [
          "Cut invoice rendering latency by 48%",
          "Led migration to typed document templates"
        ]
      }
    ],
    "projects": null,
    "skills": [
      {
        "group": "Backend",
        "items": [
          "TypeScript",
          "Postgres",
          "Queues"
        ]
      }
    ]
  }
}
JSON

curl -sS -X POST https://api.texify.dev/render \
  -H "Content-Type: application/json" \
  --data @resume-classic-payload.json \
  --output resume-classic.pdf
Python
import json
import requests

payload = json.loads(r'''{
  "entrypoint": "main.tex",
  "resources": {
    "main.tex": "\\documentclass[10pt]{article}\n\\usepackage[margin=0.65in]{geometry}\n\\usepackage{array}\n\\pagestyle{empty}\n\\begin{document}\n\\begin{center}\n{\\LARGE\\bfseries [[ .name ]]}\\\\\n[[ .headline ]]\\\\[3pt]\n[[ .contact.email ]] \\quad [[ with .contact.phone ]][[ . ]] \\quad[[ end ]] [[ with .contact.location ]][[ . ]] \\quad[[ end ]] [[ with .contact.website ]][[ . ]][[ end ]]\n[[ with .contact.github ]]\\\\[[ . ]][[ end ]][[ with .contact.linkedin ]] \\quad [[ . ]][[ end ]]\n\\end{center}\n\\section*{Experience}\n[[ range .experience ]]\\noindent\\textbf{[[ .role ]]} --- [[ .company ]]\\hfill [[ .dates ]]\\\\\n\\begin{itemize}\n[[ range .bullets ]]\\item [[ . ]]\n[[ end ]]\\end{itemize}\n[[ end ]]\n[[ with .projects ]]\\section*{Projects}\n[[ range . ]]\\noindent\\textbf{[[ .name ]]} --- [[ .description ]]\\\\\n\\textit{[[ range .stack ]][[ . ]] [[ end ]]}\\\\[4pt]\n[[ end ]][[ end ]]\n\\section*{Skills}\n[[ range .skills ]]\\noindent\\textbf{[[ .group ]]}: [[ range .items ]][[ . ]] [[ end ]]\\\\\n[[ end ]]\\end{document}"
  },
  "data": {
    "name": "Taylor Brooks",
    "headline": "Product-minded backend engineer",
    "contact": {
      "email": "taylor@example.com",
      "phone": "",
      "location": "Toronto",
      "website": "taylor.dev",
      "github": "",
      "linkedin": ""
    },
    "experience": [
      {
        "company": "LedgerOps",
        "role": "Senior Software Engineer",
        "dates": "2023-2026",
        "bullets": [
          "Cut invoice rendering latency by 48%",
          "Led migration to typed document templates"
        ]
      }
    ],
    "projects": null,
    "skills": [
      {
        "group": "Backend",
        "items": [
          "TypeScript",
          "Postgres",
          "Queues"
        ]
      }
    ]
  }
}''')
response = requests.post(
    "https://api.texify.dev/render",
    json=payload,
    timeout=90,
)
response.raise_for_status()

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

const payload = {
  "entrypoint": "main.tex",
  "resources": {
    "main.tex": "\\documentclass[10pt]{article}\n\\usepackage[margin=0.65in]{geometry}\n\\usepackage{array}\n\\pagestyle{empty}\n\\begin{document}\n\\begin{center}\n{\\LARGE\\bfseries [[ .name ]]}\\\\\n[[ .headline ]]\\\\[3pt]\n[[ .contact.email ]] \\quad [[ with .contact.phone ]][[ . ]] \\quad[[ end ]] [[ with .contact.location ]][[ . ]] \\quad[[ end ]] [[ with .contact.website ]][[ . ]][[ end ]]\n[[ with .contact.github ]]\\\\[[ . ]][[ end ]][[ with .contact.linkedin ]] \\quad [[ . ]][[ end ]]\n\\end{center}\n\\section*{Experience}\n[[ range .experience ]]\\noindent\\textbf{[[ .role ]]} --- [[ .company ]]\\hfill [[ .dates ]]\\\\\n\\begin{itemize}\n[[ range .bullets ]]\\item [[ . ]]\n[[ end ]]\\end{itemize}\n[[ end ]]\n[[ with .projects ]]\\section*{Projects}\n[[ range . ]]\\noindent\\textbf{[[ .name ]]} --- [[ .description ]]\\\\\n\\textit{[[ range .stack ]][[ . ]] [[ end ]]}\\\\[4pt]\n[[ end ]][[ end ]]\n\\section*{Skills}\n[[ range .skills ]]\\noindent\\textbf{[[ .group ]]}: [[ range .items ]][[ . ]] [[ end ]]\\\\\n[[ end ]]\\end{document}"
  },
  "data": {
    "name": "Taylor Brooks",
    "headline": "Product-minded backend engineer",
    "contact": {
      "email": "taylor@example.com",
      "phone": "",
      "location": "Toronto",
      "website": "taylor.dev",
      "github": "",
      "linkedin": ""
    },
    "experience": [
      {
        "company": "LedgerOps",
        "role": "Senior Software Engineer",
        "dates": "2023-2026",
        "bullets": [
          "Cut invoice rendering latency by 48%",
          "Led migration to typed document templates"
        ]
      }
    ],
    "projects": null,
    "skills": [
      {
        "group": "Backend",
        "items": [
          "TypeScript",
          "Postgres",
          "Queues"
        ]
      }
    ]
  }
};

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

if (!response.ok) throw new Error(await response.text());

const pdf = Buffer.from(await response.arrayBuffer());
await writeFile("resume-classic.pdf", pdf);

The template

LaTeX source sent as resources["main.tex"].

main.tex
\documentclass[10pt]{article}
\usepackage[margin=0.65in]{geometry}
\usepackage{array}
\pagestyle{empty}
\begin{document}
\begin{center}
{\LARGE\bfseries [[ .name ]]}\\
[[ .headline ]]\\[3pt]
[[ .contact.email ]] \quad [[ with .contact.phone ]][[ . ]] \quad[[ end ]] [[ with .contact.location ]][[ . ]] \quad[[ end ]] [[ with .contact.website ]][[ . ]][[ end ]]
[[ with .contact.github ]]\\[[ . ]][[ end ]][[ with .contact.linkedin ]] \quad [[ . ]][[ end ]]
\end{center}
\section*{Experience}
[[ range .experience ]]\noindent\textbf{[[ .role ]]} --- [[ .company ]]\hfill [[ .dates ]]\\
\begin{itemize}
[[ range .bullets ]]\item [[ . ]]
[[ end ]]\end{itemize}
[[ end ]]
[[ with .projects ]]\section*{Projects}
[[ range . ]]\noindent\textbf{[[ .name ]]} --- [[ .description ]]\\
\textit{[[ range .stack ]][[ . ]] [[ end ]]}\\[4pt]
[[ end ]][[ end ]]
\section*{Skills}
[[ range .skills ]]\noindent\textbf{[[ .group ]]}: [[ range .items ]][[ . ]] [[ end ]]\\
[[ end ]]\end{document}

Live render

Try sample data now.

Posts this LaTeX template and sample JSON to /render, then opens the returned PDF bytes.

Sample data
{
  "name": "Taylor Brooks",
  "headline": "Product-minded backend engineer",
  "contact": {
    "email": "taylor@example.com",
    "phone": "",
    "location": "Toronto",
    "website": "taylor.dev",
    "github": "",
    "linkedin": ""
  },
  "experience": [
    {
      "company": "LedgerOps",
      "role": "Senior Software Engineer",
      "dates": "2023-2026",
      "bullets": [
        "Cut invoice rendering latency by 48%",
        "Led migration to typed document templates"
      ]
    }
  ],
  "projects": null,
  "skills": [
    {
      "group": "Backend",
      "items": [
        "TypeScript",
        "Postgres",
        "Queues"
      ]
    }
  ]
}

FAQ

FAQ

Can I use Classic resume as a LaTeX resume API?

Yes. Copy the LaTeX template, send it in resources with your data to /render, and Texify returns PDF bytes.

Can I change colors, copy, or field names?

Yes. Edit the LaTeX source and JSON placeholders to match your data model and brand before posting to /render.

Does this render real PDF text?

Yes. Texify compiles LaTeX to PDF, so text remains selectable, searchable, and stable across environments.