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 ↗

Use now

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

hewi333/main1 file shown
SKILL.md
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.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. IMAP: imap.secureserver.net:993 TLS. SMTP: smtpout.secureserver.net:465 TLS. NOT M365 — outlook-graph skill is kept as a separate skill for businesses that use real M365. See references/godaddy-email-setup.md for full setup + verified commands.
  • Payments: Stripe test mode (STRIPE_SECRET_KEY in .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 runs himalaya envelope list to 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. A no_agent=True cron 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 — see references/website-lead-intake.md for 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=qualified
  • estimates: 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"), set estimates.status = paid and customers.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 himalaya inbox read (GoDaddy IMAP — wired and verified) OR automated website-lead polling (v2.0 — wired; see references/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 Drafts to save drafts (NOT template save — that command does not exist). Use himalaya 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

  1. Owner pastes a referral lead into Telegram.
  2. Agent summarizes it and asks to draft an estimate.
  3. Agent prices it with estimator-engine, logs to crm-lite, shows the estimate.
  4. Owner taps "yes."
  5. Agent creates a Stripe (test mode) payment link and returns it.
  6. On camera, pay with test card 4242 4242 4242 4242.
  7. 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-graph skill 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.md Location Tiers → the website estimator widget → the shared rate-card file. If you update one, update all three. Canonical source is estimator-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 forward or 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---
2name: lead-to-payment
3description: "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."
4version: "2.0.0"
5author: Hermes Agent
6license: MIT
7metadata:
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
16This is the end-to-end pipeline for a service business: a lead comes in, the agent
17turns it into a priced estimate, the owner approves it over Telegram, and the agent
18creates a payment link or invoice and tracks it to paid. The owner is never bypassed —
19the agent **drafts and proposes, the human approves**, then the agent executes. This
20mirrors how a small business owner actually wants to work: they stay in control,
21the 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
45Lead 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 
56Agent extracts: customer name, contact (email/phone), property address + region,
57square 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)
61Agent 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 
66Wait for owner go-ahead before pricing. (Keeps a human gate at the top.)
67 
68### 3. Price it — `estimator-engine`
69Run the estimator with the extracted details. Use the published rate card from
70the estimator-engine config (do not invent prices). For 2,400 sqft standard region,
71that's the 1,500–2,500 sf tier at the configured rate per psf plus the cigarette >5yrs
72extended add-on. Return structured line items, not just a total.
73 
74### 4. Log to CRM — `crm-lite`
75Upsert 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
80Show 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 
87Do NOT send or charge anything until the owner says yes.
88 
89### 6. On approval — create the charge — `stripe-payments`
90Default to a **Stripe payment link** (simplest, most demo-friendly). For NET-30 jobs
91use 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
97Agent 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
103owner in Telegram and asks: "Here's the draft email to [customer]. Want me to send it?"
104The owner must explicitly say "send" / "yes" before the agent sends via himalaya.
105 
106If the owner says "edit" → agent revises and shows again.
107If the owner says "no" → agent does not send, logs the decision in CRM.
108 
109To send after approval:
110```bash
111cat << 'EOF' | himalaya template send
112From: [email protected]
113To: [email protected]
114Subject: Your [BUSINESS_NAME] Estimate
115 
116[Email body with estimate + payment link]
117EOF
118```
119 
120To save as draft in the owner's Drafts folder (for the owner to review/edit/send):
121```bash
122cat << 'EOF' | himalaya message save --folder Drafts
123From: [email protected]
124To: [email protected]
125Subject: Your [BUSINESS_NAME] Estimate
126 
127[Email body with estimate + payment link]
128EOF
129```
130 
131Both paths keep the owner in control. Drafts live in the Drafts folder and sync
132to the owner's desktop email client.
133 
134**For email thread replies** (when replying to an existing conversation, e.g. a
135referral email): use `himalaya template reply <message_id>` to generate a
136reply template with proper `In-Reply-To` and `References` headers, then pipe the
137edited template through `himalaya message save --folder Drafts` (to save as draft)
138or `himalaya template send` (to send after owner approval). Do NOT compose a fresh
139email for a thread reply — it breaks the threading headers and the customer won't
140see 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.
164QuickBooks 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 
1751. Owner pastes a referral lead into Telegram.
1762. Agent summarizes it and asks to draft an estimate.
1773. Agent prices it with estimator-engine, logs to crm-lite, shows the estimate.
1784. Owner taps "yes."
1795. Agent creates a Stripe (test mode) payment link and returns it.
1806. On camera, pay with test card `4242 4242 4242 4242`.
1817. 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