Collect webhook leads in a Google Sheet
· the plori team
Point any form or service at a plori webhook URL and a workflow appends each delivery to a Google Sheet you already own. Google's OAuth review approved plori's Sheets access in August 2026, so connecting is one consent screen. There is no Google Cloud project to create, no API key to manage, and no Apps Script to maintain.
The sheet stays the system of record. Your lead source only needs to make one HTTP POST.
One lead, from POST to row
The front door only accepts the delivery. The single external write is one appended row.
- 01
Receive
One POST to the hook URL
HTTP 202
- 02
Resolve grant
Managed Google connection
Consent-only OAuth
- 03
Append
Write one row
Your existing sheet
- 04
Verify
Refresh the sheet
One new row
What do you need?
- A plori account.
- An existing Google Sheet with a header row, for example Name, Email, Message, Received, Status.
- The spreadsheet URL. plori asks Google for exactly one permission, the spreadsheets scope, so it cannot browse your Drive to find the file. You name it.
- A lead source that can send an HTTP POST with a JSON body: a site form handler, a payment provider, or curl while you test.
You do not register an OAuth client of your own. plori's Google app passed Google's verification review for the sensitive spreadsheets scope, and the demo Google reviewed is the same flow this example builds.
What prompt should you give plori?
Replace SHEET_URL with your spreadsheet's URL and adjust the field names to your form.
The last paragraph keeps the workflow inactive until you have seen the field mapping and
the hook URL.
Build a webhook workflow named "Lead capture to Google Sheets".
The trigger is an inbound webhook. Each delivery is a JSON lead with name, email, and message fields. Append one row to my existing Google Sheet for every delivery: name, email, message, the delivery time, and the fixed text "new" in the Status column. Use this spreadsheet: SHEET_URL, worksheet "Leads". Do not create a new spreadsheet and do not modify existing rows.
Ask me to connect Google Sheets through the connection card. Never ask me to paste a Google password, token, or code into chat.
Validate the workflow, then show me the field mapping and the hook URL. Do not activate until I approve. After I approve, I will send one test POST with curl and check the sheet myself.How does the Google connection work?
When the agent asks, plori shows a connection card. It sends you to Google's consent screen for plori's own verified app; approve it and the grant lands on your plori account. The workflow definition stores only a reference to that grant, and plori refreshes the access token server-side before a run needs it, so a workflow that fires next month still writes.
The consent screen asks for one permission, which Google words as "See, edit, create, and delete all your Google Sheets spreadsheets." That is the spreadsheets scope, and it is the only scope plori requests: no Drive browsing and no mail. The narrow grant has a visible consequence. plori cannot list your files, which is why the prompt names the spreadsheet URL.
The grant belongs to your plori account, not to this workflow. A second workflow, or the agent itself, can reuse it. Disconnecting deletes plori's stored grant but does not revoke the app at Google; to sever it on Google's side too, remove plori at myaccount.google.com/permissions.
How does the hook URL behave?
The workflow gets a URL of the form https://api.plori.ai/v1/hooks/<key>. The key is a
random 128-bit value and it is the only authentication, so treat the whole URL like a
password: anyone holding it can append rows while the workflow is active. An unknown
key, a paused workflow, and an unactivated draft all answer 404, so the URL reveals
nothing about workflows that will not fire.
The front door accepts a JSON body up to 512 KiB, answers HTTP 202, and replays the delivery into the workflow at least once. Three consequences matter before you wire a production form:
- The 202 comes back immediately and carries no row data. The caller learns "accepted", nothing more.
- 202 means accepted, not appended. The row lands when the replay runs, usually within seconds; an append failure (say the worksheet was renamed) shows up in the workflow's run history, not in the HTTP response.
- Delivery is at-least-once and the hook does not deduplicate. A source that retries its POST produces one row per POST. If your source sends a stable lead ID, tell the workflow to use it as a durable deduplication key; first sighting appends, repeats skip.
What did the real run prove?
This is the flow we recorded for Google's verification of the spreadsheets scope, against a real private spreadsheet named "Leads". Two prompts, one connection.
The first prompt asked the agent to read the sheet, summarize the leads already in it, and set a Status value on each row. Both the read and the cell updates went through the managed Google connection.
The second prompt built this webhook workflow. We then sent one curl POST with a made-up lead and did not touch plori again. The hook answered 202, and refreshing sheets.google.com showed the appended row with its Status set to "new". That recording is what Google's reviewers evaluated before approving the scope.
How do you test it before pointing a real form at it?
Approve the connection card and finish Google's consent screen. Check that the screen names only the spreadsheets permission.
Read the validated field mapping. Every sheet column should come from a named JSON field, the delivery time, or a fixed value like "new".
Approve activation, then send one test POST:
curl -X POST https://api.plori.ai/v1/hooks/YOUR_HOOK_KEY \ -H 'Content-Type: application/json' \ -d '{"name":"Test Lead","email":"[email protected]","message":"Interested in a quote"}'Expect HTTP 202. Refresh the sheet and confirm exactly one new row with the right columns.
Send the same POST again. You should get a second identical row, because the hook treats every POST as a new delivery. If that surprises you, add the deduplication key now, before real traffic does it for you.
Delete the test rows and point your form at the URL.
Can the agent work the sheet, not just fill it?
Yes, and that half turns the sheet from a dump into a tracker. The same Google connection lets the agent read rows and update cells on request: in the recorded run, one prompt had it summarize the open leads and set the Status column across them. Ask for that whenever the sheet needs triage. This example verified the on-request path; a scheduled triage pass is a separate workflow you would build and test on its own.
What are the limits?
- One Google identity per plori account. The connection stores a single Google grant, so one account cannot split leads across sheets owned by two different Google logins.
- The hook has no signature verification. The secrecy of the key is the whole authentication. That is fine for a form handler you control and not enough for a provider that signs its webhooks and expects you to verify the signature.
- Disconnecting in plori does not revoke plori at Google. Do both when you are done.
Common questions about webhooks and Google Sheets
Can I send webhook data to Google Sheets without Zapier or Apps Script?
Yes. A plori workflow gives you a URL of the form https://api.plori.ai/v1/hooks/<key>,
and each JSON POST to it appends one row to a sheet you name. Google connects through
one consent screen on plori's verified app, so there is no script editor, OAuth client,
or API key on your side.
Do I need my own Google Cloud project or API key? No. Google Sheets is a platform-app connection: plori registered and verified the Google app, and you only complete the consent screen. That differs from plori's bring-your-own-app providers such as Reddit Ads, where you register the app yourself.
What Google permission does plori ask for? Exactly one scope, spreadsheets, which Google's consent screen words as "See, edit, create, and delete all your Google Sheets spreadsheets." plori deliberately requests no Drive scope, so it cannot browse or list your files; you give it the spreadsheet URL instead.
Why did one lead show up as two rows? The hook replays each delivery at least once and never deduplicates on its own, so a retrying source produces one row per POST. If your source sends a stable ID, have the workflow use it as a durable deduplication key: the first sighting appends and every repeat skips the write.
Build it in plori
Open plori and paste the prompt. Connect Google only through the connection card when the agent asks.