Pabbly Connect
Prerequisites
- A PolyDoc account and API key - sign up for free, no credit card required. The free plan includes 150 PDF conversions per month.
- A Pabbly Connect account - sign up.
Use Case 1: Invoice PDFs from a Spreadsheet
Generate an invoice PDF for every new row in Google Sheets and email it automatically.Google Sheets (new row) → Google Sheets (Lookup Spreadsheet Rows V2) → Code (Run JavaScript) → API (Custom Request) → Gmail
Prepare your data source
Create two Google Sheets tabs: invoices and invoice_items. Examples below - import via File → Import (CSV/XLSX).
| invoice_number | invoice_date | invoice_due_date | invoice_subtotal | invoice_tax_rate | invoice_tax_amount | invoice_total | customer_name | customer_email | customer_street | customer_city | customer_country |
|---|---|---|---|---|---|---|---|---|---|---|---|
| INV-2026-001 | 2026-01-15 | 2026-02-14 | 1200 | 0.1 | 120 | 1320 | John Doe | john.doe@example.com | 456 Customer Avenue | Beautiful City | UK |
| invoice_number | quantity | name | description | price | original_price |
|---|---|---|---|---|---|
| INV-2026-001 | 1 | Web Design Services | Custom website design and development for company homepage | 800 | |
| INV-2026-001 | 1 | Logo Design | Professional logo design with 3 revision rounds | 300 | |
| INV-2026-001 | 1 | SEO Optimization | Search engine optimization for 10 target keywords | 100 | 150 |
Create a workflow and add the trigger
Log in to Pabbly Connect, click Create Workflow, name it something like PolyDoc: Google Sheets → PDF → Gmail, and pick Create from Scratch.
In the Trigger step, pick Google Sheets and choose New or Updated Spreadsheet Row (Pabbly only exposes this single Sheets trigger event). Pabbly then generates a unique Webhook URL and shows the setup steps for the Pabbly Connect Webhooks Google Sheets add-on.
Search rows on invoice_items
Click + Add Action, choose Google Sheets, and pick Lookup Spreadsheet Rows V2. Select the same spreadsheet, point at the invoice_items tab, and configure:
- Lookup Value: map the trigger's
invoice_numberfield - Lookup Column(s): the column letter that holds
invoice_numberon theinvoice_itemssheet (e.g.A) - End Column of Data: the last column letter that holds an item field (e.g.
Fforquantity,name,description,price,original_price) - Use Sheet Headers as Keys in Response: Yes (otherwise rows come back keyed by 0-based column index and the next step has to guess)
- Max Length: 100 (default)
Click Save & Send Test Request - the response panel should expand and show every matching row from invoice_items.
Build the items array
Add Code (Pabbly) → Run JavaScript after the Lookup step. Pabbly's Code step has no separate "Input Data" section - reference the upstream Lookup output by typing / inside the editor and selecting fields from the mapping picker, or by using {{2.field}} syntax (where 2 is the Lookup step's index in the scenario).
// 'rows' below is the array of matching invoice_items rows from the Lookup step.
// Insert it via the mapping picker (type "/" → pick the Lookup step's response array).
const items = rows.map(row => ({
quantity: Number(row.quantity),
name: row.name,
description: row.description,
price: Number(row.price),
...(row.original_price
? { original_price: Number(row.original_price) }
: {}),
}));
return { items };
Add the PolyDoc API request
Click + Add Action and pick API (Pabbly) → Execute API Request. Configure:
- Action Event Method: Custom Request
- Custom Request Method: POST
- API Endpoint URL:
https://api.polydoc.tech/pdf/convert - Payload Type: JSON
- Authentication: Bearer Token, value
YOUR_API_KEY(raw key, noBearerprefix - Pabbly adds it). Get the key from the Dashboard. - Add Headers: enabled, with one row -
X-Sandbox=true - Data: the JSON body below, with trigger and Code-step values mapped in via
/(avoid quoting numeric mappings)
{
"source": "[template:jlE-whg]",
"templateData": {
"invoice_number": "{{1.invoice_number}}",
"invoice_date": "{{1.invoice_date}}",
"invoice_due_date": "{{1.invoice_due_date}}",
"invoice_subtotal": {{1.invoice_subtotal}},
"invoice_tax_rate": {{1.invoice_tax_rate}},
"invoice_tax_amount": {{1.invoice_tax_amount}},
"invoice_total": {{1.invoice_total}},
"customer_name": "{{1.customer_name}}",
"customer_email": "{{1.customer_email}}",
"customer_street": "{{1.customer_street}}",
"customer_city": "{{1.customer_city}}",
"customer_country": "{{1.customer_country}}",
"items": {{3.items}}
}
}
Send the generated PDF
Add a final action: Gmail → Send Email. Pabbly's Gmail action uses OAuth - pick an existing connection or add a new one. Map:
- To:
{{1.customer_email}}from the trigger - Subject: e.g.
Invoice {{1.invoice_number}} - Attachment Name:
invoice-{{1.invoice_number}}.pdf - Attachment URL: the response body URL from the API step - if PolyDoc returned the PDF inline, use the API step's
datafield. To get a hosted URL instead, attach a cloud storage target to the PolyDoc request and pass that link to Gmail.
Save and test
Once every step shows a successful test response, flip the Disable workflow toggle off (the toggle is checked when the workflow is active) and add a real row in your spreadsheet. Watch Task History in the left nav - a green run means the email landed with the watermarked sandbox PDF attached. Then drop the X-Sandbox header to go to production.
Use Case 2: Webhook-Triggered PDF Generation
Receive data from any external service via webhook, generate a PDF, and deliver it.Webhook trigger → API (Custom Request) → Gmail
Add webhook trigger
Create a new workflow, pick Webhook by Pabbly as the trigger app, and choose Catch Webhook (Preferred). Pabbly generates a unique URL - copy it.
Send test data to the webhook
Click Capture Webhook Response in Pabbly (it polls for ~30 seconds), then send a test POST with the canonical body so Pabbly learns every field, including the nested items array:
curl -X POST <YOUR_WEBHOOK_URL> \
-H "Content-Type: application/json" \
-d '{
"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", "price": 800},
{"quantity": 1, "name": "Logo Design", "description": "Professional logo design with 3 revisions", "price": 300},
{"quantity": 1, "name": "SEO Optimization", "description": "SEO for 10 target keywords", "price": 100, "original_price": 150}
]
}'
The trigger panel collapses a Response Received section underneath - expand it to confirm every field you mapped (and the items array as a list, not flattened to per-index keys).
Add PolyDoc API request
Add API (Pabbly) → Execute API Request after the webhook trigger. The form is identical to Use Case 1 Step 5 - select Custom Request + POST, set the URL, add Bearer Token, enable Headers and add X-Sandbox = true, and paste the JSON body below into the Data field.
The only difference vs Use Case 1: every mapping token points at the webhook step ({{1.field}}) instead of at the Code step output, and items drops straight in as {{1.items}} because the webhook payload already carries it as an array.
{
"source": "[template:jlE-whg]",
"templateData": {
"invoice_number": "{{1.invoice_number}}",
"invoice_date": "{{1.invoice_date}}",
"invoice_due_date": "{{1.invoice_due_date}}",
"invoice_subtotal": {{1.invoice_subtotal}},
"invoice_tax_rate": {{1.invoice_tax_rate}},
"invoice_tax_amount": {{1.invoice_tax_amount}},
"invoice_total": {{1.invoice_total}},
"customer_name": "{{1.customer_name}}",
"customer_email": "{{1.customer_email}}",
"customer_street": "{{1.customer_street}}",
"customer_city": "{{1.customer_city}}",
"customer_country": "{{1.customer_country}}",
"items": {{1.items}}
}
}
Deliver the PDF
Add Gmail → Send Email as the final step. Map the attachment to the PolyDoc API step's response (use a cloud storage target in the PolyDoc body if Gmail rejects raw binary). Toggle the workflow active, send another curl, and confirm the PDF lands in the mailbox. Strip the X-Sandbox header for production runs.