TL;DR

  • → Issue personalized PDF certificates for any number of recipients from a single HTML template
  • → Generates concurrently — 1,000 certificates in under a minute
  • → 2 tokens per certificate (~$0.03). Tokens never expire

HTML to PDF Certificate Generator

Issuing certificates one-by-one in Canva or Word is a manual nightmare at scale. Whether you're running an online course, a hackathon, or a compliance training program, AgentGen lets you go from a recipient spreadsheet to a folder of personalized PDF certificates in minutes.

The certificate HTML template

Design your certificate once as HTML with inline styles. A landscape A4 page works well for most certificates:

def build_certificate_html(
    recipient_name: str,
    course_name: str,
    completion_date: str,
    issuer_name: str = "AgentGen Academy",
) -> str:
    return f"""<!DOCTYPE html>
    <html><head><meta charset="UTF-8">
    <link href="https://fonts.googleapis.com/css2?family=Playfair+Display:wght@400;700&family=Inter:wght@400;600&display=swap" rel="stylesheet">
    </head>
    <body style="margin:0;padding:0;background:white;
                 font-family:'Inter',sans-serif;
                 width:297mm;height:210mm;box-sizing:border-box">

      <!-- Outer border frame -->
      <div style="margin:12mm;height:calc(210mm - 24mm);box-sizing:border-box;
                  border:3px solid #c7b562;padding:10mm;
                  display:flex;flex-direction:column;
                  align-items:center;justify-content:center;text-align:center">

        <!-- Header -->
        <p style="font-size:13px;letter-spacing:.15em;text-transform:uppercase;
                  color:#9ca3af;margin:0 0 16px">{issuer_name}</p>

        <p style="font-size:14px;color:#6b7280;margin:0 0 10px">
          This certificate is proudly presented to
        </p>

        <!-- Recipient name -->
        <h1 style="font-family:'Playfair Display',serif;font-size:48px;
                   font-weight:700;color:#111;margin:0 0 16px;
                   border-bottom:2px solid #c7b562;padding-bottom:12px;
                   min-width:400px">{recipient_name}</h1>

        <p style="font-size:15px;color:#6b7280;margin:0 0 8px">
          for successfully completing
        </p>

        <h2 style="font-family:'Playfair Display',serif;font-size:28px;
                   font-weight:700;color:#1e1b4b;margin:0 0 28px">{course_name}</h2>

        <!-- Seal area -->
        <div style="width:72px;height:72px;border-radius:50%;
                    background:linear-gradient(135deg,#1e1b4b,#4f46e5);
                    display:flex;align-items:center;justify-content:center;
                    margin-bottom:24px">
          <span style="color:white;font-size:28px">✓</span>
        </div>

        <p style="font-size:13px;color:#9ca3af;margin:0">
          Issued on {completion_date}
        </p>
      </div>
    </body></html>"""

Generate a single certificate

import os, requests

def issue_certificate(recipient: str, course: str, date: str) -> str:
    """Generate a PDF certificate and return a CDN download URL."""
    html = build_certificate_html(recipient, course, date)
    r = requests.post(
        "https://www.agent-gen.com/api/v1/generate/pdf",
        headers={
            "X-API-Key": os.environ["AGENTGEN_API_KEY"],
            "Content-Type": "application/json",
        },
        json={
            "html": html,
            "format": "A4",
            "landscape": True,
            "margin": {"top": "0", "bottom": "0", "left": "0", "right": "0"},
        },
        timeout=30,
    )
    r.raise_for_status()
    return r.json()["url"]

url = issue_certificate("Sarah Chen", "Python for AI Engineers", "March 2, 2026")
print(url)  # https://cdn.agent-gen.com/output/abc123.pdf

Bulk generation — entire cohort at once

import asyncio, aiohttp, os

async def issue_cert_async(
    session: aiohttp.ClientSession,
    recipient: dict,
) -> tuple[str, str]:
    html = build_certificate_html(
        recipient["name"], recipient["course"], recipient["date"]
    )
    async with session.post(
        "https://www.agent-gen.com/api/v1/generate/pdf",
        headers={"X-API-Key": os.environ["AGENTGEN_API_KEY"]},
        json={"html": html, "format": "A4", "landscape": True,
              "margin": {"top": "0", "bottom": "0", "left": "0", "right": "0"}},
    ) as resp:
        data = await resp.json()
        return recipient["email"], data["url"]

async def issue_all_certificates(recipients: list[dict]) -> dict[str, str]:
    async with aiohttp.ClientSession() as session:
        results = await asyncio.gather(
            *(issue_cert_async(session, r) for r in recipients)
        )
    return dict(results)  # {email: pdf_url}

# Issue 1,000 certificates concurrently
cert_urls = asyncio.run(issue_all_certificates(course_graduates))
# → {"[email protected]": "https://cdn...", "[email protected]": "https://cdn...", ...}

Send via email

# After generating all certificates, email each recipient
for email, pdf_url in cert_urls.items():
    send_email(
        to=email,
        subject="Your certificate is ready!",
        body=f"Congratulations! Download your certificate: {pdf_url}",
    )

Pricing

Each certificate is one page = 2 tokens. At Growth tier ($39 for 2,500 tokens) that's 1,250 certificates for $39 — 3 cents each. A cohort of 200 graduates costs $6.

Start issuing certificates today

50 free tokens on signup — issue your first 25 certificates at no cost.