When Stripe or PayPal says "paid": mark the invoice paid in Google Sheets and get a Telegram or email alert, with Make
Short answer
Register a webhook in Stripe (invoice.paid, or checkout.session.completed for Payment Links) or PayPal (INVOICING.INVOICE.PAID) that points at a Make scenario, map the invoice number and amount from the event, and let Make find the row, mark it paid and send a thank-you and a Telegram alert. Before relying on it, confirm the payment with the provider instead of trusting the webhook body, and compare the amount received with the amount due. Stripe and PayPal both retry failed deliveries for up to three days, so the scenario must also ignore a payment it has already recorded.
Send a Stripe or PayPal webhook to Make: find the invoice in Google Sheets, mark it paid, thank the client, alert you in Telegram. Events, fields, checks.
Disclosure: links marked "paid link" pay us a commission from the vendor if you sign up. Your price is unchanged, and every file here works without them. How we choose tools →
The invoice reminder is only as good as the status column it reads. If a client pays by card on Tuesday and the sheet still says "open" on Wednesday morning, the reminder goes out to someone who has paid. Updating the sheet by hand works until the week you are busy. The fix is to let the payment provider tell Make the moment money arrives.
This guide covers the part that differs between providers: which Stripe and PayPal events to send, where the invoice number and the amount sit in each, the two checks that stop a forged or partial payment from being recorded as paid, and how to add a Telegram alert. The reminder itself, and why the two scenarios belong together, are in the main guide on automatic invoice reminders.
The reminder this scenario protectsAutomatic, polite invoice reminders from Google Sheets, and when to stop
The blueprint this guide connects to
Payment received → invoice marked "paid" → a thank-you to the client
A paid invoice keeps getting reminders. The payment webhook marks the invoice "paid" with the date in the sheet, and the client gets a short confirmation.
Get all 21 blueprints in one ZIP, by email
As shipped, the blueprint expects the webhook body to carry two fields at the top level, "invoice" and "amount", and reads the same eight-column invoices sheet as the invoice-reminder blueprint: invoice, client, amount, due, status, reminder sent, email, notes. Stripe and PayPal do not send that body shape, so the first job is mapping their fields into the search and the update. The sheet needs no changes; the section on sharing one sheet below shows which column each scenario reads and writes.
Which event to send, and where the fields are
Read from each provider's documentation on 29 September 2026. Send only the events the scenario needs: Stripe's own guidance is to listen only to the event types your integration requires.
| How the client pays | Event to send | Invoice number | Amount paid | Watch out for |
|---|---|---|---|---|
| A Stripe invoice | invoice.paid | data.object.number | data.object.amount_paid, in the smallest currency unit (cents) | Also fires when an invoice is marked paid outside Stripe |
| A Stripe Payment Link | checkout.session.completed | data.object.client_reference_id, if you added it to the link | data.object.amount_total, in cents | Delayed methods (bank debits) complete unpaid; check payment_status is "paid" |
| A PayPal invoice | INVOICING.INVOICE.PAID | detail.invoice_number, on the invoice inside resource | payments.paid_amount.value on the same invoice, a decimal string | Also fires for partially paid and pending; check status is PAID |
| Bank transfer | — (no webhook) | You type it | You type it | Mark the row by hand, or from your bank's export |
Stripe: invoices
Stripe documents invoice.paid as occurring "whenever an invoice payment attempt succeeds or an invoice is marked as paid out-of-band", which is the one you want: it also catches an invoice you mark paid by hand in Stripe. Put Stripe's invoice number in column A of the sheet, or the search will not find the row. Amounts arrive in the smallest currency unit, so 340000 is 3,400.00 US dollars: divide by 100 in Make before comparing or writing it, and do not divide for zero-decimal currencies such as the Japanese yen.
Stripe: Payment Links
A Payment Link has no invoice number of its own. Stripe lets you add a client_reference_id to the link as a URL parameter, and sends it back in checkout.session.completed after payment. Put your invoice number there: letters, digits, dashes and underscores, up to 200 characters, so "INV-1042" works and "1042/A" is silently dropped. Stripe also warns that bank debits and vouchers can take 2–14 days to confirm; for those, the session completes before the money does, so only mark the row paid when payment_status is "paid", and add checkout.session.async_payment_succeeded if you accept them.
PayPal: invoices
PayPal describes INVOICING.INVOICE.PAID as "an invoice is paid, partially paid, or payment is made and is pending". That is three situations under one name, and only one of them means paid. The invoice in the event carries a status; treat PAID and MARKED_AS_PAID as paid, and leave PARTIALLY_PAID and PAYMENT_PENDING open. The easiest way to see exactly where the fields sit is to send a test event from PayPal's webhooks simulator and open the webhook module's output in Make.
Set it up
- Import the payment-received blueprint into Make and copy the address its webhook module shows.
- Stripe: Workbench → Webhooks → "Create an event destination" → Your account → choose the event from the table → Webhook endpoint → paste the Make address. PayPal: in your app's settings on the PayPal Developer dashboard, add a webhook with the Make address and the event.
- In Make, click "Run once", then send a test: a test-mode payment in Stripe, or the webhooks simulator in PayPal.
- Open the webhook module's output and find the invoice number and the amount. Map the number into the Google Sheets search in place of "invoice", and the amount (divided by 100 for Stripe) into the update in place of "amount".
- Add the two checks in the next section, run once more with a test payment, and look at the row and the email.
- Switch the scenario on. Pay one real invoice of your own, small, and watch the row change.
The two checks before you rely on it
Both are listed on the blueprint page, and both matter more here than anywhere else, because this scenario changes money records.
1. Confirm the payment with the provider
A Make webhook address accepts a request from anyone who knows it. Stripe says it plainly: without verification, an attacker could send fake webhook events to your endpoint to trigger actions like modifying records. Stripe and PayPal both sign their events, but checking a signature needs the raw request body and some code. The no-code alternative is to ask the provider: right after the webhook, add a module that retrieves the invoice (or the Checkout Session) by its id from Stripe's API with a read-only restricted key, or from PayPal's, and continue only if the provider says it is paid. A forged event with an invented id fails that lookup. It costs one more operation per payment.
2. Compare the amount received with the amount due
Add a filter between the search and the update: amount received is greater than or equal to the amount in the sheet. Without it, a partial payment is recorded as full payment and the balance is never chased. When the filter stops a payment, send yourself an alert instead, so a person decides what the difference is.
And ignore a payment you have already recorded
Both providers retry deliveries they think failed: Stripe for up to three days in live mode, PayPal up to 25 times over three days. Stripe also notes that an endpoint may occasionally receive the same event more than once. Add a filter that stops when the row's status is already "paid", so a retry does not send the client a second thank-you. If Make takes too long to answer, the provider may retry even though the row was updated; that filter covers it.
Add a Telegram or email alert for yourself
The thank-you goes to the client. To know yourself the moment money lands, add one module at the end of the scenario: Telegram Bot → "Send a Text Message or a Reply", with a text such as "Paid: invoice [number], [amount], [client]". It costs one more operation per payment. For the alert to a team chat, the bot must be a member of the group; the chat ID guide covers where to find the number and the "chat not found" error. If you prefer email, a second Gmail module to your own address does the same job.
Get the Telegram chat ID for the alertPersonal chat, group or channel, and the fix for "chat not found"
Sharing one sheet with the reminder
Both blueprints read the same eight columns, A to H: invoice, client, amount, due, status, reminder sent, email, notes. Point both scenarios at the same spreadsheet and tab and they work together as shipped: the payment closes the row, and the reminder stops chasing it.
- The payment scenario finds the row by the invoice number in column A.
- It writes "paid" into column E (status). The reminder only picks up rows whose status is "open", so a paid invoice is never reminded again.
- It adds the payment date and amount to column H (notes), after anything already written there.
- It sends the thank-you to the client email in column G, the same address the reminder writes to.
- Never insert a column between A and H: both scenarios map by position. Helper columns go to the right of H.
The reminder that reads the same sheet, for reference; its page lists the exact columns and the date filter:
Invoice past due → an automatic, polite reminder
Once a day it finds open invoices past their date and sends a reminder. The client no longer has to remember to chase.
Set up the invoice sheet both scenarios readThe columns, the overdue formula and a view of who has paid
What it costs to run
The webhook uses nothing while nobody pays. Each payment runs four modules as shipped (webhook, search, update, thank-you); the provider check and the Telegram alert add one each, so six operations per payment with both. Thirty payments a month come to about 180 credits. Make's Free plan includes 1,000 credits a month and two active scenarios (checked 2026-09-29); this scenario and the reminder use both slots, and a third automation needs Core, from $12 a month (checked 2026-09-29).
The payment and reminder blueprints run on Make; the free plan is enough to test them with a test-mode payment: Sign up (one month of Core free) → paid link · we earn a commissionPaid link. If you sign up through it we earn a commission from Make; your price is the same, and the link gives you one month of Core free.
What does not work
- Trusting the webhook body alone. Anyone who finds the address can post a "payment". Confirm it with the provider, or verify the signature, before the sheet changes.
- Bank transfers. No provider event arrives when a client pays into your account directly. Those rows still need a person, or an import from your bank.
- Invoice numbers that do not match. The search looks for the exact text in column A. If Stripe numbers invoices "ABC-0001" and your sheet says "1042", nothing is found and nothing is updated. Use one numbering, or put the provider's number in the sheet.
- Refunds and chargebacks. This scenario only moves invoices to "paid". A refund does not reopen the row; handle those by hand, or build a second scenario on the refund event.
- Several payment tools into one scenario. Stripe and PayPal send different shapes. Use one scenario per provider, each writing to the same sheet, rather than a router that guesses which one is calling.
Which Stripe event means an invoice was paid?
invoice.paid. Stripe says it occurs whenever an invoice payment attempt succeeds or an invoice is marked as paid out-of-band. For Payment Links, use checkout.session.completed and check that payment_status is "paid", because delayed payment methods complete the session before the money arrives.
Can I link a Stripe Payment Link to my own invoice number?
Yes. Add client_reference_id=INV-1042 to the link. Stripe sends it back in checkout.session.completed. It accepts letters, digits, dashes and underscores up to 200 characters; anything else is silently dropped, so test with a real link.
Does PayPal's INVOICING.INVOICE.PAID mean the invoice is fully paid?
Not always. PayPal says the event fires when an invoice is paid, partially paid, or a payment is pending. Check the invoice status in the event: only PAID or MARKED_AS_PAID should mark the row paid.
Why did the client get two thank-you emails?
The provider delivered the event twice, which Stripe and PayPal both do when they think a delivery failed; Stripe also notes duplicates can happen occasionally. Add a filter that stops when the row already says "paid".
Is it safe to leave the Make webhook address unprotected?
Not for a scenario that marks money as received. Add a module that looks the payment up with the provider's API and continues only when it is paid, or verify the provider's signature. The lookup needs no code and costs one operation per payment.
- Stripe Docs — Receive Stripe events in your webhook endpoint (signatures, retries for up to three days, duplicate events)
- Stripe Docs — Types of events (invoice.paid, checkout.session.completed)
- Stripe Docs — Track a payment link (client_reference_id; delayed payment methods 2–14 days)
- PayPal Developer — Webhooks (signature verification; 25 retries over 3 days)
- PayPal Developer — Webhook event names (INVOICING.INVOICE.PAID)
- Make Help Center — Webhooks
- Make — Pricing (Free: 1,000 credits, 2 active scenarios; Core from $12/month; checked 2026-09-29)


