Generate PDF Reports from LangChain Agents with DocAPI
LangChain agents are good at research, reasoning, and writing. But when it comes to producing a polished PDF as the final output, most developers hit a wall.
Self-hosting Puppeteer means 150MB binaries, Lambda layer hell, and cold starts that tank your latency. Other PDF libraries aren't built for agents — they require human dashboards, email verification, or browser flows.
DocAPI is different. One POST request from an agent returns a PDF. No setup, no infra, no human in the loop.
Install
pip install langchain langchain-anthropic requestsGet a free API key at docapi.co/signup — 100 free calls, no credit card required.
For agents that should manage their own credentials:
import requests
# Agent self-registers programmatically
reg = requests.post('https://api.docapi.co/api/register').json()
api_key = reg['api_key']
print(f"Registered. Credits: {reg['credits']}")Create the LangChain Tool
from langchain.tools import tool
import requests
import os
@tool
def generate_pdf(html: str) -> str:
"""
Convert an HTML string to a PDF file.
Returns the file path on success. Use this to produce
professional PDF reports from structured HTML content.
"""
api_key = os.environ.get("DOCAPI_KEY")
response = requests.post(
"https://api.docapi.co/v1/pdf",
headers={
"x-api-key": api_key,
"Content-Type": "application/json",
},
json={"html": html},
)
if not response.ok:
return f"Error: HTTP {response.status_code} — {response.text[:200]}"
# Save locally
filepath = "/tmp/report.pdf"
with open(filepath, "wb") as f:
f.write(response.content)
credits = response.headers.get("X-Credits-Remaining", "unknown")
return f"PDF saved to {filepath}. Size: {len(response.content)} bytes. Credits remaining: {credits}"The X-Credits-Remaining header lets the agent track its own balance. Pair this with a top_up_credits tool that sends USDC to the agent's address and you have fully autonomous PDF generation — no human ever needs to touch a billing dashboard.
Build the Agent
from langchain_anthropic import ChatAnthropic
from langchain.agents import AgentExecutor, create_tool_calling_agent
from langchain_core.prompts import ChatPromptTemplate
llm = ChatAnthropic(model="claude-3-5-sonnet-20241022")
prompt = ChatPromptTemplate.from_messages([
("system", (
"You are a report generator. When asked to create a report, "
"write complete HTML with inline CSS, then call generate_pdf. "
"Make reports visually polished — use tables, headers, and color."
)),
("human", "{input}"),
("placeholder", "{agent_scratchpad}"),
])
agent = create_tool_calling_agent(llm, [generate_pdf], prompt)
executor = AgentExecutor(agent=agent, tools=[generate_pdf], verbose=True)
result = executor.invoke({
"input": (
"Generate a Q1 2026 real estate market summary for ZIP code 90210. "
"Include median price, days on market, and market temperature. "
"Export as a professional PDF report."
)
})
print(result["output"])What the Agent Produces
The agent will:
- Write structured HTML with a header, data table, and summary section
- Apply inline styles (safe for PDF rendering)
- Call
generate_pdfwith the HTML - Return the file path and credit balance
The HTML that works best for PDF includes inline styles rather than external stylesheets, since DocAPI renders with headless Chrome — the same engine as your browser.
Example HTML the Agent Generates
<!DOCTYPE html>
<html>
<head><meta charset="UTF-8"></head>
<body style="font-family: Arial, sans-serif; max-width: 800px; margin: 40px auto; color: #333;">
<h1 style="color: #1a1a2e; border-bottom: 3px solid #4a90e2; padding-bottom: 12px;">
Q1 2026 Market Report — Beverly Hills (90210)
</h1>
<table style="width: 100%; border-collapse: collapse; margin: 24px 0;">
<tr style="background: #f5f5f5;">
<th style="padding: 12px; text-align: left; border: 1px solid #ddd;">Metric</th>
<th style="padding: 12px; text-align: right; border: 1px solid #ddd;">Value</th>
</tr>
<tr>
<td style="padding: 12px; border: 1px solid #ddd;">Median Sale Price</td>
<td style="padding: 12px; text-align: right; border: 1px solid #ddd;">$4,250,000</td>
</tr>
<tr style="background: #f9f9f9;">
<td style="padding: 12px; border: 1px solid #ddd;">Days on Market</td>
<td style="padding: 12px; text-align: right; border: 1px solid #ddd;">18</td>
</tr>
</table>
</body>
</html>Full Chrome CSS support means Flexbox, Grid, web fonts, and printBackground all work exactly as they do in the browser.
Using the MCP Server
If you're in Claude Desktop or Cursor, skip the Python and add the MCP server:
{
"mcpServers": {
"docapi": {
"url": "https://mcp.docapi.co/mcp"
}
}
}Claude can then call docapi_generate_pdf directly in any conversation.