Generating PDFs with Custom Templates in Zoho Books API

We recently needed to let customers download their Sales Receipts directly from our app. Fetching the PDF from Zoho Books via API turned out to be straightforward and well-documented. Selecting a custom PDF template, however, required some reverse-engineering.

Here's everything we learned about generating PDFs with custom templates in Zoho Books.

If you haven't set up API authentication yet, check out our guide on Authenticating Zoho Books API Without User Input first.

Selecting a PDF Template

Before generating a PDF, you might want to specify which template to use. Zoho Books lets you create multiple PDF templates for each object type, and you can programmatically set which one applies to a specific record.

To change the template for a sales receipt:

PUT https://www.zohoapis.ca/books/v3/salesreceipts/{{sales_receipt_id}}/templates/{{template_id}}?organization_id={{org_id}}
Authorization: Zoho-oauthtoken {{access_token}}

This change persists. This means it will also update which template is shown when viewing this sales receipt in the Zoho Books UI.

Note: We've tested this approach with sales receipts, but it should work the same way for other Zoho Books objects like invoices, bills, purchase orders, etc. Just swap out salesreceipts in the URL for the appropriate object type (e.g., invoices, bills).

Finding the Template ID

Here's the tricky part: Zoho doesn't make template IDs obvious in the UI. To find the template ID you want:

  1. Go to Settings > Customization > PDF Templates
  2. Select the object type (e.g., Sales Receipt)
  3. Click Edit on the template you want to use
  4. Look at the URL in your browser—it will look something like:
    /app/{{org_id}}#/settings/templates/{{template_id}}/edit
  5. The template_id is right there in the URL

Generating the PDF

Once your template is set (or if you're happy with the default), generating the PDF is simple:

GET https://www.zohoapis.ca/books/v3/salesreceipts/{{sales_receipt_id}}?organization_id={{org_id}}&accept=pdf
Authorization: Zoho-oauthtoken {{access_token}}

The response will be the raw PDF binary data. Handle it according to your needs—save it to disk, upload it to storage, attach it to an email, etc.

Putting It Together

Here's a quick example of the full flow in JavaScript:

async function generateSalesReceiptPdf(salesReceiptId, templateId = null) {
  const accessToken = await getAccessToken(); // See our auth article
  const orgId = process.env.ZOHO_ORG_ID;
  const baseUrl = "https://www.zohoapis.ca/books/v3";

  // Optionally set the template first
  if (templateId) {
    const templateResponse = await fetch(
      `${baseUrl}/salesreceipts/${salesReceiptId}/templates/${templateId}?organization_id=${orgId}`,
      {
        method: "PUT",
        headers: {
          Authorization: `Zoho-oauthtoken ${accessToken}`,
        },
      }
    );

    if (!templateResponse.ok) {
      throw new Error(`Failed to set template: ${templateResponse.statusText}`);
    }
  }

  // Generate the PDF
  const pdfResponse = await fetch(
    `${baseUrl}/salesreceipts/${salesReceiptId}?organization_id=${orgId}&accept=pdf`,
    {
      headers: {
        Authorization: `Zoho-oauthtoken ${accessToken}`,
      },
    }
  );

  if (!pdfResponse.ok) {
    throw new Error(`Failed to generate PDF: ${pdfResponse.statusText}`);
  }

  return pdfResponse.arrayBuffer();
}

A Note on Data Centers

Just like with authentication, make sure you're using the correct API domain for your Zoho data center. We're using zohoapis.ca for the Canadian data center. Check Zoho's data center documentation to find the correct domain for your instance.

Wrapping Up

Generating PDFs from Zoho Books is surprisingly simple once you know the right endpoints. Set your template if needed, hit the GET endpoint with accept=pdf, and you've got your document. No complicated export jobs or polling for completion—just a straightforward API call.

2026-01-31

Thank you for reading! If you have any questions or feedback, please feel free to contact us at hi@davette.ca.

$