Skip to main content

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_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 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.

connect.pabbly.com

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.

connect.pabbly.com

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_number field
  • Lookup Column(s): the column letter that holds invoice_number on the invoice_items sheet (e.g. A)
  • End Column of Data: the last column letter that holds an item field (e.g. F for quantity, 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)
connect.pabbly.com

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 };
connect.pabbly.com

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, no Bearer prefix - 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}}
}
}
connect.pabbly.com

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 data field. 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.

connect.pabbly.com

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}}
}
}
connect.pabbly.com

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.