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}} · {{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}} · {{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 & 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 & 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.