Customer care¶
Solution
A ticket summary tells you what an agent typed after the call. It does not tell you what entitlement the customer actually had on the day they contacted you, or the exact words used in the email that promised a callback. Telha resolves entitlement and interaction state at the moment it mattered, with a citation back to the message itself.
The state questions customer care needs to answer¶
- What was the customer's entitlement (plan, SLA tier, add-ons) on the date they contacted us, not today?
- What did we tell them, in what channel, and when?
- Did this case breach its SLA, and what was the SLA at the time the case was opened?
- Who on our side made the promise, and can we find the exact message?
- What was the state of the customer's open cases the last time they escalated?
- Is there a conflict between what Slack says the team agreed and what the customer was actually emailed?
Entitlement changes; the case doesn't move with it
Plans and SLA tiers change over the life of an account. A case opened in January against a Gold-tier SLA should still read as Gold-tier when reviewed in June, even after a downgrade. That is atValidTime pinned to the case's open date, not "current state" applied retroactively.
flowchart LR
A["Case opened"] --> B["Query ENTITLEMENT<br/>atValidTime = case open date"]
B --> C{"SLA tier<br/>at that date"}
C --> D["Response promised<br/>in email or Slack"]
D --> E["Query MESSAGE<br/>expand SENT_BY"]
E --> F["Answer with [S1]/[S2]<br/>citations to CRM + message"] The same pattern (pin the entitlement to the case's open date, then pull the message that made the promise) answers most "what did we owe them, and what did we say" questions without a manual timeline reconstruction.
What to connect¶
Customer care usually spans three systems that never agree with each other on their own: the CRM record of what the customer is entitled to, the inbox where promises actually get made, and the internal channel where the team argues about what to do. Telha ingests all three into one graph so a single query can answer across them.
| Source | Shipped connector | What it feeds |
|---|---|---|
| Salesforce | Salesforce connector | Cases, entitlements, SLA fields, account plan/tier, as format=json records |
| Exchange connector | Customer-facing correspondence, ingested as format=email with immutable message ids | |
| Slack | Slack connector | Internal case discussion and escalations, ingested as format=json (SLACK_THREAD) |
| Policy and SLA documents (PDF/DOCX) | Uploaded via /v1/ingest (docling) | The SLA terms themselves, dated at their source-record time |
| Identity | Entra ID connector | Verified agent identity, for clarification routing and RBAC |
Run the Entra connector before the others. Salesforce, Exchange, and Slack principals (agents, requesters, approvers) resolve against the identity it establishes, and that same identity substrate is what clarification routing uses to find the right person to confirm an ambiguous promise date.
Example queries¶
All examples run against POST /v1/query. See the query language reference for the full grammar.
{
"find": "CASE",
"where": {
"status": { "$eq": "open" },
"priority": { "$in": ["high", "urgent"] },
"owner": { "$exists": false }
},
"limit": 100
}
{
"find": "ENTITLEMENT",
"where": { "account": { "$eq": "Aster Logistics" } },
"atValidTime": "2026-04-02T09:15:00Z"
}
{
"find": "CASE",
"where": { "caseNumber": { "$eq": "00145821" } },
"atValidTime": "2026-04-02T09:15:00Z",
"atTxTime": "2026-04-05T00:00:00Z"
}
{
"find": "MESSAGE",
"where": { "case": { "$eq": "00145821" } },
"vector": { "text": "callback within 24 hours", "model": "m1", "k": 10, "minScore": 0.5 },
"expand": ["SENT_BY"]
}
A verified answer in practice¶
Slack-style Q&A, as an agent might ask through the AI assistant:
Agent: What did we tell Aster Logistics about their refund, and when?
Telha: We told Aster Logistics the refund would be processed within 5 business days, in an email sent by the account's assigned agent on April 3, 2026 [S1]. At the time of that email, the account held a Gold-tier SLA entitling them to expedited refund handling [S2].
verification.status: verified· claim 1 → supported, span S1 (Exchange message, byte range of the sentence promising 5 business days) · claim 2 → supported, span S2 (Salesforce entitlement field, dated to the case's open date)
Both citations click through to the source: S1 opens the original Outlook message behind the agent's own login, S2 opens the entitlement record in Salesforce as it stood on April 3. Neither is reconstructed from a ticket note written after the fact, per the plan-generate-verify loop in verified answers.
When the promise date is ambiguous
If the email had said "we'll get this sorted early next week" with no fixed date, ingestion applies a best-guess interpretation at reduced confidence and opens a clarification: a one-tap Teams or Slack card to the agent who sent it, asking them to confirm the date. Any answer generated before that clarification resolves carries an explicit caveat rather than stating the date as settled.
Evidence and permissions¶
- Provenance to the exact message. Every "what did we tell them" claim carries provenance to the specific email or Slack message span it came from, not "a message in this thread."
- Deny-by-default RBAC. Case and entitlement access follows Entra group mappings; an agent not mapped to a queue or account team sees nothing for it.
- Field-level encryption. Fields declared classified (payment details, identity-verification answers) are encrypted before Telha core ever stores them, and stay out of indexing and vector search.
- Corrections preserve the trail. A corrected SLA tier or reassigned case writes a new fact version; the case's state as any earlier report saw it stays reconstructable at its original transaction time.
What this replaces
Instead of an agent stitching together a Salesforce tab, an Outlook search, and a Slack scroll to answer "what did we promise," the same question goes to /v1/generate once, and the answer arrives with the same citations an agent would have hunted down by hand, minus the hunting.