← All posts
·10 min read

How to Build an Invoicing Agent with GPT-4o and AgentGen

Last Updated: March 2026

TL;DR

  • GPT-4o collects invoice details in conversation using function calling
  • AgentGen renders the HTML template to a polished PDF via headless Chrome
  • The user gets a CDN download link in the same conversation turn — 2 tokens (~$0.03)

What we're building

A conversational invoicing agent. The user says something like: "Invoice Acme Corp, $5,000 for consulting, due April 15" — and the agent asks any missing questions, then produces a professional PDF invoice and returns the download link.

Setup

pip install openai requests python-dotenv

You need an OpenAI API key and an AgentGen API key. Get your AgentGen key free — new accounts get 50 tokens.

Step 1 — The invoice HTML template

def build_invoice_html(data: dict) -> str:
    rows = "".join(
        f"""<tr>
          <td style="padding:8px 0;border-bottom:1px solid #f3f4f6;color:#374151">
            {item["desc"]}
          </td>
          <td style="padding:8px 0;text-align:right;border-bottom:1px solid #f3f4f6">
            {item["qty"]}
          </td>
          <td style="padding:8px 0;text-align:right;font-weight:600;border-bottom:1px solid #f3f4f6">
            ${item["qty"] * item["unit_price"]:.2f}
          </td>
        </tr>"""
        for item in data["line_items"]
    )
    subtotal = sum(i["qty"] * i["unit_price"] for i in data["line_items"])
    return f"""<!DOCTYPE html>
    <html><head><meta charset="UTF-8"></head>
    <body style="font-family:'Helvetica Neue',sans-serif;padding:48px;color:#111;max-width:680px">
      <div style="display:flex;justify-content:space-between;align-items:start;margin-bottom:40px">
        <div>
          <h1 style="margin:0 0 4px;font-size:28px;font-weight:800">INVOICE</h1>
          <p style="margin:0;color:#6b7280">#{data["number"]}</p>
        </div>
        <div style="text-align:right">
          <p style="margin:0;font-weight:600">{data["issuer"]}</p>
          <p style="margin:0;color:#6b7280;font-size:14px">{data["date"]}</p>
        </div>
      </div>
      <p style="color:#6b7280;font-size:13px;margin-bottom:4px">Bill to</p>
      <p style="font-size:18px;font-weight:700;margin:0 0 32px">{data["client"]}</p>
      <table style="width:100%;border-collapse:collapse;margin-bottom:24px">
        <thead>
          <tr style="border-bottom:2px solid #e5e7eb">
            <th style="text-align:left;padding-bottom:8px;font-size:12px;color:#9ca3af;text-transform:uppercase">Description</th>
            <th style="text-align:right;padding-bottom:8px;font-size:12px;color:#9ca3af;text-transform:uppercase">Qty</th>
            <th style="text-align:right;padding-bottom:8px;font-size:12px;color:#9ca3af;text-transform:uppercase">Amount</th>
          </tr>
        </thead>
        <tbody>{rows}</tbody>
      </table>
      <div style="display:flex;justify-content:flex-end">
        <div style="min-width:200px">
          <div style="display:flex;justify-content:space-between;padding:6px 0;color:#6b7280;font-size:14px">
            <span>Subtotal</span><span>${subtotal:.2f}</span>
          </div>
          <div style="display:flex;justify-content:space-between;padding:12px 0 0;font-size:20px;font-weight:800;color:#4f46e5;border-top:2px solid #e5e7eb;margin-top:6px">
            <span>Total</span><span>${subtotal:.2f}</span>
          </div>
        </div>
      </div>
      <p style="margin-top:40px;color:#9ca3af;font-size:12px">
        Payment due: {data["due_date"]} · Thank you for your business.
      </p>
    </body></html>"""

Step 2 — The AgentGen tool function

import os, json, requests

def create_invoice(
    client: str,
    number: str,
    date: str,
    due_date: str,
    issuer: str,
    line_items: list[dict],
) -> dict:
    """Render an invoice PDF and return a download URL. Cost: 2 tokens."""
    html = build_invoice_html({
        "client": client, "number": number,
        "date": date, "due_date": due_date,
        "issuer": issuer, "line_items": line_items,
    })
    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"},
        timeout=30,
    )
    r.raise_for_status()
    return {"pdf_url": r.json()["url"]}

Step 3 — Define the OpenAI tool schema

tools = [{
    "type": "function",
    "function": {
        "name": "create_invoice",
        "description": (
            "Generate a professional PDF invoice and return a download URL. "
            "Call this once you have all required invoice details."
        ),
        "parameters": {
            "type": "object",
            "properties": {
                "client": {"type": "string", "description": "Client or company name"},
                "number": {"type": "string", "description": "Invoice number, e.g. INV-001"},
                "date": {"type": "string", "description": "Invoice date, e.g. March 2, 2026"},
                "due_date": {"type": "string", "description": "Payment due date"},
                "issuer": {"type": "string", "description": "Your name or company name"},
                "line_items": {
                    "type": "array",
                    "items": {
                        "type": "object",
                        "properties": {
                            "desc": {"type": "string"},
                            "qty": {"type": "number"},
                            "unit_price": {"type": "number"},
                        },
                        "required": ["desc", "qty", "unit_price"],
                    },
                },
            },
            "required": ["client", "number", "date", "due_date", "issuer", "line_items"],
        },
    },
}]

Step 4 — The agent loop

from openai import OpenAI

client = OpenAI()

def run_invoicing_agent(user_message: str) -> str:
    messages = [
        {
            "role": "system",
            "content": (
                "You are an invoicing assistant. Collect all required invoice details from "
                "the user (client name, services, amounts, due date, your name/company), "
                "then call create_invoice to generate the PDF. "
                "If any details are missing, ask for them before generating."
            ),
        },
        {"role": "user", "content": user_message},
    ]

    while True:
        response = client.chat.completions.create(
            model="gpt-4o",
            messages=messages,
            tools=tools,
            tool_choice="auto",
        )
        msg = response.choices[0].message

        if msg.tool_calls:
            messages.append(msg)
            for call in msg.tool_calls:
                args = json.loads(call.function.arguments)
                result = create_invoice(**args)
                messages.append({
                    "role": "tool",
                    "tool_call_id": call.id,
                    "content": json.dumps(result),
                })
        else:
            return msg.content

# Run it
print(run_invoicing_agent(
    "Invoice Acme Corp $5,000 for API consulting, due April 15. My name is Yair Levi."
))
# → "Here's your invoice: https://cdn.agent-gen.com/output/abc123.pdf
#    Invoice #INV-001 · Acme Corp · Due April 15, 2026 · $5,000.00"

Cost

Each invoice costs 2 tokens (~$0.03 at Growth tier). The GPT-4o API call is a few cents on top. Total round-trip is under 3 seconds.

Get started free → — 50 tokens on signup, enough for 25 invoices to test your workflow.

Ready to start generating?

Create a free account and generate your first PDF or image in minutes.

Get started free