Home/Integrations/Stripe

Stripe and Google Sheets integration

Stripe handles the card. Your sheet keeps track of who paid, how much and for what. I connect the two with Apps Script so a sign-up, order or invoice in a row gets a checkout link, and the payment comes back to that same row without anyone matching it by hand.

Connect Stripe to my sheet

What it can do

Common Stripe jobs I set up. Yours will match how you use Stripe today.

A checkout link per row

The script creates a Stripe Checkout Session or Payment Link with the right amount and description, and writes the link into the row or into the confirmation email.

Payments matched automatically

Each checkout carries the row's ID in its metadata, so when it's paid the script finds the row and marks it Paid with the amount, date and Stripe reference.

Deposits and balances

Charge a deposit now and send a link for the remaining balance later, with the running balance kept on the row.

Refunds logged

Refunds and partial refunds made in the Stripe dashboard show up on the original row, so the sheet's totals stay correct.

Payout reconciliation

A tab listing each Stripe payout with the charges and fees inside it, so you can match deposits in your bank account.

Unpaid reminders

Rows still unpaid after a set number of days get a reminder email with a fresh payment link.

How it's built

The script talks to Stripe's REST API with UrlFetchApp, using a restricted API key stored in the script's properties instead of in the code or the sheet. Creating a Checkout Session is one API call that returns a URL. The row ID goes into the session's metadata and client_reference_id, which is what ties the payment back to the right row.

Stripe can send webhooks, and an Apps Script web app can receive them, but there are two catches. A web app's doPost can't read request headers, so it can't check the Stripe-Signature header directly. And Apps Script answers POST requests through a redirect, which Stripe can count as a failed delivery and retry. When I do use a webhook, the script treats the incoming payload only as a hint and fetches the event from Stripe by its ID before trusting it.

For most small businesses I use a time-driven trigger instead. Every few minutes the script asks Stripe for events or completed checkout sessions created since its last run, updates the matching rows and saves its place. It's simple, it doesn't depend on deliveries arriving, and a missed run catches up on the next one.

Good to know

  • With polling, a payment can take a few minutes to show in the sheet. If you need it in seconds, a small relay service in front of Apps Script can handle webhooks properly.
  • Stripe's normal processing fees still apply. The integration adds no fee of its own.
  • Subscriptions with complex proration or many plan changes are better managed in Stripe's own billing tools, with the sheet as a report.
  • Apps Script's daily URL fetch quota is plenty for most businesses, but very high payment volume should be scoped before building.

Stripe questions

Does card information ever go into my sheet?

No. Customers pay on Stripe's own checkout page. The sheet only receives the result: paid or not, the amount, the date and Stripe's reference ID.

Can I keep using Stripe the way I do now?

Yes. Your Stripe account, dashboard and payouts stay exactly as they are. The script reads from Stripe and creates checkout links; it doesn't change your settings.

What if a customer pays twice?

The script sees both payments against the same row and flags it, so you can refund one from Stripe. It doesn't refund anything on its own unless you ask for that.

Can it work with Stripe test mode first?

Yes. I build and test everything against your test mode keys, then switch to live keys once you've tried it end to end.

Tell me what your sheet needs to do

A few sentences is enough to start. I'll reply with questions, then a plan and a fixed quote.