Skip to main content

Appsmith

Prerequisites

  • A PolyDoc account and API key - sign up for free, no credit card required. The free plan includes 150 PDF conversions per month.
  • An Appsmith instance: Community Edition (self-hosted, free) or Appsmith Cloud (free tier available).
  • Your data in a database, REST API, or Google Sheets connected as an Appsmith datasource.

Use Case 1: Download invoice PDF from a table row

Add a Download PDF button to an Appsmith table. When clicked it reads the selected invoice row plus its line items, calls PolyDoc, and saves the resulting PDF directly from the browser.
Button (onClick) → REST query (PolyDoc) → JS Object (Blob download)

Set up your data

Use invoices (one row per invoice) and invoice_items (line rows linked by invoice_number). Examples below - two tabs in Sheets; two tables or linked records elsewhere.

invoice_numberinvoice_dateinvoice_due_dateinvoice_subtotalinvoice_tax_rateinvoice_tax_amountinvoice_totalcustomer_namecustomer_emailcustomer_streetcustomer_citycustomer_country
INV-2026-0012026-01-152026-02-1412000.11201320John Doejohn.doe@example.com456 Customer AvenueBeautiful CityUK
invoice_numberquantitynamedescriptionpriceoriginal_price
INV-2026-0011Web Design ServicesCustom website design and development for company homepage800
INV-2026-0011Logo DesignProfessional logo design with 3 revision rounds300
INV-2026-0011SEO OptimizationSearch engine optimization for 10 target keywords100150

Create a new Appsmith app. Open the JS tab, click + New JS Object, and replace its body with the data below — one invoice with its line items nested under items:

export default {
invoices: [
{
invoice_number: "INV-2026-001",
invoice_date: "2026-01-15",
invoice_due_date: "2026-02-14",
invoice_subtotal: 1200,
invoice_tax_rate: 0.1,
invoice_tax_amount: 120,
invoice_total: 1320,
customer_name: "John Doe",
customer_email: "john.doe@example.com",
customer_street: "456 Customer Avenue",
customer_city: "Beautiful City",
customer_country: "UK",
items: [
{ quantity: 1, name: "Web Design Services", description: "Custom website design and development for company homepage", price: 800 },
{ quantity: 1, name: "Logo Design", description: "Professional logo design with 3 revision rounds", price: 300 },
{ quantity: 1, name: "SEO Optimization", description: "Search engine optimization for 10 target keywords", price: 100, original_price: 150 },
],
},
],
};

Save and rename the JS Object to appData. Then drag a Table widget onto the canvas and set its Table data property to {{appData.invoices}}. Selecting the row exposes every column as Table1.selectedRow.* to the rest of the steps — including the nested items array.

app.appsmith.com

Add the PolyDoc REST API datasource

Navigate to Datasources → + New datasource and choose Authenticated API. Configure:

  • Name: PolyDoc
  • URL: https://api.polydoc.tech
  • Authentication type: Bearer token
  • Bearer token: your PolyDoc API key (paste the raw api_… string — no Bearer prefix; Appsmith adds that to the Authorization header automatically). Grab the key from the PolyDoc Dashboard.

Click Save. Every query built on this datasource will now send Authorization: Bearer api_… automatically — Step 3 just configures the path, headers, and body.

app.appsmith.com

Create the line items and PDF queries

Create a query on the PolyDoc datasource from Step 2, name it generatePdf, and configure:

  • Method: POST
  • Path: /pdf/convert
  • Headers:
  • Body type: JSON

Paste this into the Body tab. Appsmith's mustache bindings expand inline, so text fields stay quoted ("{{...}}") and numeric / array fields are left unquoted:

{
"source": "[template:jlE-whg]",
"templateData": {
"invoice_number": "{{Table1.selectedRow.invoice_number}}",
"invoice_date": "{{Table1.selectedRow.invoice_date}}",
"invoice_due_date": "{{Table1.selectedRow.invoice_due_date}}",
"invoice_subtotal": {{Table1.selectedRow.invoice_subtotal}},
"invoice_tax_rate": {{Table1.selectedRow.invoice_tax_rate}},
"invoice_tax_amount": {{Table1.selectedRow.invoice_tax_amount}},
"invoice_total": {{Table1.selectedRow.invoice_total}},
"customer_name": "{{Table1.selectedRow.customer_name}}",
"customer_email": "{{Table1.selectedRow.customer_email}}",
"customer_street": "{{Table1.selectedRow.customer_street}}",
"customer_city": "{{Table1.selectedRow.customer_city}}",
"customer_country": "{{Table1.selectedRow.customer_country}}",
"items": {{Table1.selectedRow.items}}
}
}
app.appsmith.com

Create a JS Object with the download function

Back in the JS tab, click + New JS Object and name it invoiceActions (a second JS Object alongside the appData created in Step 1). The function below runs the generatePdf query from Step 3, wraps the binary response in a Blob, and triggers a browser download:

export default {
async downloadPdf() {
// Call PolyDoc - response.data is the binary PDF (Step 3)
await generatePdf.run();

// Wrap the binary response in a Blob and trigger the save dialog
const blob = new Blob([generatePdf.data], { type: "application/pdf" });
const objectUrl = URL.createObjectURL(blob);
download(
objectUrl,
"invoice-" + Table1.selectedRow.invoice_number + ".pdf"
);
URL.revokeObjectURL(objectUrl);
},
};
app.appsmith.com

Add a button and test

Drag a Button widget next to the table from Step 1 and set its label to Download PDF. In the onClick event, choose Execute a JS function, then pick invoiceActions.downloadPdf — the function authored in Step 4.

Select the seeded INV-2026-001 row and click the button. The browser saves a file named invoice-INV-2026-001.pdf. If nothing happens, open the Run history panel — it shows the raw PolyDoc response and any error envelope.

app.appsmith.com

Use Case 2: Email the invoice PDF to the customer

Add a second Send Invoice button that emails the PDF as an attachment, using Appsmith's built-in SMTP datasource — no S3 bucket or third-party email API needed.
Button (onClick) → JS Object → REST query (PolyDoc) → SMTP query

Add an SMTP datasource

Go to Datasources → + New datasource and choose SMTP. Configure with your email provider's relay settings:

  • Name: SendMail
  • Host: your SMTP server (e.g. smtp.gmail.com, smtp.sendgrid.net)
  • Port: 587 (STARTTLS) or 465 (implicit TLS)
  • Username: the SMTP login (often your sender address)
  • Password: an app password for Gmail / Outlook / iCloud — the normal account password is rejected once 2FA is on. For transactional services (SendGrid, Mailgun, Postmark) this is the API credential they issue.

Click Test to verify the connection, then Save. A failed test usually means port/TLS mismatch (try the other of 587 / 465) or that 2FA blocks the plain account password.

app.appsmith.com

Create the send email query

Create a query on the SendMail datasource from Step 1, name it sendInvoiceEmail, and fill in:

  • From email: your sender address (must match what the SMTP provider authorises for the account in Step 1)
  • To email: {{Table1.selectedRow.customer_email}}
  • Subject: Invoice {{Table1.selectedRow.invoice_number}}
  • Body type: Text, content e.g. Hi, please find your invoice attached.
  • Attachments:
    • File name: invoice-{{Table1.selectedRow.invoice_number}}.pdf
    • Data: {{generatePdf.data}}
    • Type: application/pdf
app.appsmith.com

Add a sendInvoice function to the JS Object

Add a sendInvoice function to the invoiceActions JS Object created in Use Case 1, Step 4. It chains the three queries — line items, PDF, email — and shows an alert when SMTP confirms delivery:

export default {
// ... existing downloadPdf function ...

async sendInvoice() {
// Generate the PDF (binary response on generatePdf.data)
await generatePdf.run();

// Email it as a PDF attachment
await sendInvoiceEmail.run();

showAlert(
"Invoice sent to " + Table1.selectedRow.customer_email,
"success"
);
},
};
app.appsmith.com

Add a button and test

Repeat the pattern from Use Case 1, Step 5: drag a Button widget alongside the existing Download PDF button, label it Send Invoice, and wire its onClick event to invoiceActions.sendInvoice — the function added in Step 3.

Select the seeded invoice row, click Send Invoice, and confirm the customer's inbox receives the email with the PDF attached. The Run history panel shows each query's response in order, which is the fastest way to spot whether the SMTP step or the PolyDoc call failed.

app.appsmith.com