Skip to content
TheThinkLoop

Template - Customer health

Score

Churn risk

How likely a customer is to leave, based on what they wrote.

A score decision that reads a customer message for signs of churn, so customer success can respond before a cancellation arrives.

The decision

ScoreA position on the ordered levels (0 = first level), a confidence value, and a probability for every level.

How likely is this customer to churn?

Levels, lowest to highest

  1. 0Low: Satisfied or neutral. No sign of leaving.
  2. 1Elevated: Frustrated or disengaged, but no stated intent to leave.
  3. 2High: States or strongly implies an intent to cancel, not renew, or switch.

Evidence checks (asked in the same request)

  • Cancellation intent: The customer says they intend to cancel or not renew.
  • Competitor mentioned: The customer mentions a competitor or evaluating alternatives.
  • Negative sentiment: The customer expresses frustration or dissatisfaction.

Expected output: A score from 0 to 2, a probability for each level, and a confidence value, plus one probability per evidence check.

Input

The Decisions API reads one input. Combine these fields into it as labeled text so the model sees the facts the decision depends on.

Input fields
FieldTypeRequiredDescription
messagestringYesThe customer's message, verbatim. Include the subject line if there is one.
renewal_datestringNoUpcoming renewal date, so risk can be read in context.

Worked examples

  1. Evaluating alternatives before renewal

    We're evaluating alternatives because the reporting module is still broken after three tickets. Honestly we're frustrated, and unless this improves we won't renew in March.

    A careful reviewer would say: High. An explicit non-renewal warning, an unresolved problem, and a competitor evaluation.

    Run this example
  2. Expanding and asking for more

    Loving the new dashboards. We just added 20 more seats for the EMEA team. Is there a way to schedule reports weekly?

    A careful reviewer would say: Low. Expansion and positive sentiment. The question is about using the product more.

    Run this example

Expected answers are human judgments written for this template, not model output.

How it works

This template reads one message. It is a signal to add to your health model, not a replacement for it: usage data and renewal history say more about churn than any single email.

What it adds is speed. A customer who writes "we're evaluating alternatives" in a support ticket should reach customer success the same day, and this decision can make that happen without anyone reading every ticket.

Human review and thresholds

Recommended review policy

The action here is a notification to a person, so automation risk is low. Send High results to the account owner immediately, and batch Elevated results into a daily digest.

Choosing thresholds

The cost of a false alarm is a customer success manager's attention. If your team is small, alert only on a high probability for the top level. If each account is worth a lot, a lower bar pays for itself.

Starting automation threshold
80%
Starting don’t-decide threshold
50%

Starting points for the playground, not recommendations. The right values depend on your costs and on how the model’s confidence tracks accuracy on your data. Calibrate them.

Limitations

  • Many customers who churn never say so. A low score on a message is not evidence of a healthy account.
  • Frustration is common in support and usually does not mean churn. Expect the middle level to be noisy.
  • This is text classification of intent signals, not a churn forecast. Do not report its scores as probabilities of churn.

Use it in your code

The template definition is plain JSON: the question, the evidence checks, the input fields, and the starting policy. The SDK call below sends the same question and checks to the Decisions API from your server.

churn-risk.jsonjson
{
  "$format": "thethinkloop.template/v1",
  "slug": "churn-risk",
  "title": "Churn risk",
  "decides": "How likely a customer is to leave, based on what they wrote.",
  "question": {
    "name": "decision",
    "type": "score",
    "instructions": "How likely is this customer to churn?",
    "levels": [
      {
        "label": "Low",
        "description": "Satisfied or neutral. No sign of leaving."
      },
      {
        "label": "Elevated",
        "description": "Frustrated or disengaged, but no stated intent to leave."
      },
      {
        "label": "High",
        "description": "States or strongly implies an intent to cancel, not renew, or switch."
      }
    ]
  },
  "evidenceChecks": [
    {
      "name": "factor_1",
      "label": "Cancellation intent",
      "type": "predicate",
      "instructions": "The customer says they intend to cancel or not renew."
    },
    {
      "name": "factor_2",
      "label": "Competitor mentioned",
      "type": "predicate",
      "instructions": "The customer mentions a competitor or evaluating alternatives."
    },
    {
      "name": "factor_3",
      "label": "Negative sentiment",
      "type": "predicate",
      "instructions": "The customer expresses frustration or dissatisfaction."
    }
  ],
  "inputs": [
    {
      "name": "message",
      "type": "string",
      "required": true,
      "description": "The customer's message, verbatim. Include the subject line if there is one."
    },
    {
      "name": "renewal_date",
      "type": "string",
      "required": false,
      "description": "Upcoming renewal date, so risk can be read in context."
    }
  ],
  "expectedOutput": "A score from 0 to 2, a probability for each level, and a confidence value, plus one probability per evidence check.",
  "examples": [
    {
      "title": "Evaluating alternatives before renewal",
      "input": "We're evaluating alternatives because the reporting module is still broken after three tickets. Honestly we're frustrated, and unless this improves we won't renew in March.",
      "expected": "High"
    },
    {
      "title": "Expanding and asking for more",
      "input": "Loving the new dashboards. We just added 20 more seats for the EMEA team. Is there a way to schedule reports weekly?",
      "expected": "Low"
    }
  ],
  "startingPolicy": {
    "automateAt": 0.8,
    "abstainBelow": 0.5,
    "note": "A starting point for exploration, not a recommendation. Calibrate against your own labeled examples."
  }
}
Equivalent SDK calljavascript
import OpenAI from "openai"; // openai >= 7.30.0

const client = new OpenAI(); // reads OPENAI_API_KEY on the server

const decision = await client.decisions.create({
  model: "gpt-6-luna",
  input: "We're evaluating alternatives because the reporting module is still broken after three tickets. Honestly we're frustrated, and unless this improves we won't renew in March.",
  questions: [
    {
      type: "score",
      name: "decision",
      instructions: "How likely is this customer to churn?",
      levels: [
        {
          label: "Low",
          description: "Satisfied or neutral. No sign of leaving."
        },
        {
          label: "Elevated",
          description: "Frustrated or disengaged, but no stated intent to leave."
        },
        {
          label: "High",
          description: "States or strongly implies an intent to cancel, not renew, or switch."
        }
      ]
    },
    {
      type: "predicate",
      name: "factor_1",
      instructions: "The customer says they intend to cancel or not renew."
    },
    {
      type: "predicate",
      name: "factor_2",
      instructions: "The customer mentions a competitor or evaluating alternatives."
    },
    {
      type: "predicate",
      name: "factor_3",
      instructions: "The customer expresses frustration or dissatisfaction."
    }
  ],
});

// Answers come back in question order. A question can also be refused.
const [main, ...checks] = decision.answers;
if (main.type === "refusal") throw new Error("The model declined to answer.");
if (main.type === "score") {
  console.log(main.score, main.confidence, main.probabilities);
}

Download it as churn-risk.json, or browse all developer resources.

Need this decision tuned to your policy?

We are running a small number of pilots with B2B teams: your policy, your examples, your thresholds. Request early access.