Business

Work order PDF generator API

A service work order with job details, a task checklist, parts and labor costs, and sign-off lines.

Give technicians everything they need on one page. This work order includes the customer and site, priority and status, a job description, a task checklist, parts and labor with costs, the assigned technician and schedule, and lines for technician and customer sign-off.

Generate work orders when a job is booked, then regenerate the completed version with ticked tasks and final costs for the customer’s records.

Generate a Work Order PDF via the API

POST your data to /api/v1/generate and get a PDF back. Copy-paste an example, swap in your API key, and loop over a list to render thousands — one work order per record.

curl -X POST https://pdfgen.com/api/v1/generate \
-H "Authorization: Bearer pdfg_live_xxx" \
-H "Content-Type: application/json" \
-d '{
"data": {
"company": {
"name": "FixRight Facilities",
"phone": "(415) 555-0188",
"email": "service@fixright.co"
},
"workOrderNumber": "WO-2026-0871",
"date": "2026-10-27",
"priority": "High",
"status": "Scheduled",
"customer": {
"name": "Harbor Café",
"contact": "Lena Ortiz · (415) 555-0142",
"address": "45 Embarcadero Center\nSan Francisco, CA 94111"
},
"technician": "Marcus Lee",
"scheduledDate": "2026-10-28",
"timeWindow": "9:00 AM – 12:00 PM",
"description": "The walk-in refrigerator is not holding temperature (reads 46°F, target 36°F). Inspect the compressor and door seal, replace faulty parts, and confirm the unit holds temperature for two hours.",
"tasks": [
{
"description": "Inspect compressor and condenser coils",
"done": true
},
{
"description": "Replace worn door gasket",
"done": true
},
{
"description": "Recharge refrigerant to spec",
"done": false
},
{
"description": "Verify the unit holds 36°F for two hours",
"done": false
}
],
"currency": "USD",
"materials": [
{
"item": "Door gasket, 36 × 80 in",
"quantity": 1,
"unitCost": 89,
"total": 89
},
{
"item": "R-404A refrigerant (lb)",
"quantity": 4,
"unitCost": 38,
"total": 152
}
],
"laborHours": 3.5,
"laborRate": 95,
"laborTotal": 332.5,
"subtotal": 573.5,
"taxRate": 8.625,
"tax": 20.79,
"total": 594.29
},
"format": "A4",
"engine": "handlebars",
"html": "<div style=\"max-width:760px;margin:0 auto;padding:44px;font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica,Arial,sans-serif;color:#111827;font-size:13px;\">\n <div style=\"display:flex;justify-content:space-between;align-items:flex-start;margin-bottom:22px;\">\n <div>\n <h1 style=\"font-size:22px;font-weight:800;margin:0;\">{{company.name}}</h1>\n <p style=\"margin:4px 0 0;font-size:12px;color:#6b7280;\">{{company.phone}} &middot; {{company.email}}</p>\n </div>\n <div style=\"text-align:right;\">\n <h2 style=\"font-size:22px;font-weight:800;letter-spacing:2px;margin:0;\">WORK ORDER</h2>\n <p style=\"margin:4px 0 0;color:#6b7280;\">{{workOrderNumber}} &middot; {{formatDate date}}</p>\n <p style=\"margin:8px 0 0;\"><span style=\"background:#fef2f2;color:#b91c1c;font-weight:700;font-size:11px;padding:3px 8px;border-radius:4px;\">{{priority}} priority</span> <span style=\"background:#eff6ff;color:#1d4ed8;font-weight:700;font-size:11px;padding:3px 8px;border-radius:4px;\">{{status}}</span></p>\n </div>\n </div>\n <div style=\"display:flex;gap:16px;margin-bottom:20px;\">\n <div style=\"flex:1;border:1px solid #e5e7eb;border-radius:8px;padding:14px;\">\n <p style=\"font-size:11px;text-transform:uppercase;letter-spacing:1.5px;color:#9ca3af;font-weight:700;margin:0 0 8px;\">Customer &amp; site</p>\n <p style=\"margin:0;font-weight:700;\">{{customer.name}}</p>\n <p style=\"margin:2px 0 0;color:#6b7280;\">{{customer.contact}}</p>\n <p style=\"margin:2px 0 0;color:#6b7280;white-space:pre-line;\">{{customer.address}}</p>\n </div>\n <div style=\"flex:1;border:1px solid #e5e7eb;border-radius:8px;padding:14px;\">\n <p style=\"font-size:11px;text-transform:uppercase;letter-spacing:1.5px;color:#9ca3af;font-weight:700;margin:0 0 8px;\">Assigned</p>\n <p style=\"margin:0;font-weight:700;\">{{technician}}</p>\n <p style=\"margin:2px 0 0;color:#6b7280;\">{{formatDate scheduledDate}}, {{timeWindow}}</p>\n </div>\n </div>\n <p style=\"font-size:11px;text-transform:uppercase;letter-spacing:1.5px;color:#9ca3af;font-weight:700;margin:0 0 8px;\">Job description</p>\n <p style=\"margin:0 0 18px;line-height:1.6;color:#374151;\">{{description}}</p>\n <p style=\"font-size:11px;text-transform:uppercase;letter-spacing:1.5px;color:#9ca3af;font-weight:700;margin:0 0 8px;\">Tasks</p>\n <div style=\"margin-bottom:20px;\">\n {{#each tasks}}\n <div style=\"display:flex;align-items:center;gap:10px;padding:5px 0;\">\n <span style=\"width:14px;height:14px;border:1.5px solid #6b7280;border-radius:3px;display:inline-flex;align-items:center;justify-content:center;flex-shrink:0;\">{{#if done}}<span style=\"width:8px;height:8px;background:#16a34a;border-radius:1px;\"></span>{{/if}}</span>\n <span style=\"{{#if done}}color:#6b7280;{{/if}}\">{{description}}</span>\n </div>\n {{/each}}\n </div>\n <table style=\"width:100%;border-collapse:collapse;font-size:inherit;line-height:inherit;\">\n <thead>\n <tr style=\"background:#f3f4f6;text-align:left;\">\n <th style=\"padding:8px 10px;\">Parts &amp; materials</th>\n <th style=\"padding:8px 10px;text-align:center;\">Qty</th>\n <th style=\"padding:8px 10px;text-align:right;\">Unit cost</th>\n <th style=\"padding:8px 10px;text-align:right;\">Total</th>\n </tr>\n </thead>\n <tbody>\n {{#each materials}}\n <tr>\n <td style=\"padding:8px 10px;border-bottom:1px solid #f3f4f6;\">{{item}}</td>\n <td style=\"padding:8px 10px;border-bottom:1px solid #f3f4f6;text-align:center;\">{{quantity}}</td>\n <td style=\"padding:8px 10px;border-bottom:1px solid #f3f4f6;text-align:right;\">{{formatCurrency unitCost ../currency}}</td>\n <td style=\"padding:8px 10px;border-bottom:1px solid #f3f4f6;text-align:right;\">{{formatCurrency total ../currency}}</td>\n </tr>\n {{/each}}\n <tr>\n <td style=\"padding:8px 10px;border-bottom:1px solid #f3f4f6;\">Labor ({{laborHours}} h at {{formatCurrency laborRate currency}}/h)</td>\n <td style=\"padding:8px 10px;border-bottom:1px solid #f3f4f6;\"></td>\n <td style=\"padding:8px 10px;border-bottom:1px solid #f3f4f6;\"></td>\n <td style=\"padding:8px 10px;border-bottom:1px solid #f3f4f6;text-align:right;\">{{formatCurrency laborTotal currency}}</td>\n </tr>\n </tbody>\n </table>\n <div style=\"display:flex;justify-content:flex-end;margin-top:12px;\">\n <table style=\"min-width:220px;font-size:inherit;line-height:inherit;\">\n <tr><td style=\"padding:3px 0;color:#6b7280;\">Subtotal</td><td style=\"padding:3px 0;text-align:right;\">{{formatCurrency subtotal currency}}</td></tr>\n <tr><td style=\"padding:3px 0;color:#6b7280;\">Tax on parts ({{taxRate}}%)</td><td style=\"padding:3px 0;text-align:right;\">{{formatCurrency tax currency}}</td></tr>\n <tr><td style=\"padding:8px 0 0;font-weight:800;font-size:15px;\">Total</td><td style=\"padding:8px 0 0;text-align:right;font-weight:800;font-size:15px;\">{{formatCurrency total currency}}</td></tr>\n </table>\n </div>\n <div style=\"display:flex;gap:40px;margin-top:44px;font-size:12px;color:#6b7280;\">\n <span style=\"flex:1;border-top:1px solid #9ca3af;padding-top:4px;\">Technician signature</span>\n <span style=\"flex:1;border-top:1px solid #9ca3af;padding-top:4px;\">Customer approval</span>\n </div>\n</div>"
}' --output work-order.pdf

Working in another language? Follow a full guide for your stack:

What you can build

  • Field service teams dispatching jobs to technicians
  • Facilities and maintenance companies tracking repairs
  • Property managers raising maintenance requests
  • Producing a signed completion record for the customer

Frequently asked questions

Can tasks show as completed?
Yes — each task has a done flag, and completed tasks are shown with a filled checkbox.
Can I include parts and labor costs?
Yes — materials are a list with quantity and unit cost, and labor shows hours and rate, followed by tax and the total.
Can I generate work orders from my job management tool?
Yes — call /api/v1/generate when a job is created or completed, or connect it with Zapier or Make.

Related templates

Ship your work order PDF endpoint today

Generate this template with AI, tweak it to match your brand, then render at scale with a single API call — no headless browsers to babysit.