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:

PartContent
Statemessage (string, required), company_size (number), source (string)
purchase_intentprobability — 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.
priorityscore — low, medium, high, critical
routechoice — 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
Compositelead_score = 2 × purchase_intent + 1 × priority + 1 × p(route = sales), from 0 to 1 — see Composites
Policies1. 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"
    }
  }'
200 OK
{
  "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:

Leadactionaction_reason
A vendor pitch: route = spamblock{ "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 = otherescalate (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, sdr and nurture with 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 high is the most likely level: { "field": "priority", "on": "score", "operator": "gte", "value": 3.5, "action": "escalate" }.

  • Require confident routing with "minConfidence": 0.7 on route: below it, the fallback action applies.

  • Tune lead_score by changing its weights, or add terms — a − 3 × spam probability, a company_fit score — 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.

On this page