MotusAI
Try the Form →

Stage 01 of 05

Lead
Capture

Every inbound signal — form, webhook, chat, or API — is validated, AI-classified, and structured in under 2 seconds. No manual triage. No missed leads.

Zero manual triage5 intent labels2 AI calls per leadSpam filtered at 85% confidenceInstant qualification queue

The Pipeline

5 steps from submission to queue

The Intake Bot (B1) is a BullMQ worker that processes every job deterministically. Each step has clear success and failure handling.

01

Inbound arrives

Any channel — form, webhook, chat widget, or API — sends a JSON payload to POST /api/triggers/lead.

02

Schema validation

Zod validates the payload. Malformed or missing-email submissions are rejected with an audit log entry (ESC-INT-001) and never touch the database.

03

Intent classification

Claude Haiku reads the message and classifies intent into one of 5 labels. Spam (>85% confidence) is terminated here — no DB write, no wasted compute.

04

Entity extraction

Claude Haiku extracts structured data: name, company, role, budget, use case, and timeline. Falls back to raw form fields if the AI call fails.

05

DB write + queue

Lead record is written to PostgreSQL with all extracted fields. A lead.qualification job is enqueued for the Qualification Bot (B2) to score via BANT.

Capture Channels

6 ways leads enter the system

Every channel posts to the same endpoint: POST /api/triggers/lead. Source attribution is preserved.

Primary

Web Form

The leads app (apps/leads) — a standalone Next.js form at a public URL. Submits via Server Action to avoid CORS.

Attribution

Landing Page CTA

Any button on the landing page that links to the leads form. Source field is set to "landing-cta" for attribution.

Integration

Partner Webhooks

HubSpot, Typeform, or Zapier/Make automations POST directly to /api/triggers/lead with field mapping.

Integration

Chat Widgets

Intercom, Crisp, or Drift can trigger a webhook on conversation close — contact data flows straight into the intake queue.

Async

Email Parsing

Postmark inbound email webhooks parse the sender + body and POST to the intake endpoint. Source is set to "email".

API

Direct API

Any system with an x-api-key header can POST directly. Used for B2B partner integrations and white-label channels.

Payload Schema

What the form sends — what the bot stores

Only email is required. The AI fills gaps — it splits names, infers roles, and normalises budgets.

FieldTypeSourceNotes
emailstringFormPrimary identifier — required on every submission
name / firstName / lastNamestringForm → AI splitAI splits full name into first + last
companystringForm → AI inferAI can infer from email domain if absent
phonestringFormOptional — used by Scheduling Bot
rolestringForm → AI inferAI infers from message context if not stated
budgetstring → numberForm → AI parseAI normalises "$20k" → 20000 (USD)
messagestringFormFree-text — primary input for both AI calls
sourcestringAuto-setChannel attribution: "leads-form", "email", "api"
intentINT_INQ | INT_PRT | …AIWritten to DB after classification
followUpCountint (default 0)SystemIncremented by Follow-Up Bot (B7)
meetingBookedbooleanSystemSet true by Scheduling Bot (B3)
stripePaidbooleanSystemSet true by Payment Bot (B4) on webhook

The AI Layer

Two Claude Haiku calls per lead

Using claude-haiku-4-5-20251001 for both calls — fast (<500ms) and cheap. The two-call design is intentional: spam is detected in Call 1 and terminated before Call 2 runs, saving tokens.

Call 2 only runs if Call 1 returns a non-spam intent. For a 30% spam rate, this reduces entity extraction costs by 30%.

Call 1

Intent Classification

Reads the contact's message and classifies it into one of 5 labels. Runs before any DB write. Spam gate fires here.

INT_INQ

Sales inquiry

Wants pricing, demo, or more info about the platform. Default when intent is ambiguous.

INT_PRT

Partnership

Wants to resell, white-label, integrate, or co-market. Must be explicitly stated.

INT_SUP

Support ticket

Existing customer with a bug or technical issue. Redirected to Support Bot — no lead record created.

INT_SPM

Spam

Automated submission, pharma/casino vocabulary, or no real name. Terminated silently (ESC-INT-002) at >85% confidence.

INT_OOS

Out of scope

Unrelated question with no business value. Logged and discarded.

systemclaude-haiku-4-5-20251001
You are an intent classifier for Motus AI, a B2B AI automation platform.
Classify the contact's submission into exactly one of these intent labels:

INT_INQ — Sales inquiry: wants pricing, a demo, or more information about the platform
INT_PRT — Partnership: wants to resell, white-label, integrate, or co-market
INT_SUP — Support ticket: existing customer reporting a bug or requesting technical help
INT_SPM — Spam: automated submission, irrelevant commercial offer, no real name, or keyword spam
INT_OOS — Out of scope: unrelated question with no business value

Classification rules:
1. Default to INT_INQ when intent is ambiguous but shows genuine interest
2. Mark INT_SPM only when confidence > 0.85 — requires strong signals: no real name,
   suspicious URLs, pharma/casino/SEO vocabulary, or clearly automated
3. Mark INT_PRT only when the contact explicitly mentions reselling, white-labeling,
   integrating, or co-marketing
4. Mark INT_SUP only when the contact references an existing account, mentions
   "not working", "error", "broken", "my subscription", or similar support language

Return valid JSON only — no markdown, no explanation:
{ "intent": "INT_INQ", "confidence": 0.92, "reason": "Contact asks about pricing and team size" }
userclaude-haiku-4-5-20251001
Contact name: {name}
Contact email: {email}
Company: {company}
Message: "{message}"

Classify this contact's intent and return JSON.

// Expected JSON response

{
  "intent":     "INT_INQ",
  "confidence": 0.92,
  "reason":     "Contact asks about pricing and mentions their team size"
}
Call 2

Entity Extraction

Extracts 7 structured fields from the free-text message and form data. Fails gracefully — if extraction fails, raw form fields are used as fallback.

systemclaude-haiku-4-5-20251001
You are an entity extractor for the Motus AI sales qualification system.
Extract structured data from the contact's form submission.
Return null for any field not mentioned — never guess or fabricate.

Extraction rules:
- firstName / lastName: split the full name field; if only one word, put it in firstName
- company: use the form value; if absent, infer from email domain (e.g. john@acme.com → "Acme")
  only if domain is not gmail/yahoo/outlook
- role: use the form value if present; otherwise infer from message context
  ("I run the company" → "CEO/Founder", "our dev team" → "Developer")
- estimatedBudget: extract as a number in USD
  "$20k" → 20000 | "around 15k/month" → 15000 | "under $50k" → 50000
  budget range → use midpoint | return null if not mentioned
- useCase: 3–6 word summary of what they want automated
  e.g. "lead qualification automation", "customer onboarding workflows"
- timeline: when they want to start — normalised string
  "Q3 2026" | "immediately" | "within 3 months" | null if not mentioned

Return valid JSON only — no markdown, no explanation:
{
  "firstName": "Sarah",
  "lastName": "Chen",
  "company": "Acme Corp",
  "role": "Director of Operations",
  "estimatedBudget": 20000,
  "useCase": "customer onboarding automation",
  "timeline": "Q3 2026"
}
userclaude-haiku-4-5-20251001
Name: {name}
Email: {email}
Company: {company}
Phone: {phone}
Role: {role}
Budget: {budget}
Message: "{message}"

Extract structured entity data and return JSON.

// Expected JSON response

{
  "firstName":       "Sarah",
  "lastName":        "Chen",
  "company":         "Acme Corp",
  "role":            "Director of Operations",
  "estimatedBudget": 20000,
  "useCase":         "customer onboarding automation",
  "timeline":        "Q3 2026"
}

Escalation Matrix

4 failure modes, all handled

Every failure path is explicit. Nothing is swallowed silently.

ESC-INT-001

Trigger: Schema validation fails — missing email or malformed payload

Action: Audit log written. Job thrown back to BullMQ for retry (max 4 attempts, exponential backoff). Lead never written to DB.

ESC-INT-002

Trigger: Intent classified as INT_SPM with confidence > 0.85

Action: Terminate cleanly. No DB write. No retry. Audit log entry only. BullMQ marks job as completed.

ESC-INT-003

Trigger: Intent classified as INT_SUP

Action: Enqueue support.ticket_create on bot-support queue. No Lead row created — routed to Support Bot (B5).

ESC-INT-004

Trigger: Entity extraction fails (AI timeout / malformed JSON)

Action: Non-fatal fallback: use raw form fields. Lead is still created and enqueued for qualification.

What Happens Next

Intake completes → Qualification starts

The final action of the Intake Bot is to enqueue a lead.qualification job. The Qualification Bot (B2) runs the BANT scoring model and assigns HOT / WARM / COLD.

≥ 75

HOT

Direct to Scheduling Bot (B3)

50 – 74

WARM

Outreach Bot (B6) for nurturing

< 50

COLD

Archived + CRM task logged

See it live

Submit a lead — watch the pipeline run

Fill out the form. Your submission goes through every step on this page in real time.