Lead qualification
Score purchase intent, set a priority, rank with a lead score and route inbound leads to sales, SDRs or nurture — and block spam — with the Lead Qualification template.
Goal: every inbound lead (contact form, chat, e-mail) gets a purchase-intent score, a priority, a lead score and a destination team in a few hundred milliseconds, and obvious spam never reaches your CRM. The template combines three patterns: intent routing, confidence-gated routing and composite scoring.
Create the decision
In the app, open Templates → Lead Qualification → Create decision. The draft contains:
| Part | Content |
|---|---|
| State | message (string, required), company_size (number), source (string) |
purchase_intent | probability — real intent to buy in the next 30 days? Yes: asks for pricing, a demo, a quote or a start date. No: just browsing, student, vendor or spam. |
priority | score — low, medium, high, critical |
route | choice — sales (high intent, ready to talk to sales), sdr (some intent, needs qualification), nurture (early stage, send content), spam (spam, vendor pitch or irrelevant), other |
| Composite | lead_score = 2 × purchase_intent + 1 × priority + 1 × p(route = sales), from 0 to 1 — see Composites |
| Policies | 1. route = spam → block · 2. confidence of purchase_intent below 0.6 → escalate |
Test it in the Playground, then Deploy v1.
Call it
curl -X POST https://api.dcision.io/v1/decisions/lead-qualification \
-H "Authorization: Bearer $DCISION_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: lead-8421" \
-d '{
"state": {
"message": "We need pricing for 500 users and want to start next month.",
"company_size": 500,
"source": "website"
}
}'{
"decision_id": "dec_3fKq9ZtW1mXcV7bN2pLa",
"execution_id": "exec_8HsT2kQw9ZyR4vMn1cXe",
"schema": "lead-qualification",
"version": 1,
"result": { "purchase_intent": 0.9412, "priority": "high", "route": "sales" },
"confidence": { "purchase_intent": 0.8824, "priority": 0.69, "route": 0.85 },
"scores": { "priority": 2.81 },
"composites": { "lead_score": 0.8414 },
"action": "continue",
"action_reason": { "type": "default" },
"metrics": { "latency_ms": 412, "engine": "jev", "model": "jev-1.13.0", "estimated_cost_usd": 0.00001575, "input_tokens": 375, "output_tokens": 36 }
}Other outcomes you will see:
| Lead | action | action_reason |
|---|---|---|
A vendor pitch: route = spam | block | { "type": "policy", "rule": 0 } |
An ambiguous message: purchase_intent = 0.45 (confidence 0.1) | escalate | { "type": "policy", "rule": 1 } |
Nothing fits — a job application: route = other | escalate (the fallback action) | { "type": "other_option", "question": "route" } |
The confidence of a probability is |2p − 1|, so rule 2 escalates every lead whose purchase_intent is between 0.2 and 0.8 — see Confidence and probabilities.
Act on it
async function qualify(lead) {
const response = await fetch("https://api.dcision.io/v1/decisions/lead-qualification", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.DCISION_API_KEY}`,
"Content-Type": "application/json",
"Idempotency-Key": `lead-${lead.id}`,
},
body: JSON.stringify({ state: { message: lead.message, company_size: lead.companySize, source: lead.source } }),
});
if (!response.ok) return crm.assign(lead, "sdr"); // on errors, a person decides
const { action, result, composites, execution_id } = await response.json();
switch (action) {
case "block":
return crm.discard(lead, { reason: "spam", execution_id });
case "escalate":
return crm.assign(lead, "sdr", { note: "needs review", execution_id });
default: {
const sla = { critical: "1h", high: "4h", medium: "1d", low: "3d" }[result.priority];
return crm.assign(lead, result.route, { sla, score: composites.lead_score, execution_id });
}
}
}Sort each team's queue by lead_score to work the best leads first. Fields the decision doesn't declare are still forwarded to the engine, so you can add context such as country or page without changing the schema.
Tune it
-
Describe your business in the decision's
context: what you sell, to whom, your price range. It's sent with every lead. -
Sharpen the boundaries between
sales,sdrandnurturewith exclusions ("not for existing customers", "no budget or timeline mentioned"). If the Playground flags a near tie, the descriptions overlap. -
Escalate critical leads to a person even when routing is confident:
{ "field": "priority", "on": "output", "operator": "gte", "value": "critical", "action": "escalate" } -
Escalate on the weighted level to catch leads that lean critical even when
highis the most likely level:{ "field": "priority", "on": "score", "operator": "gte", "value": 3.5, "action": "escalate" }. -
Require confident routing with
"minConfidence": 0.7onroute: below it, the fallback action applies. -
Tune
lead_scoreby changing its weights, or add terms — a− 3 × spamprobability, acompany_fitscore — then route on it:{ "field": "lead_score", "operator": "gte", "value": 0.8, "action": "continue" }. -
Replay real leads: in Executions, open a run and Re-run this input in the Playground to check that an edit improves it before you deploy v2.
MCP server
The Dcision MCP server at https://api.dcision.io/mcp — authentication, the nine tools with their inputs and outputs, errors, and setup for Claude Code, Cursor, VS Code, Claude Desktop, Codex, Gemini CLI and curl.
Support routing
Route support messages to the right department, rate their urgency and escalate to a human when needed, with the Support Routing template.