Log every Paddle payment and refund to a Google Sheet
Every payment, refund and chargeback lands as a new row in your spreadsheet, with amounts already converted so the net column adds up.
Whenever Paddle reports a billing event, append a row to a Google Sheet so I have a live transaction ledger I can pivot on without exporting reports by hand. Trigger this on a Paddle webhook. In Paddle, under Developer Tools, the notification destination should be subscribed to transaction.completed and adjustment.created. Ignore anything else that arrives: read event_type off the incoming payload and stop early if it is not one of those two.
Work out which transaction the event is about. For transaction.completed the transaction id is data.id. For adjustment.created the adjustment id is data.id and the transaction it adjusts is data.transaction_id. In both cases call Paddle Get Transaction with that transaction id to fetch the full record, which gives me details.totals, details.line_items, items, customer_id, address_id and billed_at.
Resolve the customer with Paddle Get Customer using the transaction's customer_id and take the email. Resolve the country with Paddle Get Address for Customer using that same customer_id plus the transaction's address_id, and take country_code. If the transaction has no address_id, or either lookup fails, leave those cells blank and still write the row. A missing email must never drop a revenue event from the ledger.
Take the money straight from Paddle so the figures stay internally consistent. For transaction.completed use details.totals: total as gross, fee as fees, earnings as net, and currency_code as the currency. For adjustment.created use the adjustment's own totals object, which has the same shape (total, fee, earnings, currency_code). Do not recompute net from gross minus fees.
Convert the amounts before writing. Paddle's docs state it plainly: "Monetary amounts are strings in the currency's smallest unit (for example "1000" is $10.00 USD, but "1000" is ¥1000 for zero-decimal JPY)." So do not hard-code a divide by 100. Build a small map of currency code to decimal places, defaulting to 2, with 0 for the zero-decimal currencies I bill in, Japanese yen and Korean won being the common ones. Divide by ten to the power of that number of places and write a real number rather than a string, so the sheet can sum the column.
Signs decide whether the net column is real revenue. transaction.completed rows are positive. adjustment.created rows depend on data.action: refund, credit, chargeback and chargeback_warning are money leaving, so write gross, fees and net as negative; chargeback_reverse and credit_reverse are money coming back, so keep those positive. Apply the same sign to all three amount columns so any one of them can be summed on its own.
Append exactly one row per event with Google Sheets Append Values, in this column order: event type (the raw event_type), date, record id, customer email, country, product, plan, currency, gross amount, fees, net amount. Date is the UTC calendar day formatted YYYY-MM-DD, taken from billed_at for transactions (falling back to created_at) and from the adjustment's created_at for adjustments. Record id is the transaction id for transaction.completed and the adjustment id for adjustment.created, which also makes it the key I can dedupe on if Paddle retries a delivery. Product is the line item product names from details.line_items joined with commas, and plan is the matching price names joined the same way, so a multi item transaction still writes a single row. Send the values as USER_ENTERED so dates and numbers land as dates and numbers rather than text.
This one is strictly deterministic. No summarizing, no judgement, no enrichment, no deciding whether an event is interesting. One event in, one clean row out. The sheet already has its header row, so never write headers and never read the sheet back, just append below the last row.
What does this prompt do?
- Adds a row to your spreadsheet the moment a Paddle payment completes or a refund, credit or chargeback is issued.
- Fills in the customer's email and country, the product and plan they bought, and the currency, so you can pivot by customer, region or product.
- Records refunds and chargebacks as negative amounts, so totalling the net column gives you real revenue rather than gross sales.
- Converts Paddle's raw amounts into normal money values, including for currencies like Japanese yen that do not use cents.
What do I need to use this?
- A Paddle account, plus the access needed to add a notification in Paddle's Developer Tools so Paddle can tell us when a billing event happens.
- A Google account with edit access to the spreadsheet you want to use as your ledger.
- A spreadsheet with a tab set aside for the ledger and a header row across the top: event type, date, record id, customer email, country, product, plan, currency, gross, fees, net.
How can I customize it?
- Choose which billing events get logged. Completed payments and adjustments are the default, but you can add failed payments or subscription changes.
- Change the columns or their order, or add your own such as subscription id, tax or discount.
- Point it at a different tab per year, per brand or per currency if you want separate ledgers.
FAQs
Will refunds and chargebacks show up as negative numbers?
What happens with currencies like Japanese yen that do not use cents?
Do I need to set up the spreadsheet first?
Does this work with Paddle Classic or only the current Paddle?
Can I test it before pointing it at real revenue?
Related templates
Every Monday, check every S3 bucket for public exposure, missing encryption and weak backup settings, then get the risks ranked in Slack.
Every weekday at 7am, sign in to the tender portals you track, filter new notices against your bid criteria, and open a deal for the ones worth chasing.
Every weekday at 4pm, spot the threads that went quiet, stage a ready-to-send nudge in your mailbox, and get a ranked Slack recap.
Keep a spreadsheet of your most important senders, and every email from one gets labeled, posted to your team channel, and logged automatically.
The moment an order is fulfilled, we register it with Yotpo so the review request is timed off real delivery, and we log every sync so failures never go unnoticed.
Every night at 11pm we compare the day's Shopify orders with your Zoho Books invoices and payments, and flag only what does not match.
Stop exporting Paddle reports to reconcile revenue.
Set it up once and every payment, refund and chargeback writes itself into your spreadsheet, ready to pivot.