Flow — Cold Outreach (Veterinary)
Status: DRAFTED Owner: john@veterinarywiseai.com Last verified against prod: 2026-05-04 (initial draft — not yet run end-to-end) Related skill: none (new vertical — no skill exists yet)
1. Purpose
Drive veterinary clinic prospects from first awareness to demo booking to paid setup. Source: scraped vet clinic listings. This is the second commercial non-church vertical. Pipeline mirrors church outreach but uses vet-coded copy and routes bookings to the vet-specific Cal.com event type.
2. Trigger
Same pipeline as church/funeral — parameterized by vertical = 'vet'.
- Type: cron (weekly) + manual override
- Source:
/api/cron/outreach-scrape/route.ts(withvertical = 'vet'param) - Schedule: Scrape Mondays 6am ET; send Wednesdays 9am ET
- Founder UI:
/founder/[token]/outreach-engine→ filter by vertical=vet
3. Preconditions
-
outreach_contactsrow exists withvertical = 'vet',status = 'provisioned' -
preview_urlpopulated (must use vet preview template — NOT church or funeral template) -
outreach_contacts.email_do_not_contact = false -
outreach_contacts.status != 'dnc'and!= 'bounced'and!= 'converted' -
tenant_voice_agentsFK constraint DROPPED (Stream A — must be resolved) - Vet preview template deployed (Stream A)
- RESEND_API_KEY active and domain verified for
veterinarywiseai.com - Physical address confirmed in email footer template — BLOCKER for first send
- Cal.com
vetwiseai-demoevent type exists (founder creates manually)
4. Steps
Step 1 — Scrape
What happens: Vet clinic listings are scraped from public directories and loaded into outreach_contacts with vertical = 'vet'.
Where: Scrape source TBD — likely Google Places API (veterinarian category), AVMA directory, or Yellow Pages vet category.
Verifications:
- db:
SELECT count(*) FROM outreach_contacts WHERE vertical='vet' AND created_at >= now() - interval '7 days'→ >0 after scrape run - db:
SELECT name, email, website FROM outreach_contacts WHERE vertical='vet' LIMIT 5→ spot-check: vet clinics only (no pet stores, no groomers)
Failure signal: Count doesn't grow → scraper blocked. Wrong business types included → filter criteria need tightening.
Step 2 — Provision (Personalized Demo Preview)
What happens: provision.ts scrapes the vet clinic website, generates vet-specific Q&A (species served, services, hours, triage scenarios), creates demo tenant row, populates preview_url.
Where: churchwiseai-web/src/lib/outreach/provision.ts — requires vet vertical path (FK blocker must be resolved)
Key Q&A to provision:
- Species served (dogs, cats, exotic, equine)
- After-hours emergency contact / preferred 24-hour facility
- Common services (wellness, dental, surgery, emergency)
- Appointment booking process
Verifications:
- db:
SELECT preview_url, status FROM outreach_contacts WHERE id = '<id>'→ NOT NULL,status = 'provisioned' - render: GET
{preview_url}→ HTTP 200, vet template (not church or funeral), clinic name in title - render: Demo chatbot can answer "What species do you treat?" with provisioned answer
Failure signal: status = 'provision_failed' → FK constraint (Stream A). Preview uses wrong template → vertical routing broken.
Step 3 — Send Email 1 (Day 0)
What happens: Send Email 1 ("What happens when someone calls [Clinic Name] at 8pm?") via Resend. FROM: hello@veterinarywiseai.com.
Where: /api/cron/outreach-send/route.ts → cold-outreach-emails-vet.md templates
Verifications:
- db:
SELECT status, email_1_sent_at FROM outreach_contacts WHERE id = '<id>'→email_1_sent, timestamp NOT NULL - render: FROM address is
hello@veterinarywiseai.com, NOT churchwiseai.com or funeralwiseai.com - render: Subject: "What happens when someone calls [Clinic Name] at 8pm?"
- render: ASPCA Poison Control (888-426-4435) mentioned correctly in body
- render: No theological language ("church," "pastor," "prayer," "congregation")
- render: CASL footer with physical address, unsubscribe link, source disclosure
Failure signal: FROM wrong → template not using VET_FROM constant. ASPCA number wrong → copy error, CRITICAL in this vertical.
Step 4 — Click → Preview Page
What happens: Prospect clicks demo link → /p/[token] stamps pro_website_clicked_at → 302 to /preview/[slug]?ref=outreach_{token}.
Verifications:
- db:
SELECT pro_website_clicked_at, status FROM outreach_contacts WHERE id = '<id>'→ NOT NULL,status = 'clicked' - render: Preview page uses vet template — verify: "your clinic" not "your church," no cross/steeple, no congregation language, triage call-to-action visible
Failure signal: Church template showing → vertical routing broken in PreviewClient.tsx.
Step 5 — Chatbot Interaction (Demo)
What happens: Vet clinic owner/manager types symptoms or questions into demo chatbot.
Verifications:
- render: Type "My dog ate chocolate, what should I do?" → AI gathers weight/amount, references ASPCA Poison Control, doesn't give a medical diagnosis, recommends appropriate action
- render: Type "Do you treat cats?" → responds based on provisioned species data
- render: Type "How do I schedule an appointment?" → clinic-appropriate response, not church booking language
- code: AI does NOT claim to diagnose — it triages and escalates appropriately
Failure signal: AI gives medical diagnosis → CRITICAL. Contact John immediately. AI uses church language → vertical isolation broken.
Step 6 — Demo Voice Call (Optional)
What happens: Prospect dials demo number, hears vet-coded voice agent.
Verifications:
- code: Greeting uses clinic name, mentions after-hours triage capability
- code: Agent asks symptom questions, references ASPCA Poison Control for toxin cases
- code: Agent does NOT say "Let me pray with you" or any church language
- db:
voice_call_logsrow created with correct tenant
Failure signal: Wrong tone (enthusiastic instead of calm clinical) → vet prompt not applied. ASPCA not referenced on toxin call → CRITICAL escalation path broken.
Step 7 — Email 2 (Day 3) and Email 3 (Day 7)
What happens: Follow-up emails sent. Vet-coded copy only.
Verifications:
- db:
SELECT email_2_sent_at, email_3_sent_at FROM outreach_contacts WHERE id = '<id>' - render: Email 2 subject: "The 5pm Friday call that didn't go to voicemail"
- render: ASPCA Poison Control number correct in Email 2 body
- code: DNC gate blocks follow-up if
outreach_contacts.email_do_not_contact = true
Step 8 — Reply / Book / Convert
What happens: Prospect clicks "Book a 20-min call" → cal.com/john-moelker/vetwiseai-demo. Booking recorded.
Verifications:
- db:
SELECT status, booked_at FROM outreach_contacts WHERE id = '<id>'→booked, timestamp NOT NULL - code: Cal.com event type
vetwiseai-demoexists before first campaign send
Failure signal: Cal.com event type missing → 404 on booking link. CRITICAL — check before first send.
Step 9 — Email 4 Break-Up (Day 14)
Verifications:
- db:
SELECT email_4_sent_at FROM outreach_contacts WHERE id = '<id>'→ NOT NULL at day 14 - render: Email 4 close: "Thanks for running a clinic that pet owners trust" — verify no church language
5. What the Recipient Sees
Email 1: Subject: "What happens when someone calls [Clinic Name] at 8pm?"
- From: hello@veterinarywiseai.com
- Practical-empathetic tone
- CTA: "[HEAR [CLINIC NAME]'S DEMO →]" → vet-template preview page
- CASL footer with physical address, unsubscribe, source disclosure
Preview page: /preview/[slug] — vet branded, demo chatbot with triage capability, "Book a Demo" CTA
6. Compliance & Unsubscribe
- Regime: CASL (Canadian) + CAN-SPAM (US)
- Unsubscribe:
veterinarywiseai.com/unsubscribe?token={{token}} - DNC gate:
outreach_contacts.email_do_not_contact = true - Physical address: Required — confirm with founder before first send
- Source disclosure: "You're receiving this because [Clinic Name] appears in public business listings"
7. Failure Modes
| Failure | Signal | Alerting path |
|---|---|---|
| FK constraint blocks provisioning | provision_failed status | Stream A blocker |
| ASPCA number wrong in email | Content error — possible legal exposure | Manual review before first send |
| AI gives medical diagnosis | CRITICAL — liability | Immediate escalation to John |
| Preview uses wrong template | Visual QA fail | Fix vertical routing |
| Cal.com event type missing | 404 on booking link | Founder creates manually before first send |
| FROM wrong domain | Deliverability / brand mismatch | Fix VET_FROM constant |
8. Verification Manifest
flow: cold-outreach-vet
verifications:
- step: 1
verb: db
command: SELECT count(*) FROM outreach_contacts WHERE vertical='vet' AND created_at >= now() - interval '7 days'
expect: ">0 after scrape run"
- step: 2
verb: render
command: "GET {preview_url}"
expect: "HTTP 200, vet template, clinic name in title, no church imagery"
- step: 3
verb: render
command: "Inspect email FROM, subject, body, ASPCA number, footer"
expect: "FROM=hello@veterinarywiseai.com, ASPCA 888-426-4435, CASL footer, no theology"
- step: 5
verb: render
command: "Type 'My dog ate chocolate' in demo chatbot"
expect: "Triage response, ASPCA reference, no diagnosis, appropriate escalation"
- step: 8
verb: db
command: SELECT status, booked_at FROM outreach_contacts WHERE id = '<id>'
expect: "booked, timestamp NOT NULL after Cal.com booking"
9. Open Questions / Known Gaps
- Physical address for CASL footer — BLOCKER
- Vet scrape source not finalized — confirm with founder which directory/API
-
tenant_voice_agentsFK constraint — Stream A must resolve - Vet preview template — Stream A must ship
- Cal.com
vetwiseai-demoevent type — founder creates manually - Resend domain verification for
veterinarywiseai.com - ASPCA Poison Control fee disclosure: the ASPCA Animal Poison Control Center charges ~$95/case. The AI should reference it accurately — not imply it's free. Verify wording in triage prompts.
- Species scope per prospect — provision.ts needs to detect clinic species scope from website before generating Q&A