Lead-to-Payment — Master Sales Flow skill
Use when a new lead arrives (email, Telegram message, or website form) and needs to move through the full pipeline: qualify the lead, generate an estimate, get owner approval, create a payment link, draft a customer email for owner review, and track payment.
by hewi333·MIT license·★ 122 Stars on the repo·GitHub ↗
npx degit hewi333/Mom-n-Pop-Skills/skills/lead-to-payment#main ~/.claude/skills/lead-to-paymentChecked ·commit main
Inside this skill
SKILL.md · the author's own words# Lead-to-Payment — Master Sales Flow ## Overview This is the end-to-end pipeline for a service business: a lead comes in, the agent turns it into a priced estimate, the owner approves it over Telegram, and the agent creates a payment link or invoice and tracks it to paid. The owner is never bypassed — the agent **drafts and proposes, the human approves**, then the agent executes. This mirrors how a small business owner actually wants to work: they stay in control, the agent removes the 30–60 min of manual work per estimate. ## Environment assumptions - Model: `zai-org/GLM-5.2` via Together AI, **direct** (no proxy). - Gateway: Telegram, running as a systemd service. Tool calling works in the gateway. - Secrets live in `~/.hermes/.env`. - **Email:** GoDaddy Workspace Email via IMAP/SMTP (`himalaya` CLI, not Microsoft Graph). Config at `~/.config/himalaya/config.toml`, password at `~/.config/himalaya/.email-pw`.
Word-for-word excerpt, not a result. Read the full SKILL.md ↓
Files of Lead-to-Payment — Master Sales Flow
Show the full text208 lines
Lead-to-Payment — Master Sales Flow
Overview
This is the end-to-end pipeline for a service business: a lead comes in, the agent turns it into a priced estimate, the owner approves it over Telegram, and the agent creates a payment link or invoice and tracks it to paid. The owner is never bypassed — the agent drafts and proposes, the human approves, then the agent executes. This mirrors how a small business owner actually wants to work: they stay in control, the agent removes the 30–60 min of manual work per estimate.
Environment assumptions
- Model:
zai-org/GLM-5.2via Together AI, direct (no proxy). - Gateway: Telegram, running as a systemd service. Tool calling works in the gateway.
- Secrets live in
~/.hermes/.env. - Email: GoDaddy Workspace Email via IMAP/SMTP (
himalayaCLI, not Microsoft Graph). Config at~/.config/himalaya/config.toml, password at~/.config/himalaya/.email-pw. IMAP:imap.secureserver.net:993TLS. SMTP:smtpout.secureserver.net:465TLS. NOT M365 —outlook-graphskill is kept as a separate skill for businesses that use real M365. Seereferences/godaddy-email-setup.mdfor full setup + verified commands. - Payments: Stripe test mode (
STRIPE_SECRET_KEYin.env). - QuickBooks is not wired (post-hackathon P1). The flow degrades gracefully without it.
When to Use
- A referral or customer inquiry arrives (e.g., 80% of leads are referral-based).
- Owner forwards/pastes a lead to the agent in Telegram.
- A website estimator form submission needs a real estimate + payment path.
- A voicemail monitor (
grasshopper-voicemail-monitor) logged a new lead and the owner says "price it."
The Flow (happy path)
1. Intake
Lead arrives one of three ways:
- Email inbox (GoDaddy via
himalaya): owner says "check the email" → agent runshimalaya envelope listto read the inbox, identifies leads vs spam/newsletters. - Telegram (always works): owner pastes "new lead: Jane Doe, 2,400 sqft home in [CITY], cigarette smoke, referral from [Referral Partner]."
- Website form (automated, cron-based): the site's contact form emails the owner's
inbox with subject
New website lead: ...and a structured body. Ano_agent=Truecron job polls the inbox every 3 min, parses the fields, logs to CRM, and delivers a formatted summary to the owner's Telegram. v2.0: this is wired and running — seereferences/website-lead-intake.mdfor the polling architecture.
Agent extracts: customer name, contact (email/phone), property address + region, square footage, property type (residential/commercial/apartment), severity/service type (e.g. cigarette >5yrs, pet/trauma), lead source.
2. Summarize + notify owner (Telegram)
Agent posts a short summary to the owner:
📥 New lead — Jane Doe (referral, [Referral Partner]) 2,400 sqft residential, [CITY] ([REGION]), cigarette smoke >5yrs Want me to draft an estimate?
Wait for owner go-ahead before pricing. (Keeps a human gate at the top.)
3. Price it — estimator-engine
Run the estimator with the extracted details. Use the published rate card from the estimator-engine config (do not invent prices). For 2,400 sqft standard region, that's the 1,500–2,500 sf tier at the configured rate per psf plus the cigarette >5yrs extended add-on. Return structured line items, not just a total.
4. Log to CRM — crm-lite
Upsert the customer and create a lead/estimate record:
customers: name, email, phone, address, city, state, zip,lead_source,lead_status=qualifiedestimates: line items, total,status=draft, link back to customer id
5. Propose the estimate to the owner (Telegram) — APPROVAL GATE
Show the owner the full estimate and ask before sending:
🧾 Estimate for Jane Doe — $3,300 • Odor treatment, 2,400 sqft @ $1.25 = $3,000 • Cigarette >5yrs extended = +$550 (adjust per rate card tier) • Travel surcharge ([REGION]) = +$75 Send this to the customer as a payment link / invoice? (yes / edit / no)
Do NOT send or charge anything until the owner says yes.
6. On approval — create the charge — stripe-payments
Default to a Stripe payment link (simplest, most demo-friendly). For NET-30 jobs use a Stripe invoice instead. Amounts are in cents ($3,300 = 330000).
- Create/lookup Stripe customer (store metadata: region, sqft, source).
- Create payment link (or invoice → finalize → send).
- Capture the returned
https://buy.stripe.com/...URL.
7. Draft customer email — himalaya (IMAP/SMTP) — DRAFT ONLY, NO AUTO-SEND
Agent composes a customer-facing email from [email protected] containing:
- The estimate summary (line items + total)
- The Stripe payment link
- Business contact info + call-to-action
The agent does NOT send this email automatically. It shows the full draft to the owner in Telegram and asks: "Here's the draft email to [customer]. Want me to send it?" The owner must explicitly say "send" / "yes" before the agent sends via himalaya.
If the owner says "edit" → agent revises and shows again. If the owner says "no" → agent does not send, logs the decision in CRM.
To send after approval:
cat << 'EOF' | himalaya template send
From: [email protected]
To: [email protected]
Subject: Your [BUSINESS_NAME] Estimate
[Email body with estimate + payment link]
EOF
To save as draft in the owner's Drafts folder (for the owner to review/edit/send):
cat << 'EOF' | himalaya message save --folder Drafts
From: [email protected]
To: [email protected]
Subject: Your [BUSINESS_NAME] Estimate
[Email body with estimate + payment link]
EOF
Both paths keep the owner in control. Drafts live in the Drafts folder and sync to the owner's desktop email client.
For email thread replies (when replying to an existing conversation, e.g. a
referral email): use himalaya template reply <message_id> to generate a
reply template with proper In-Reply-To and References headers, then pipe the
edited template through himalaya message save --folder Drafts (to save as draft)
or himalaya template send (to send after owner approval). Do NOT compose a fresh
email for a thread reply — it breaks the threading headers and the customer won't
see it as part of the conversation.
8. Update CRM + set follow-up
estimates.status = sent, store the Stripe link / invoice id.- Create a follow-up reminder (todo or cron) for 3 days out if unpaid.
9. Track to paid
- Poll Stripe payment status (or receive a webhook if configured).
- On
paid: notify owners in Telegram ("✅ Jane Doe paid $3,300"), setestimates.status = paidandcustomers.lead_status = won. - If QuickBooks is wired: record the payment against the QBO invoice. If not, the Stripe record is the source of truth — fine for now.
Current state (what runs TODAY)
- Intake: Telegram paste OR
himalayainbox read (GoDaddy IMAP — wired and verified) OR automated website-lead polling (v2.0 — wired; seereferences/website-lead-intake.md). - Price: estimator-engine (no creds needed, rate tables in skill config).
- Log: crm-lite (SQLite, no creds needed).
- Charge: Stripe payment link (test mode key set).
- Draft email: himalaya IMAP/SMTP (GoDaddy — wired and verified). DRAFT ONLY — owner
approves before send. Use
himalaya message save --folder Draftsto save drafts (NOTtemplate save— that command does not exist). Usehimalaya template reply <msg_id>for thread replies to preserve In-Reply-To headers. - Track: agent checks Stripe status on request. QuickBooks is not wired (post-hackathon P1). The Stripe record is the source of truth.
Owner-in-the-loop rules (important)
- Always summarize a lead before pricing, and always show an estimate before sending.
- Never create a Stripe charge, send an email, or mark anything paid without explicit owner approval in the chat. The agent proposes; the human commits.
- Keep Hermes command approvals ON. For a business that spends real money, annoying-but-safe beats fast-but-loose.
Demo script
- Owner pastes a referral lead into Telegram.
- Agent summarizes it and asks to draft an estimate.
- Agent prices it with estimator-engine, logs to crm-lite, shows the estimate.
- Owner taps "yes."
- Agent creates a Stripe (test mode) payment link and returns it.
- On camera, pay with test card
4242 4242 4242 4242. - Agent detects
paid, posts "✅ paid" in Telegram, updates the CRM.
Pitfalls
- Stripe amounts are in cents. $3,300 = 330000, not 3300.
- Use Stripe test mode (
sk_test_…) for the demo; test cards only work in test mode. - Match estimate totals to the estimator-engine output exactly so the charge equals the quote.
- Don't claim QuickBooks is live if it isn't wired — present it as roadmap.
- Severity add-on amounts vary by sqft tier — pull the exact figure from the estimator rate card.
- Email is GoDaddy IMAP/SMTP via himalaya, NOT Microsoft Graph. Do not use
outlook-graphskill for GoDaddy-hosted email — it's kept as a separate skill for other businesses that use real M365. - Never auto-send customer emails. Always draft, show the owner in Telegram, get explicit "send" approval, then send via himalaya.
- Region classification must match across all locations:
estimator-engine/SKILL.mdLocation Tiers → the website estimator widget → the shared rate-card file. If you update one, update all three. Canonical source isestimator-engine. - Link CLI approval holds expire in ~6 minutes. When filming + approving real-money flows, set up the camera first, then trigger the spend request. Don't race the timer.
- One-time virtual cards don't work for recurring subscriptions. The Link CLI issues one-time-use cards; the first charge works but rebilling will fail. Accepted for demo; handle recurring billing properly post-hackathon.
- Not all inbound emails are estimate requests. Some are brochure/info requests,
partnership inquiries, or vendor correspondence. Do NOT run these through the estimate
pipeline. Classify first: marketing/brochure requests → route to the marketing owner;
other non-estimate inbound → ask the owner for direction. Use
himalaya message forwardor a fresh email only when thread headers don't matter. - Website-lead emails must match the parser. The form's subject prefix, field names,
and "phone or email" validation must stay in sync with the inbox monitor script. A
validation change on the site is a parser change too (see
references/website-lead-intake.md).
| 1 | |
| 2 | name lead-to-payment |
| 3 | description "Use when a new lead arrives (email, Telegram message, or website form) and needs to move through the full pipeline: qualify the lead, generate an estimate, get owner approval, create a payment link, draft a customer email for owner review, and track payment. This is the master flow that orchestrates estimator-engine, crm-lite, stripe-payments, himalaya (IMAP/SMTP), and quickbooks-online. Owner stays in the loop and approves before anything is sent or charged." |
| 4 | version "2.0.0" |
| 5 | author Hermes Agent |
| 6 | license MIT |
| 7 | metadata |
| 8 | hermes |
| 9 | tags [workflow, orchestration, sales-pipeline, lead-to-cash, owner-in-the-loop] |
| 10 | related_skills [estimator-engine, crm-lite, stripe-payments, himalaya, grasshopper-voicemail-monitor, quickbooks-online] |
| 11 | |
| 12 | |
| 13 | # Lead-to-Payment — Master Sales Flow |
| 14 | |
| 15 | ## Overview |
| 16 | This is the end-to-end pipeline for a service business: a lead comes in, the agent |
| 17 | turns it into a priced estimate, the owner approves it over Telegram, and the agent |
| 18 | creates a payment link or invoice and tracks it to paid. The owner is never bypassed — |
| 19 | the agent **drafts and proposes, the human approves**, then the agent executes. This |
| 20 | mirrors how a small business owner actually wants to work: they stay in control, |
| 21 | the agent removes the 30–60 min of manual work per estimate. |
| 22 | |
| 23 | ## Environment assumptions |
| 24 | Model: `zai-org/GLM-5.2` via Together AI, **direct** (no proxy). |
| 25 | Gateway: Telegram, running as a systemd service. Tool calling works in the gateway. |
| 26 | Secrets live in `~/.hermes/.env`. |
| 27 | **Email:** GoDaddy Workspace Email via IMAP/SMTP (`himalaya` CLI, not Microsoft Graph). |
| 28 | Config at `~/.config/himalaya/config.toml`, password at `~/.config/himalaya/.email-pw`. |
| 29 | IMAP: `imap.secureserver.net:993` TLS. SMTP: `smtpout.secureserver.net:465` TLS. |
| 30 | NOT M365 — `outlook-graph` skill is kept as a separate skill for businesses that use real M365. |
| 31 | See `references/godaddy-email-setup.md` for full setup + verified commands. |
| 32 | **Payments:** Stripe test mode (`STRIPE_SECRET_KEY` in `.env`). |
| 33 | QuickBooks is not wired (post-hackathon P1). The flow degrades gracefully without it. |
| 34 | |
| 35 | ## When to Use |
| 36 | A referral or customer inquiry arrives (e.g., 80% of leads are referral-based). |
| 37 | Owner forwards/pastes a lead to the agent in Telegram. |
| 38 | A website estimator form submission needs a real estimate + payment path. |
| 39 | A voicemail monitor (`grasshopper-voicemail-monitor`) logged a new lead and the |
| 40 | owner says "price it." |
| 41 | |
| 42 | ## The Flow (happy path) |
| 43 | |
| 44 | ### 1. Intake |
| 45 | Lead arrives one of three ways: |
| 46 | **Email inbox** (GoDaddy via `himalaya`): owner says "check the email" → agent |
| 47 | runs `himalaya envelope list` to read the inbox, identifies leads vs spam/newsletters. |
| 48 | **Telegram** (always works): owner pastes "new lead: Jane Doe, 2,400 sqft home in [CITY], |
| 49 | cigarette smoke, referral from [Referral Partner]." |
| 50 | **Website form** (automated, cron-based): the site's contact form emails the owner's |
| 51 | inbox with subject `New website lead: ...` and a structured body. A `no_agent=True` |
| 52 | cron job polls the inbox every 3 min, parses the fields, logs to CRM, and delivers a |
| 53 | formatted summary to the owner's Telegram. **v2.0: this is wired and running** — |
| 54 | see `references/website-lead-intake.md` for the polling architecture. |
| 55 | |
| 56 | Agent extracts: customer name, contact (email/phone), property address + region, |
| 57 | square footage, property type (residential/commercial/apartment), severity/service type |
| 58 | (e.g. cigarette >5yrs, pet/trauma), lead source. |
| 59 | |
| 60 | ### 2. Summarize + notify owner (Telegram) |
| 61 | Agent posts a short summary to the owner: |
| 62 | > 📥 New lead — Jane Doe (referral, [Referral Partner]) |
| 63 | > 2,400 sqft residential, [CITY] ([REGION]), cigarette smoke >5yrs |
| 64 | > Want me to draft an estimate? |
| 65 | |
| 66 | Wait for owner go-ahead before pricing. (Keeps a human gate at the top.) |
| 67 | |
| 68 | ### 3. Price it — `estimator-engine` |
| 69 | Run the estimator with the extracted details. Use the published rate card from |
| 70 | the estimator-engine config (do not invent prices). For 2,400 sqft standard region, |
| 71 | that's the 1,500–2,500 sf tier at the configured rate per psf plus the cigarette >5yrs |
| 72 | extended add-on. Return structured line items, not just a total. |
| 73 | |
| 74 | ### 4. Log to CRM — `crm-lite` |
| 75 | Upsert the customer and create a lead/estimate record: |
| 76 | `customers`: name, email, phone, address, city, state, zip, `lead_source`, `lead_status=qualified` |
| 77 | `estimates`: line items, total, `status=draft`, link back to customer id |
| 78 | |
| 79 | ### 5. Propose the estimate to the owner (Telegram) — APPROVAL GATE |
| 80 | Show the owner the full estimate and ask before sending: |
| 81 | > 🧾 Estimate for Jane Doe — **$3,300** |
| 82 | > • Odor treatment, 2,400 sqft @ $1.25 = $3,000 |
| 83 | > • Cigarette >5yrs extended = +$550 (adjust per rate card tier) |
| 84 | > • Travel surcharge ([REGION]) = +$75 |
| 85 | > Send this to the customer as a payment link / invoice? (yes / edit / no) |
| 86 | |
| 87 | Do NOT send or charge anything until the owner says yes. |
| 88 | |
| 89 | ### 6. On approval — create the charge — `stripe-payments` |
| 90 | Default to a **Stripe payment link** (simplest, most demo-friendly). For NET-30 jobs |
| 91 | use a Stripe invoice instead. Amounts are in **cents** ($3,300 = 330000). |
| 92 | Create/lookup Stripe customer (store metadata: region, sqft, source). |
| 93 | Create payment link (or invoice → finalize → send). |
| 94 | Capture the returned `https://buy.stripe.com/...` URL. |
| 95 | |
| 96 | ### 7. Draft customer email — `himalaya` (IMAP/SMTP) — DRAFT ONLY, NO AUTO-SEND |
| 97 | Agent composes a customer-facing email from `[email protected]` containing: |
| 98 | The estimate summary (line items + total) |
| 99 | The Stripe payment link |
| 100 | Business contact info + call-to-action |
| 101 | |
| 102 | **The agent does NOT send this email automatically.** It shows the full draft to the |
| 103 | owner in Telegram and asks: "Here's the draft email to [customer]. Want me to send it?" |
| 104 | The owner must explicitly say "send" / "yes" before the agent sends via himalaya. |
| 105 | |
| 106 | If the owner says "edit" → agent revises and shows again. |
| 107 | If the owner says "no" → agent does not send, logs the decision in CRM. |
| 108 | |
| 109 | To send after approval: |
| 110 | |
| 111 | cat << 'EOF' | himalaya template send |
| 112 | From: [email protected] |
| 113 | To: [email protected] |
| 114 | Subject: Your [BUSINESS_NAME] Estimate |
| 115 | |
| 116 | [Email body with estimate + payment link] |
| 117 | EOF |
| 118 | |
| 119 | |
| 120 | To save as draft in the owner's Drafts folder (for the owner to review/edit/send): |
| 121 | |
| 122 | cat << 'EOF' | himalaya message save --folder Drafts |
| 123 | From: [email protected] |
| 124 | To: [email protected] |
| 125 | Subject: Your [BUSINESS_NAME] Estimate |
| 126 | |
| 127 | [Email body with estimate + payment link] |
| 128 | EOF |
| 129 | |
| 130 | |
| 131 | Both paths keep the owner in control. Drafts live in the Drafts folder and sync |
| 132 | to the owner's desktop email client. |
| 133 | |
| 134 | **For email thread replies** (when replying to an existing conversation, e.g. a |
| 135 | referral email): use `himalaya template reply <message_id>` to generate a |
| 136 | reply template with proper `In-Reply-To` and `References` headers, then pipe the |
| 137 | edited template through `himalaya message save --folder Drafts` (to save as draft) |
| 138 | or `himalaya template send` (to send after owner approval). Do NOT compose a fresh |
| 139 | email for a thread reply — it breaks the threading headers and the customer won't |
| 140 | see it as part of the conversation. |
| 141 | |
| 142 | ### 8. Update CRM + set follow-up |
| 143 | `estimates.status = sent`, store the Stripe link / invoice id. |
| 144 | Create a follow-up reminder (todo or cron) for 3 days out if unpaid. |
| 145 | |
| 146 | ### 9. Track to paid |
| 147 | Poll Stripe payment status (or receive a webhook if configured). |
| 148 | On `paid`: notify owners in Telegram ("✅ Jane Doe paid $3,300"), set |
| 149 | `estimates.status = paid` and `customers.lead_status = won`. |
| 150 | If QuickBooks is wired: record the payment against the QBO invoice. If not, the Stripe |
| 151 | record is the source of truth — fine for now. |
| 152 | |
| 153 | ## Current state (what runs TODAY) |
| 154 | Intake: Telegram paste OR `himalaya` inbox read (GoDaddy IMAP — wired and verified) |
| 155 | OR automated website-lead polling (v2.0 — wired; see `references/website-lead-intake.md`). |
| 156 | Price: estimator-engine (no creds needed, rate tables in skill config). |
| 157 | Log: crm-lite (SQLite, no creds needed). |
| 158 | Charge: Stripe payment link (test mode key set). |
| 159 | Draft email: himalaya IMAP/SMTP (GoDaddy — wired and verified). DRAFT ONLY — owner |
| 160 | approves before send. Use `himalaya message save --folder Drafts` to save drafts (NOT |
| 161 | `template save` — that command does not exist). Use `himalaya template reply <msg_id>` for |
| 162 | thread replies to preserve In-Reply-To headers. |
| 163 | Track: agent checks Stripe status on request. |
| 164 | QuickBooks is not wired (post-hackathon P1). The Stripe record is the source of truth. |
| 165 | |
| 166 | ## Owner-in-the-loop rules (important) |
| 167 | Always summarize a lead before pricing, and always show an estimate before sending. |
| 168 | Never create a Stripe charge, send an email, or mark anything paid without explicit |
| 169 | owner approval in the chat. The agent proposes; the human commits. |
| 170 | Keep Hermes command approvals ON. For a business that spends real money, annoying-but-safe |
| 171 | beats fast-but-loose. |
| 172 | |
| 173 | ## Demo script |
| 174 | |
| 175 | Owner pastes a referral lead into Telegram. |
| 176 | Agent summarizes it and asks to draft an estimate. |
| 177 | Agent prices it with estimator-engine, logs to crm-lite, shows the estimate. |
| 178 | Owner taps "yes." |
| 179 | Agent creates a Stripe (test mode) payment link and returns it. |
| 180 | On camera, pay with test card `4242 4242 4242 4242`. |
| 181 | Agent detects `paid`, posts "✅ paid" in Telegram, updates the CRM. |
| 182 | |
| 183 | ## Pitfalls |
| 184 | Stripe amounts are in **cents**. $3,300 = 330000, not 3300. |
| 185 | Use Stripe **test mode** (`sk_test_…`) for the demo; test cards only work in test mode. |
| 186 | Match estimate totals to the estimator-engine output exactly so the charge equals the quote. |
| 187 | Don't claim QuickBooks is live if it isn't wired — present it as roadmap. |
| 188 | Severity add-on amounts vary by sqft tier — pull the exact figure from the estimator rate card. |
| 189 | **Email is GoDaddy IMAP/SMTP via himalaya, NOT Microsoft Graph.** Do not use `outlook-graph` |
| 190 | skill for GoDaddy-hosted email — it's kept as a separate skill for other businesses that use real M365. |
| 191 | **Never auto-send customer emails.** Always draft, show the owner in Telegram, get explicit |
| 192 | "send" approval, then send via himalaya. |
| 193 | **Region classification must match across all locations:** `estimator-engine/SKILL.md` |
| 194 | Location Tiers → the website estimator widget → the shared rate-card file. If you update |
| 195 | one, update all three. Canonical source is `estimator-engine`. |
| 196 | **Link CLI approval holds expire in ~6 minutes.** When filming + approving real-money |
| 197 | flows, set up the camera first, then trigger the spend request. Don't race the timer. |
| 198 | **One-time virtual cards don't work for recurring subscriptions.** The Link CLI issues |
| 199 | one-time-use cards; the first charge works but rebilling will fail. Accepted for demo; |
| 200 | handle recurring billing properly post-hackathon. |
| 201 | **Not all inbound emails are estimate requests.** Some are brochure/info requests, |
| 202 | partnership inquiries, or vendor correspondence. Do NOT run these through the estimate |
| 203 | pipeline. Classify first: marketing/brochure requests → route to the marketing owner; |
| 204 | other non-estimate inbound → ask the owner for direction. Use `himalaya message forward` |
| 205 | or a fresh email only when thread headers don't matter. |
| 206 | **Website-lead emails must match the parser.** The form's subject prefix, field names, |
| 207 | and "phone or email" validation must stay in sync with the inbox monitor script. A |
| 208 | validation change on the site is a parser change too (see `references/website-lead-intake.md`). |
Discussion
Alternatives
Browse more free Claude skills or everything in Finance.