How a new customer gets enrolled
The guide only guides the customers who are on the list. So the first job is making sure a new customer lands on the list the moment they sign up — without anyone having to remember to add them. There are three ways a customer gets in: your app calls a webhook when someone signs up, somebody types a row in the Drive sheet, or somebody forwards the welcome email to a dedicated address. The first one carries almost everyone. The other two exist for the customers your app can’t tell the guide about on its own.
Key takeaways
- Three enrollment lanes feed one list: a signup webhook, the Drive sheet, and an inbox-forwarding lane.
- The webhook is a Lambda Function URL — your app posts a new customer and the row is enrolled at once.
- Forwarded welcome emails are read by Bedrock Haiku 4.5, which proposes a row.
- Every webhook and parsed row is checked before the sequence starts at day 0.
- The Drive sheet stays the canonical store. The other lanes are conveniences that write into it.
Three lanes into one list
Lane 1: the signup webhook (the lane that carries everyone)
The main lane. Your app already knows the instant someone signs up — that’s the moment to enroll them. Set up a Lambda Function URL (a plain HTTPS endpoint on a Lambda, no API Gateway needed) and have your app POST a small JSON body to it whenever a new customer is created: name, email, plan, and a signup timestamp. The enroll Lambda validates the body (checks the email looks real, the plan is one you know, the signup date isn’t in the future), normalizes it into the sheet’s column shape, and writes the row via the Sheets API. The customer is on the list within a second of signing up, and the sequence starts at day 0 on the next tick.
The endpoint is protected with a shared secret your app sends in a header, checked against a value in Secrets Manager — so a random POST from the internet can’t enroll a fake customer. This is the lane that should carry almost every real signup; the other two exist for the edges.
Lane 2: the Drive sheet itself
The simplest lane. Open the onboarding sheet in Drive, add a row, save. The columns are short: name, email, plan, signup date, the current step, which steps are done, and a paused flag. A small Lambda — drive-sync — runs every fifteen minutes, exports the sheet as plain CSV via the Drive API, and writes it to s3://og-list-source/onboarding.csv if the sheet has changed since the last sync. The guide reads from S3, not Drive directly. That keeps Drive API calls predictable and gives you S3 versioning for free, so a bad bulk-edit can be rolled back in one click.
This lane covers the customers your app can’t webhook for you — the enterprise account your sales team set up by hand, the customer you migrated from an old system, the one who signed a contract over email. Type the row and the guide picks them up on the next tick.
Lane 3: inbox forwarding
Some signups arrive as an email, not an app event. A reseller sends over a new account. A customer replies to your sales thread to confirm they want to start. The welcome message your billing tool sends lands in a shared inbox. Forcing someone to retype those into a sheet is a small chore that gets skipped exactly when things are busy.
Set up a dedicated inbound address — something like welcome@your-company.com — via Amazon SES. Anyone forwards the welcome email there. SES writes the raw MIME to s3://og-raw-mime/. The S3 PUT triggers a parser Lambda that calls Bedrock Haiku 4.5 to read the email and emit a structured row: name, email, plan (if it can tell), and a signup date. The prompt is short: “Extract a customer row. Return JSON only. Mark each field with a confidence score. Do not invent a plan that isn’t in the text.” The proposal goes to a small Slack message that pings the rep who forwarded it — the proposed row, the confidence per field, and three buttons: approve, edit, discard. On approve, the row is written to the sheet via the Sheets API.
The reason every parsed row goes to a human first is simple: a customer enrolled on the wrong plan gets the wrong step plan, and a customer enrolled with a typo in their email never gets a single message. Both are worse than a row that needed ten seconds of human confirmation.
Why the list stays the source of truth
Three lanes in, but only one place where the guide actually looks. That’s a deliberate constraint. If two lanes both wrote directly to the guide’s state, every “why did this customer get this message?” question would mean checking three places. Funneling everything through the Drive sheet means there is exactly one row per customer, and any rep can read or edit any of it without learning a new tool. The convenience lanes are first-class for getting customers in, but they always pass through the sheet on the way.
Next post: how the guide actually reads the list, computes days-since-signup, looks at which steps are done, and picks one of four moves.
All posts