Polotno + Lulu pairs Polotno's embedded design editor SDK with Lulu's Print API . Your users lay out cover and interior pages inside your app, your backend hands the book files to Lulu, and Lulu prints, binds, and ships globally.
Try it below: design a 6 × 9 in paperback cover, then open the Lulu tab and press Check with Lulu. The editor exports the cover as a PDF with bleed and Lulu's Print API checks it against the book's size, paper and page count, in Lulu's sandbox. Nothing is printed.
The full code, editor and server, is on GitHub: polotno-lulu-demo. It runs on Polotno SDK, so it needs a Polotno API key. To compare it with the other print APIs, see the print on demand API comparison.
For other sizes and page counts, the free Lulu cover template generator works out the cover size and opens the same editor.
The problem Lulu doesn't solve
Lulu's Print API is the best in the category for indie authors and publishers, but it assumes you arrive with two finished PDFs: one interior and one cover. For indie authors, producing those PDFs is the hard part. Most of them do it in InDesign offline, turning "publish" into a weeks-long project.
Teams building on Lulu without a design layer usually:
- Push authors to InDesign, Affinity Publisher, or Word before upload
- Provide only cover-image placeholders and hand-assembled interiors
- Build custom editors that take months to match Lulu's binding and spine specs
Polotno goes in front of Lulu so authors lay out book pages directly in your app, with the cover bound to Lulu's dimensions, spine included. Peleman used the same pattern to automate their print workflow.
How to create Lulu print jobs with the API
- Design: Author picks a book size (e.g. 6×9 paperback) matching Lulu's pod_package_id . Polotno loads the interior at trim, plus a cover template sized by Lulu's cover-dimensions endpoint for that page count.
- Edit: Author lays out text and images page by page. Spine width recalculates live as pages are added or removed.
- Export: Your app exports two print-ready PDFs (interior and cover) with fonts embedded and images at 300 ppi, using the @polotno/pdf-export package.
- Order: Your backend creates a print job via Lulu's print-jobs/ endpoint with the PDF URLs, pod_package_id , and shipping address.
- Fulfill: Lulu prints, binds, and ships. Your backend receives status updates via Lulu webhooks.
What a request looks like
// 1. Export interior + cover as print-ready PDFs (server-side).
import { jsonToPDF } from "@polotno/pdf-export"
const pdfx = { pdfx: "x-1a", outputIntent: { profile, identifier: "FOGRA39" } }
await jsonToPDF(interiorStore.toJSON(), "./interior.pdf", pdfx)
await jsonToPDF(coverStore.toJSON(), "./cover.pdf", pdfx)
// 2. Upload the PDFs to storage, then POST a print-job to Lulu.
await fetch("https://api.lulu.com/print-jobs/", {
method: "POST",
headers: {
Authorization: `Bearer ${LULU_ACCESS_TOKEN}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
line_items: [{
printable_normalization: {
cover: { source_url: coverPdfUrl },
interior: { source_url: interiorPdfUrl },
pod_package_id: "0600X0900.BW.STD.PB.060UW444.MXX", // 6×9 paperback B&W
},
quantity: 1,
title: "My Book",
}],
contact_email: "dev@yourshop.com", // required: who Lulu contacts about the job
shipping_address: shippingAddress, // includes phone_number
shipping_level: "MAIL",
}),
})
// See https://api.lulu.com/docs/ for the full print-jobs schema.What Polotno handles vs. what Lulu handles
Polotno (in your app)
- Cover + interior page templates, multi-page canvas
- Cover canvas sized from Lulu's cover-dimensions endpoint
- Print-ready PDF export with embedded fonts, plus PDF/X-1a with flattened transparency
- Bleed per pod_package_id , with no crop or trim marks (Lulu asks for none)
- Client, self-hosted, or cloud rendering
Lulu (backend)
- Paperback, hardcover, magazine, photo-book production
- Binding, trimming, finishing
- Global fulfillment
- Print-job status webhooks
Technical details
- Export format: PDF from @polotno/pdf-export with embedded fonts and 300 ppi images. Lulu accepts standard PDFs; PDF/X-1a with CMYK, which flattens transparency, is available when you want stricter control.
- Spine: Your app computes it from the current page count and Lulu's paper + binding tables, then sizes the cover canvas to match.
- Auth: OpenID Connect bearer tokens via Lulu's developer portal. Sandbox available.
- Rendering modes: Client-side for the editor; server-side or Polotno Cloud Render API for deterministic PDF export.
- Handoff to Lulu: POST interior + cover PDF URLs + pod_package_id to print-jobs/ ; receive status via webhook.
What you can build
Any Lulu POD format:
- Paperbacks: perfect-bound, standard and large trim sizes
- Hardcover books: casebound and linen
- Photo books
- Graphic novels and comics
- Workbooks, journals, and notebooks
- Technical manuals and textbooks
- Magazines and zines: saddle-stitched
FAQ
Do I need a Lulu developer account?
Yes. Lulu's API uses OpenID Connect. You'll need client credentials from their developer portal.
What file format does Polotno export?
Print-ready PDFs with embedded fonts and bleed via @polotno/pdf-export , and PDF/X-1a with CMYK when you need it.
How is spine width handled?
Lulu's API calculates it: POST /cover-dimensions/ with the pod_package_id and interior_page_count returns the full cover size. Your app calls it whenever the page count changes and resizes the cover canvas, so interior page count and cover spine can't drift out of sync.
Can I use Lulu's test environment?
Yes. Lulu offers a sandbox. Use those credentials during development, switch to production before launch.
Is this self-serve yet?
Yes. Try the demo above, then start from its code with a Polotno API key and your own Lulu account.
Start building
The code for the demo above is on GitHub: polotno-lulu-demo. Clone it, add a Polotno API key (a trial key from your Polotno dashboard works) and your Lulu API credentials, and the editor-to-order flow runs locally.
