Template - Support
PredicateBilling escalation
Whether a billing issue should leave the support queue and go to finance.
A predicate decision for billing conversations that carry financial or legal risk and should not wait in a general queue.
The decision
Should this billing issue be escalated to the finance team?
Evidence checks (asked in the same request)
- Duplicate charge: The customer reports being charged more than once.
- Legal or chargeback risk: The customer mentions a chargeback, bank dispute, or legal action.
- Repeat contact: The customer has contacted us about this before.
Expected output: A probability from 0 to 1 that the issue should be escalated, 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.
| Field | Type | Required | Description |
|---|---|---|---|
message | string | Yes | The customer's message, verbatim. Include the subject line if there is one. |
disputed_amount | number | No | The amount in question, if known from billing data. |
Worked examples
Repeated contact with a threatened bank dispute
This is the third time I've written about invoice #2291. You charged us $4,800 twice and I still have no response. If this isn't fixed this week I'll dispute it with my bank.
A careful reviewer would say: Yes. A large duplicate charge, repeated contact, and a threatened dispute all point to escalation.
Run this exampleRoutine invoice copy
Could you send me a copy of last month's invoice? Thanks!
A careful reviewer would say: No. A routine request any agent can complete.
Run this example
Expected answers are human judgments written for this template, not model output.
How it works
Most billing tickets are routine: copies of invoices, card updates, plan changes. A few carry real exposure, such as disputed charges or chargeback threats. This decision separates the two.
A chargeback threat is worth gating on by itself. The evidence check for legal or chargeback risk is often more useful than the headline probability.
Human review and thresholds
Recommended review policy
Escalation is itself a hand-off to a person, so automated "Yes" results are low-risk. The risk is in automated "No" results: sample them regularly to see what is being left in the general queue.
Choosing thresholds
A missed escalation can become a chargeback or a lost account, while an unnecessary one costs a few minutes of a finance person's time. That usually justifies a low bar for escalating.
- Starting automation threshold
- 80%
- Starting don’t-decide threshold
- 55%
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
- The amount at stake often isn't in the message. Add it from billing data when you have it.
- The model can't verify that a duplicate charge actually happened. Escalation means a person checks.
- Tone is not a reliable indicator of financial risk. Polite messages can describe serious billing errors.
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.
{
"$format": "thethinkloop.template/v1",
"slug": "billing-escalation",
"title": "Billing escalation",
"decides": "Whether a billing issue should leave the support queue and go to finance.",
"question": {
"name": "decision",
"type": "predicate",
"instructions": "Should this billing issue be escalated to the finance team?"
},
"evidenceChecks": [
{
"name": "factor_1",
"label": "Duplicate charge",
"type": "predicate",
"instructions": "The customer reports being charged more than once."
},
{
"name": "factor_2",
"label": "Legal or chargeback risk",
"type": "predicate",
"instructions": "The customer mentions a chargeback, bank dispute, or legal action."
},
{
"name": "factor_3",
"label": "Repeat contact",
"type": "predicate",
"instructions": "The customer has contacted us about this before."
}
],
"inputs": [
{
"name": "message",
"type": "string",
"required": true,
"description": "The customer's message, verbatim. Include the subject line if there is one."
},
{
"name": "disputed_amount",
"type": "number",
"required": false,
"description": "The amount in question, if known from billing data."
}
],
"expectedOutput": "A probability from 0 to 1 that the issue should be escalated, plus one probability per evidence check.",
"examples": [
{
"title": "Repeated contact with a threatened bank dispute",
"input": "This is the third time I've written about invoice #2291. You charged us $4,800 twice and I still have no response. If this isn't fixed this week I'll dispute it with my bank.",
"expected": "Yes"
},
{
"title": "Routine invoice copy",
"input": "Could you send me a copy of last month's invoice? Thanks!",
"expected": "No"
}
],
"startingPolicy": {
"automateAt": 0.8,
"abstainBelow": 0.55,
"note": "A starting point for exploration, not a recommendation. Calibrate against your own labeled examples."
}
}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: "This is the third time I've written about invoice #2291. You charged us $4,800 twice and I still have no response. If this isn't fixed this week I'll dispute it with my bank.",
questions: [
{
type: "predicate",
name: "decision",
instructions: "Should this billing issue be escalated to the finance team?"
},
{
type: "predicate",
name: "factor_1",
instructions: "The customer reports being charged more than once."
},
{
type: "predicate",
name: "factor_2",
instructions: "The customer mentions a chargeback, bank dispute, or legal action."
},
{
type: "predicate",
name: "factor_3",
instructions: "The customer has contacted us about this before."
}
],
});
// 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 === "predicate") {
console.log(main.probability); // 0–1 estimate that the condition is true
}
Download it as billing-escalation.json, or browse all developer resources.
Need this decision tuned to your policy?
Related
- Predicate template
Refund eligibility
Whether a refund request should be approved under your written refund policy.
- Predicate template
Support escalation
Whether a conversation should move from a frontline agent to a senior one.
- Choice template
Customer message routing
Which team should own a customer message: sales, customer success, support, or billing.
- Guide
AI decision routing
A routing decision is several smaller decisions plus a rule that combines them. How to design that rule, where people fit, and what to log.
- Guide
Confidence thresholds
Probability, confidence, accuracy, calibration, and correctness are different things. How to set a review policy from the cost of each kind of mistake.
- Guide
Human-in-the-loop AI
When should AI decide and when should it ask? Review patterns, what reviewers need to see, sizing the queue, and keeping oversight real.