Skip to content
TheThinkLoop

Template - Revenue

Choice

Customer message routing

Which team should own a customer message: sales, customer success, support, or billing.

A choice decision for shared inboxes where one address receives purchase questions, onboarding requests, technical problems, and invoices.

The decision

ChoiceOne of the listed values, a confidence value, and a probability for every option.

Which team should own this customer message?

Choices

  1. •sales: New purchases, pricing, demos, and quotes.
  2. •customer_success: Onboarding, adoption, renewals, and expansion.
  3. •support: Troubleshooting and technical problems with the product.
  4. •billing: Invoices, payments, and refunds.

Evidence checks (asked in the same request)

  • Technical failure: The message reports an error, crash, or failed request.
  • Cancellation intent: The customer says they intend to cancel or not renew.

Expected output: One of the four values, a confidence value, and a probability for every option, 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.
is_customerbooleanNoWhether the sender is an existing customer. Helps separate sales from customer success.

Worked examples

  1. A new customer planning their rollout

    We signed last month and need help planning the rollout. Can someone run onboarding training for our 30 agents and share best practices?

    A careful reviewer would say: customer_success. An existing customer asking for onboarding and adoption help.

    Run this example
  2. A seat count dispute on an invoice

    Our invoice for October shows a charge for 50 seats but we only have 35. Please correct it.

    A careful reviewer would say: billing. An invoice correction.

    Run this example

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

How it works

This is often the first decision teams automate, and the one where generic routing products already do a reasonable job. What makes it yours is the definitions: where an expansion request goes, who owns a renewal with a technical blocker.

The cancellation check exists because a cancellation request sent to billing as a plan change is a lost save opportunity. Gate on it separately.

Human review and thresholds

Recommended review policy

Automate confident routes. Send low-confidence messages to a triage queue rather than guessing, since a wrong route costs a hand-off and a slower first response.

Choosing thresholds

Misroutes are cheap individually and expensive in aggregate. Measure the re-route rate per team after launch and adjust the bar for the teams where misroutes hurt most.

Starting automation threshold
75%
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

  • Messages that span teams get one owner. Decide in advance which team leads when a billing problem is caused by a product bug.
  • Four options is a deliberately small set. Each added team makes every boundary harder to hold.
  • The model doesn't know your team's capacity or working hours.

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.

account-team-routing.jsonjson
{
  "$format": "thethinkloop.template/v1",
  "slug": "account-team-routing",
  "title": "Customer message routing",
  "decides": "Which team should own a customer message: sales, customer success, support, or billing.",
  "question": {
    "name": "decision",
    "type": "choice",
    "instructions": "Which team should own this customer message?",
    "choices": [
      {
        "value": "sales",
        "description": "New purchases, pricing, demos, and quotes."
      },
      {
        "value": "customer_success",
        "description": "Onboarding, adoption, renewals, and expansion."
      },
      {
        "value": "support",
        "description": "Troubleshooting and technical problems with the product."
      },
      {
        "value": "billing",
        "description": "Invoices, payments, and refunds."
      }
    ]
  },
  "evidenceChecks": [
    {
      "name": "factor_1",
      "label": "Technical failure",
      "type": "predicate",
      "instructions": "The message reports an error, crash, or failed request."
    },
    {
      "name": "factor_2",
      "label": "Cancellation intent",
      "type": "predicate",
      "instructions": "The customer says they intend to cancel or not renew."
    }
  ],
  "inputs": [
    {
      "name": "message",
      "type": "string",
      "required": true,
      "description": "The customer's message, verbatim. Include the subject line if there is one."
    },
    {
      "name": "is_customer",
      "type": "boolean",
      "required": false,
      "description": "Whether the sender is an existing customer. Helps separate sales from customer success."
    }
  ],
  "expectedOutput": "One of the four values, a confidence value, and a probability for every option, plus one probability per evidence check.",
  "examples": [
    {
      "title": "A new customer planning their rollout",
      "input": "We signed last month and need help planning the rollout. Can someone run onboarding training for our 30 agents and share best practices?",
      "expected": "customer_success"
    },
    {
      "title": "A seat count dispute on an invoice",
      "input": "Our invoice for October shows a charge for 50 seats but we only have 35. Please correct it.",
      "expected": "billing"
    }
  ],
  "startingPolicy": {
    "automateAt": 0.75,
    "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 signed last month and need help planning the rollout. Can someone run onboarding training for our 30 agents and share best practices?",
  questions: [
    {
      type: "choice",
      name: "decision",
      instructions: "Which team should own this customer message?",
      choices: [
        {
          value: "sales",
          description: "New purchases, pricing, demos, and quotes."
        },
        {
          value: "customer_success",
          description: "Onboarding, adoption, renewals, and expansion."
        },
        {
          value: "support",
          description: "Troubleshooting and technical problems with the product."
        },
        {
          value: "billing",
          description: "Invoices, payments, and refunds."
        }
      ]
    },
    {
      type: "predicate",
      name: "factor_1",
      instructions: "The message reports an error, crash, or failed request."
    },
    {
      type: "predicate",
      name: "factor_2",
      instructions: "The customer says they intend to cancel or not renew."
    }
  ],
});

// 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 === "choice") {
  console.log(main.choice, main.confidence, main.probabilities);
}

Download it as account-team-routing.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.