·8 min read
Building an Invoice Generator with an AI Agent
Imagine telling your AI assistant: "Generate an invoice for Acme Corp, $5,000 for consulting, due March 15." — and getting back a professional PDF download link. That's what we're building in this tutorial.
Architecture
The system has three parts:
- A conversational LLM that collects invoice details
- A
create_invoicetool that templates and renders the PDF - AgentGen API to perform the actual HTML → PDF conversion
Defining the tool schema
const tools = [{
name: 'create_invoice',
description: 'Generate a professional PDF invoice and return a download URL.',
input_schema: {
type: 'object',
properties: {
client_name: { type: 'string', description: 'Client or company name' },
invoice_number: { type: 'string' },
due_date: { type: 'string', description: 'ISO date YYYY-MM-DD' },
line_items: {
type: 'array',
items: {
type: 'object',
properties: {
description: { type: 'string' },
quantity: { type: 'number' },
unit_price: { type: 'number' },
},
},
},
currency: { type: 'string', default: 'USD' },
},
required: ['client_name', 'invoice_number', 'due_date', 'line_items'],
},
}]
Implementing the tool handler
async function handleToolCall(toolName, input) {
if (toolName !== 'create_invoice') return null
const total = input.line_items.reduce(
(sum, item) => sum + item.quantity * item.unit_price, 0
)
const html = buildInvoiceHtml({ ...input, total })
const res = await fetch('https://www.agent-gen.com/api/v1/generate/pdf', {
method: 'POST',
headers: {
'X-API-Key': process.env.AGENTGEN_API_KEY,
'Content-Type': 'application/json',
},
body: JSON.stringify({
html,
format: 'A4',
margin: { top: '15mm', bottom: '15mm', left: '15mm', right: '15mm' },
}),
})
const { url } = await res.json()
return { pdf_url: url, total }
}
Running the agent loop
async function runInvoiceAgent(userMessage) {
const messages = [{ role: 'user', content: userMessage }]
while (true) {
const response = await anthropic.messages.create({
model: 'claude-opus-4-6',
max_tokens: 1024,
tools,
messages,
})
if (response.stop_reason === 'tool_use') {
const toolUse = response.content.find(b => b.type === 'tool_use')
const result = await handleToolCall(toolUse.name, toolUse.input)
messages.push(
{ role: 'assistant', content: response.content },
{ role: 'user', content: [{ type: 'tool_result', tool_use_id: toolUse.id, content: JSON.stringify(result) }] }
)
} else {
return response.content[0].text
}
}
}
Result
Running runInvoiceAgent("Invoice Acme Corp $5000 consulting due March 15") produces:
I've generated your invoice. Download PDF
Invoice #001 · Acme Corp · Due March 15, 2026 · Total: $5,000.00
The whole round-trip takes under 3 seconds and costs 2 tokens (~$0.03 at Growth tier).
Get started — you can have this running in an afternoon.
Ready to start generating?
Create a free account and generate your first PDF or image in minutes.
Get started free