FinzBooksDevelopers

PDFs

Render a finished PDF for any customer- or vendor-facing document. The same templates the FinzBooks dashboard uses produce the bytes — branch identity, GSTIN block, HSN/SAC summary, signature image, declaration text all in place.

Each endpoint returns the raw PDF inline so a browser tab can preview it. Pass ?download=true when you want a forced Content-Disposition: attachment instead. The first call for a given document version triggers Puppeteer; subsequent calls return a cached S3 object via redirect, which is why download is fast on the second hit.

Authentication & scopes

Every PDF route gates on the resource's standard READ scope. A token that can list invoices (AIBooks.invoices.READ) can download invoice PDFs — there is no separate “PDF” scope. Multi-org tokens must include ?organization_id on every call.

Common request headers

Authorization:   Bearer aibooks_pat_XXXX...     // PAT or OAuth access token
X-AIBooks-Org:   org_8f9a1c2d                   // required for multi-org tokens
Accept:          application/pdf

Common response headers

HTTP/1.1 200 OK
Content-Type:        application/pdf
Content-Disposition: inline; filename="INV-2026-0042.pdf"
Content-Length:      184236
Cache-Control:       private, max-age=900
X-AIBooks-Render:    cached            // or "fresh" on a first render
X-AIBooks-Version:   7                  // document version this PDF was rendered against

<binary PDF bytes>

When ?download=true is supplied theContent-Disposition flips to attachment so the browser writes the file to disk instead of opening it.

GET/invoices/{invoice_id}/pdfInvoice PDFAIBooks.invoices.READ

Renders the invoice using the org's active template (configured in Settings → Templates). The branch's GSTIN, signatory name, declaration text, and bank-details footer are pulled in automatically.

ParamWhereNotes
invoice_idpathInvoice ID. 404 if not in the active org.
downloadqueryPass true to force an attachment response.
templatequeryOverride the org default. One of classic / modern / boxed / tally. Useful when an integrator wants a different look than the dashboard sends.

Sample request

GET /api/public/v1/invoices/inv_8c3f1a9b/pdf?template=modern&download=true HTTP/1.1
Host: api.aibooks.in
Authorization: Bearer aibooks_pat_3p9q0v1w2x3y4z5a6b7c8d9e
X-AIBooks-Org: org_8f9a1c2d
Accept: application/pdf

Sample response

HTTP/1.1 200 OK
Content-Type:        application/pdf
Content-Disposition: attachment; filename="INV-2026-0042.pdf"
Content-Length:      184236
X-AIBooks-Render:    cached
X-AIBooks-Version:   7

%PDF-1.7
%âãÏÓ
1 0 obj
<< /Type /Catalog /Pages 2 0 R >>
endobj
... [184,168 more bytes] ...
%%EOF

Status doesn't matter — DRAFT and CANCELLED invoices render too, with their state visible at the top of the document. Approved invoices include the IRN + QR when e-invoicing is enabled for the branch.

GET/bills/{bill_id}/pdfBill PDFAIBooks.bills.READ

Renders the vendor bill from the same template family. Note this is the internal-facingrepresentation — you typically don't email a bill back to the vendor (they sent you theirs). Use this for archival or for sending a copy to an internal approver.

Sample request

GET /api/public/v1/bills/bill_2d4e6f8a/pdf HTTP/1.1
Host: api.aibooks.in
Authorization: Bearer aibooks_pat_3p9q0v1w2x3y4z5a6b7c8d9e
X-AIBooks-Org: org_8f9a1c2d
Accept: application/pdf

Sample response

HTTP/1.1 200 OK
Content-Type:        application/pdf
Content-Disposition: inline; filename="BILL-2026-0118.pdf"
Content-Length:      152042
X-AIBooks-Render:    fresh
X-AIBooks-Version:   2

%PDF-1.7 ... [binary bytes] ... %%EOF
GET/estimates/{estimate_id}/pdfEstimate PDFAIBooks.estimates.READ

Standard quote layout with line items, totals, expiry date, and a footer noting validity. Recipients usually receive this attached to an email via the /estimates/{id}/email endpoint — that wraps this same render with an SES delivery.

Sample request

GET /api/public/v1/estimates/est_9b1c3d5e/pdf HTTP/1.1
Host: api.aibooks.in
Authorization: Bearer aibooks_pat_3p9q0v1w2x3y4z5a6b7c8d9e
X-AIBooks-Org: org_8f9a1c2d

Sample response

HTTP/1.1 200 OK
Content-Type:        application/pdf
Content-Disposition: inline; filename="EST-2026-0073.pdf"
Content-Length:      96512
X-AIBooks-Render:    cached
X-AIBooks-Version:   3

%PDF-1.7 ... [binary bytes] ... %%EOF
GET/credit_notes/{credit_note_id}/pdfCredit note PDFAIBooks.creditnotes.READ

Includes a clear “Credit Note” banner so it doesn't get confused with a fresh invoice during GST review. Parent invoice number is referenced in the metadata block when the credit note was raised against one.

Sample request

GET /api/public/v1/credit_notes/cn_7a2b4c6d/pdf?download=true HTTP/1.1
Host: api.aibooks.in
Authorization: Bearer aibooks_pat_3p9q0v1w2x3y4z5a6b7c8d9e
X-AIBooks-Org: org_8f9a1c2d

Sample response

HTTP/1.1 200 OK
Content-Type:        application/pdf
Content-Disposition: attachment; filename="CN-2026-0015.pdf"
Content-Length:      72944
X-AIBooks-Render:    cached
X-AIBooks-Version:   1

%PDF-1.7 ... [binary bytes] ... %%EOF
GET/debit_notes/{debit_note_id}/pdfDebit note PDFAIBooks.debitnotes.READ

Buyer-side version of the above. Includes the reason text + reference to the original bill where present.

Sample request

GET /api/public/v1/debit_notes/dn_5e7f9a1b/pdf HTTP/1.1
Host: api.aibooks.in
Authorization: Bearer aibooks_pat_3p9q0v1w2x3y4z5a6b7c8d9e
X-AIBooks-Org: org_8f9a1c2d

Sample response

HTTP/1.1 200 OK
Content-Type:        application/pdf
Content-Disposition: inline; filename="DN-2026-0008.pdf"
Content-Length:      68812
X-AIBooks-Render:    fresh
X-AIBooks-Version:   1

%PDF-1.7 ... [binary bytes] ... %%EOF
GET/purchase_orders/{purchase_order_id}/pdfPurchase order PDFAIBooks.purchaseorders.READ

Standard PO layout with line items, expected delivery date, and the buyer's shipping address. Emitted to vendors as a confirmation document before they raise their invoice.

Sample request

GET /api/public/v1/purchase_orders/po_1a3b5c7d/pdf?download=true HTTP/1.1
Host: api.aibooks.in
Authorization: Bearer aibooks_pat_3p9q0v1w2x3y4z5a6b7c8d9e
X-AIBooks-Org: org_8f9a1c2d

Sample response

HTTP/1.1 200 OK
Content-Type:        application/pdf
Content-Disposition: attachment; filename="PO-2026-0044.pdf"
Content-Length:      88216
X-AIBooks-Render:    cached
X-AIBooks-Version:   4

%PDF-1.7 ... [binary bytes] ... %%EOF
GET/payments/{payment_id}/pdfPayment voucher PDFAIBooks.payments.READ

A receipt document showing the payment amount, mode (BANK / CASH / UPI / CHEQUE), reference / UTR number, and the invoice(s) or bill(s) the payment was applied against. Used as proof-of-payment by both sides of the transaction.

Sample request

GET /api/public/v1/payments/pay_9d8c7b6a/pdf HTTP/1.1
Host: api.aibooks.in
Authorization: Bearer aibooks_pat_3p9q0v1w2x3y4z5a6b7c8d9e
X-AIBooks-Org: org_8f9a1c2d

Sample response

HTTP/1.1 200 OK
Content-Type:        application/pdf
Content-Disposition: inline; filename="PAY-RCT-2026-0211.pdf"
Content-Length:      52480
X-AIBooks-Render:    cached
X-AIBooks-Version:   1

%PDF-1.7 ... [binary bytes] ... %%EOF

Errors

On failure the response flips to application/json and the standard envelope shape:

HTTP/1.1 404 Not Found
Content-Type: application/json

{
  "code":    "not_found.resource",
  "message": "Invoice 'inv_unknown' not found in this organization."
}
CodeHTTPWhen
not_found.resource404The document doesn't exist in the active org.
auth.insufficient_scope403Token doesn't hold the required READ scope.
validation.invalid_value400Unknown template value.

Implementation notes

  • PDFs are cached per (document_id, version). Editing the document increments the version, forcing the next request to re-render.
  • The first render after a version bump can take up to a few seconds — Puppeteer cold-start. Cached fetches are sub-100ms (a 302 to a presigned S3 URL).
  • Use ?template=…to A/B different layouts without changing the org's default in Settings.