Create a branded PDF receipt for every Stripe payment with n8n
Each successful Stripe payment becomes a receipt built from your own Google Docs template, saved to Google Drive as a Doc and a PDF, with the link emailed to the customer.
- Source
- Stripe
- Output
- Google DocsPDF (single runs only)
- Delivered to
- Google Drive
n8n workflow
The importable workflow file for this recipe is being tested and will be added here. The steps below show exactly what it does, so you can build it now in a few minutes with the SourceToDocs n8n node.
How the workflow runs
- 01
Stripe Trigger: Checkout Session.completed
Starts the workflow when a customer completes a Stripe Checkout session or a Payment Link. The event carries the customer's name and email, the amount and the currency.
- 02
If: payment_status is equal to paid
A session can complete before the money has arrived, for example with a bank debit. Only paid sessions continue.
- 03
SourceToDocs: Document, Generate
Rows Come From is set to the Map Columns mode. Customer, Email and Reference come from the event; Amount is divided by 100 and given its currency code; Paid on is the event's timestamp as a date. One payment is one run, so switching on Also generate PDF delivers a PDF beside the Google Doc.
- 04
Gmail: Message, Send
The node's output carries file_url, file_name and a deliveries list. The email goes to the address the customer paid with, and the PDF link comes from the Google Drive delivery.
| Stripe field | Template placeholder |
|---|---|
| customer_details.name | {{ customer }} |
| customer_details.email | {{ email }} |
| amount_total and currency | {{ amount }} |
| payment_intent | {{ reference }} |
| created (the event's time) | {{ paid_on }} |
Or have Claude set it up
The Invoices and receipts skill
works through the SourceToDocs connector at https://app.sourcetodocs.com/api/mcp. Install the skill, connect, then paste:
Use the invoices-and-receipts skill. I exported last month's successful payments from Stripe as a CSV, attached here: one row per payment, with the columns Customer, Email, Amount, Reference and Paid on. The receipts have no line items: one row is one receipt. Create a Google Docs receipt document in SourceToDocs from it, with a PDF for each receipt. I will pick the Google Docs template and the Drive folder "Receipts 2026" when you send me the links. Show me the placeholder mapping and tell me how many runs it takes before you run anything, then generate the first receipt only.
To turn a Stripe payment into a PDF receipt with n8n, start the workflow with the Stripe Trigger on a completed Checkout session, let only paid sessions through, pass the customer, amount and date to the SourceToDocs node to fill your Google Docs receipt template, and email the link the node returns with Gmail. Each payment is its own run, which is what lets SourceToDocs save a PDF next to the Google Doc in your Drive folder. The build is four nodes, described below.
What you need
- A Stripe account that takes payments through Checkout or Payment Links, and its API key for the n8n credential. Build and test with a test mode key first.
- A receipt template in Google Docs with your logo and the placeholders
{{ customer }},{{ email }},{{ amount }},{{ reference }}and{{ paid_on }}. The receipt template is a fuller design with its own placeholder names: a design reference, not a drop-in file. - A SourceToDocs workspace and an API token for it. A workspace owner or admin creates the token on the API Tokens page.
- On the Accounts page, a Google Docs connection for the template and a Google Drive connection for delivery. Every tile is a separate connection: Google Drive does not cover Google Docs.
- n8n, self-hosted or Cloud, with the SourceToDocs node installed. In n8n, open Settings, then Community nodes, and install
@twovmodules/n8n-nodes-sourcetodocs. On n8n Cloud, add it from the nodes panel, where it is listed as a verified node. - A Gmail credential in n8n.
Set up the document in SourceToDocs
SourceToDocs has no Stripe connection. The template and its settings live in SourceToDocs, and n8n sends the payment’s values.
- Create a Google Docs document.
- Upload a small CSV with the header row
Customer,Email,Amount,Reference,Paid onand one sample line as the data source; it becomes a data set. The sample is enough, because the workflow sends the real rows in place of reading the source. - Each column gets an alias, a snake-case identifier derived from its name. The template uses the alias: column
Paid onis{{ paid_on }}. - On the Document step, pick your Google Doc. Its Variables panel lists the exact placeholders for your data set; click one to copy it.
- Add a Google Drive distribution and choose the folder.
- Switch on Also generate PDF in the Output card.
- Leave split off. A split document produces no PDFs.
Build it in n8n
Add the nodes in this order and connect them in a line, using the true output of If. Stripe delivers one event per execution, so no loop is needed.
| Node | Operation | Key settings |
|---|---|---|
| Stripe Trigger | Events: Checkout Session.completed, the checkout.session.completed event | No other settings. Activating the workflow registers the webhook in your Stripe account. |
| If | One condition | {{ $json.data.object.payment_status }} is equal to paid. |
| SourceToDocs | Resource: Document. Operation: Generate | Document: your receipt document. Rows Come From: This Workflow — Map Columns. Data Set: the one with the five columns. Columns: see below. Wait for Completion stays on, which is the default. |
| Gmail | Resource: Message. Operation: Send | To, Subject and Message: see below. |
The trigger outputs the Stripe event, and the Checkout session sits under data.object. Make a test payment and confirm the paths below in the trigger’s output panel. The five column values in the SourceToDocs node:
| Column | Value |
|---|---|
| Customer | {{ $json.data.object.customer_details.name }} |
{{ $json.data.object.customer_details.email }} | |
| Amount | {{ ($json.data.object.amount_total / 100).toFixed(2) }} {{ $json.data.object.currency.toUpperCase() }} |
| Reference | {{ $json.data.object.payment_intent }} |
| Paid on | {{ DateTime.fromSeconds($json.created).toFormat('d LLLL yyyy') }} |
The Gmail fields:
| Field | Value |
|---|---|
| To | {{ $('Stripe Trigger').first().json.data.object.customer_details.email }} |
| Subject | Your receipt |
| Message | Thank you for your payment. Your receipt: {{ $json.deliveries[0].result.pdf_url }} |
The Column names are the data set’s column names, case included, not the template placeholders, which use the aliases.
Getting the amount right
Stripe sends amount_total in the smallest unit of the currency and currency as a lowercase code. A payment of 49.00 euros arrives as 4900 and eur. The Amount expression divides by 100, keeps two decimals and appends the code in capitals, which prints 49.00 EUR.
Two cases need a change:
- Currencies without a minor unit. The Japanese yen and a few others arrive as whole units. Leave out the division for those, or the receipt will show a hundredth of what was paid.
- A currency symbol in place of the code. Replace the expression with
{{ new Intl.NumberFormat('en-US', { style: 'currency', currency: $json.data.object.currency.toUpperCase() }).format($json.data.object.amount_total / 100) }}and set the locale to the one your customers expect.
Mapped values are sent as they resolve, so what the expression prints in n8n’s preview is what appears on the receipt. Check it against a test payment before you go live.
Other Stripe events
Checkout Session.completed is the event to use when customers pay through Checkout or Payment Links, because it carries the name and email they typed. payment_intent is filled for one-off payments; a subscription checkout carries an invoice reference instead, so map Reference to {{ $json.data.object.id }} or another field you see in the trigger’s output.
If your payments are created another way, the Stripe Trigger also offers Charge Succeeded and Payment Intent.succeeded. Their objects have other field names (a charge has amount in place of amount_total, for instance) and do not always carry the customer’s email. Run the trigger once, read the output and adjust the five expressions.
Which link to send
The SourceToDocs node returns file_url and file_name at the top level of its output. With Also generate PDF on and a Google Drive destination, the deliveries list holds one entry per destination, and a Drive entry’s result carries drive_url for the Google Doc and pdf_url for the PDF. The Message above uses the first entry, which is correct when the document has one destination.
The file sits in your Drive folder, so a customer can open the link only if that folder’s sharing allows it. Share the folder so that anyone with the link can view it, or attach the PDF to the email instead (see the FAQ). For customers, the attachment is usually the better choice: nothing in your Drive has to be opened up.
When Stripe’s own receipt is enough
Stripe can email its own receipt after a successful payment, with your branding on it. If that layout is all you need, switch it on and skip this workflow. Build the workflow when the receipt has to follow your own template, carry wording Stripe’s receipt does not have, or be filed as a Doc and a PDF in a Drive folder your team works from.
The Claude route
With the SourceToDocs connector added to Claude and the invoices-and-receipts skill installed, Claude can do the setup above for you: create the document, attach your data, read the template’s placeholders, show you the mapping, set the Drive delivery with a PDF and start the runs, one run per receipt, because a PDF comes with a single run only. You pick the template and the Drive folder through links Claude sends you, and you edit the template itself in Google Docs. The MCP page explains how to connect it.
The limit: Claude cannot read Stripe through SourceToDocs, a payment does not start it, and it does not email the customer. Export the payments from Stripe as a CSV, or keep them in a Google Sheet or an Airtable base, and hand that to Claude. That suits a handful of receipts for a period that has already closed; Claude tells you the number of runs before it starts. To issue a receipt the moment a payment succeeds, use the n8n workflow on this page.
Where this fits
An event, a template and a destination: the same pattern sits behind most generated documents. The document automation guide covers it beyond receipts, and the n8n node page lists what else the node can do.
Related
- document automation: the full guide this recipe belongs to.
- Free receipt template for Google Docs: the template this workflow fills.
- The SourceToDocs n8n node: every action and setting.
- The SourceToDocs MCP server: what Claude can do through the connector.