# Chat Widget Agent
Source: https://docs.decimal.app/agents/chat-widget
Answer end users directly in the widget embedded on your site.
The Chat Widget answers the people using your product, through the widget you embed on your site. It's the only one that talks to end users without a teammate in between, so its [tone and voice](/agents/tone-voice) is worth setting deliberately rather than leaving on the default.
Open **Agents** and select **Chat Widget**, where you can configure its tone and voice.
For the requests your team handles the same way every time, a [policy](/policies) takes the agent through your procedure step by step instead of leaving it to answer from your knowledge base.
Everything else about the widget lives under [Chat Widgets](/chat-widgets/overview): installing it, verifying who your users are, and reading the [conversations](/chat-widgets/conversations) it has had.
# Investigation Format
Source: https://docs.decimal.app/agents/investigation-format
Define the sections the agent's investigation summary follows, publish the template, and roll back a version that didn't work.
Open **Agents**, select **Support Agent**, then **Investigation Format**. This is the shape of the investigation summary your team reads on a ticket, not the customer-facing reply.
Only the Support Agent has this tab, since it's the only agent that writes an investigation summary.
## Sections
Each section has a **name**, which becomes the heading in the summary, and a **description** telling the agent what belongs under it. The description is where the work happens: "Root Cause" means little on its own, while "the specific code path or config that produced the behavior, or say you couldn't determine it" tells the agent what you expect.
Sections are numbered in the order the agent writes them. **Add section** appends one, and **Start from** drops in a ready-made set: **Dynamic**, **Sections**, **Q\&A**, or **RCA**. Leave the sections empty and the agent falls back to a single-section summary.
The published sections also appear as the parts you can include under [Reply Content](/support/reply-content), and you can see the result on a real ticket in [Ticket Detail](/support/ticket#reading-the-answer).
## Publishing
Edits stay a draft until you press **Publish**, and an **Unsaved changes** bar sits at the bottom of the page until you do, with **Discard** next to it. The agent follows the published template on its next run, so an in-progress rewrite never reaches a ticket.
## Version History
Every publish is kept as a numbered version with the summary of what changed, who published it, and when. The version in use is marked **Current**. On any older version, **View diff** shows what changed from the one before it, and you can roll back to it from there.
# Agents
Source: https://docs.decimal.app/agents/overview
The agents in your workspace, what each one answers, and where to configure them.
**Agents** in the sidebar lists every agent in your workspace. Open one to set its [tone and voice](/agents/tone-voice), and, for the agents that have them, its own settings.
Only organization administrators can open **Agents**. Your teammates still work tickets in [Support](/support/overview) as usual.
| Agent | What it answers |
| -------------------------------------- | ------------------------------------------------------------ |
| [Support Agent](/agents/support-agent) | Support tickets, with an investigation behind each answer |
| [Slack](/agents/slack) | Questions in Slack DMs and channels |
| [Chat Widget](/agents/chat-widget) | End users in the widget on your site |
| [Playground](/agents/playground) | Your own team's questions across every connected data source |
The switch in the top right of an agent's page turns it on and off. Switch it off and that agent stops answering, while your configuration stays as you left it.
# Playground Agent
Source: https://docs.decimal.app/agents/playground
Answer your own team's questions across every connected data source.
The Playground answers your team, not your customers. It reaches across every connected source, so it's the one to ask when you want to explore the codebase, find what the knowledge base already says, or work through a problem before a ticket exists.
Open **Agents** and select **Playground**, where you can configure its [tone and voice](/agents/tone-voice).
[Playground](/playground/overview) covers its usage: setting which repositories it searches, pinning tickets or articles as context, attaching files, and saving an answer as a knowledge base article. It can also answer questions about your own support history, which [Ask Data](/playground/ask-data) covers.
# Public Agent
Source: https://docs.decimal.app/agents/public-agent
A second agent that answers your customers directly, grounded only in what is already public about your product.
This feature is enabled per workspace. [Email us](mailto:support@getdecimal.ai?subject=Enable%20Public%20agent) to turn it on. If you don't see a **Routing** tab on the Support Agent, it isn't on yet.
Most tickets in your queue are answered by the **private agent**: it investigates across everything you've connected, then hands your team a draft. The **public agent** is a second agent that works differently. It answers the customer directly, and it is only allowed to use information a customer could already have found on their own.
That restriction is the point. An answer built only from your public documentation and public code is an answer that is safe to send without a person reading it first.
## Two Agents, Two Evidence Bases
Both agents can run on the same ticket. What separates them is what they are allowed to look at, and who reads the result.
| | Private agent | Public agent |
| ------------------- | ----------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------- |
| **Sources** | Everything connected: internal and public knowledge base, private and public repositories, logs, warehouses, past tickets, payments | Public knowledge base articles, public repositories, your status page |
| **Audience** | Your support team | Your customer |
| **Default outcome** | A draft your team reviews and sends | A reply the customer receives |
| **Best at** | "Why did this specific account break?" | "How do I do X?" |
The private agent is the stronger investigator. It can trace a failing request through your logs and tell you which customer record is wrong. The public agent cannot do any of that, and it is not meant to. It exists to clear the large share of your queue that never needed an investigation in the first place.
## What the Public Agent Can See
The public agent has a deliberately short list of sources:
* **Public knowledge base articles.** Only articles marked **Public** in your [knowledge base](/knowledge-base/manage-articles). Anything left private is invisible to it, including every investigation note your team has written.
* **Public code repositories.** Only repositories that are public on GitHub, GitLab, or Bitbucket. If all of your connected repositories are private, the public agent works from the knowledge base alone.
* **Your status page**, if your workspace has one configured. When a customer reports that something is broken and an incident is live, the agent points them at the status page rather than guessing.
It has no access to internal tickets, private repositories, observability data, data warehouses, payment records, or any of the other tools the [private agent](/agents/tools) can call.
## Every Answer Is Verified
The public agent does not get to decide on its own that an answer is good enough. Before anything is delivered, a separate verifier reads the drafted reply and checks it sentence by sentence against the sources the agent cited.
Three things can happen:
* **The answer holds up.** Every claim traces back to a cited source, and the reply goes out as written.
* **Part of it doesn't hold up.** The verifier rewrites the answer down to the parts that are supported, dropping the rest.
* **Too little survives.** The verifier blocks the reply. Nothing goes to the customer. The draft lands on the ticket as an internal note instead, and the ticket waits for your team like any other.
The agent is also held to a strict citation rule: every claim it makes must be traceable to a specific article or file. If it cannot cite a claim, it is not allowed to make it.
## How Its Replies Are Signed
A public agent reply goes to the customer under your team's name, so what sits at the bottom of it matters more here than it does on a draft your team reads before sending. **Signature rules** decide that.
Open **Agents**, select **Support Agent**, go to the **Replies** tab, and find **Signature**. Each rule reads as a sentence you assemble from dropdowns:
> When the **public agent** replies **in category** Billing question, sign **as** Sarah or Ada.
* **Which agent it covers.** Rules are written per agent, so the public agent can sign differently from the drafts your team sends out.
* **When it applies.** To any ticket, to tickets in specific [routing categories](/agents/routing), or to tickets on specific channels.
* **How it signs.** As one or more **teammates**, with **custom text** you write, or with **no signature** at all.
Rules are read top to bottom and **the first match wins**, so put your specific rules above your general ones. Each rule has its own switch, you can reorder them with the arrows, and you can keep up to 20.
### Signing as a Teammate
Choosing a teammate signs the reply with that person's [reply signature](/support/preferences#your-reply-signature), rendered with their name.
Choose more than one and Decimal picks between them per ticket. The pick is stable rather than random: the same ticket always resolves to the same signer, so a follow-up on a thread is signed by whoever signed the first reply rather than by a different name each time.
Signing as a named teammate is most of what makes an automated reply read like it came from your team. Pair it with a [response delay](/agents/routing#response-delay) on the category and the reply arrives signed by a person, at a pace a person could have worked at.
If a teammate you picked has no reply signature configured, that rule is skipped and the next matching rule applies. If no rule matches at all, the agent signs off however its [tone and voice](/agents/tone-voice) leads it to.
## Public Agent vs Full Autonomy
These two features both end with a customer receiving a reply nobody on your team typed, which is why they get confused. They solve different problems and they work independently.
| | Public Agent | [Full Autonomy](/support/full-autonomy) |
| --------------------------- | --------------------------------------------------------------- | --------------------------------------------------------- |
| **The question it answers** | Which agent should answer this ticket? | Should the private agent's draft be sent without a human? |
| **Whose answer goes out** | The public agent's | The private agent's |
| **Evidence behind it** | Public sources only | Everything you've connected, internal data included |
| **What holds it back** | The verifier, plus the [routing](/agents/routing) rules you set | The verifier, your guardrails, and a confidence threshold |
The clean way to hold the difference: **Full Autonomy changes who presses send. The public agent changes who writes the reply, and what they were allowed to read while writing it.**
You can run either one alone, or both together. When both are on, [routing](/agents/routing) decides which agent's answer is the candidate for the customer, and Full Autonomy governs the private drafts that routing keeps in-house.
## Turning It On
1. **Open the Settings tab.** Go to **Agents**, select **Support Agent**, then **Settings**.
2. **Turn on Run the public agent.** From here the public agent starts drafting alongside the private agent.
3. **Open the new Routing tab.** Turning the public agent on adds a **Routing** tab to the Support Agent, where you decide which kinds of tickets it is trusted to answer.
4. **Define your categories in Preview.** New categories start in **Preview**, so the public agent drafts real answers and posts them as internal notes without any of them reaching a customer. See [Routing](/agents/routing).
5. **Read the previews on real tickets.** Give it a week of live traffic and read what it would have sent.
6. **Switch the categories you trust to Live.** Move them one at a time rather than all at once.
The public agent is only as good as your public knowledge base. If the previews are thin, that is usually a signal about your documentation rather than about the agent. [KB gap detection](/knowledge-base/kb-gap-detection) will tell you which articles are missing.
## What You See on the Ticket
Every public agent run is recorded on the ticket, whether or not the customer saw it.
* **In Preview**, the drafted answer posts as an internal note headed **Public Agent Response**. Your team sees exactly what would have gone out.
* **In Live**, the answer is posted as a reply to the customer, and the ticket shows it as the reply that was sent.
* **When the verifier blocks a reply**, the draft posts as an internal note and the ticket is left for your team.
## When the Public Agent Stands Down
The public agent does not answer every ticket it drafts for. It steps aside when:
* **A teammate has already replied.** The agent never sends over a human.
* **The verifier blocked the answer.** Covered above.
* **The customer is asking for a person**, or is visibly frustrated with automated replies. The ticket is handed to your team.
* **Someone mentions Decimal directly** on the ticket. A direct mention is a request for the investigating agent, so the ticket goes private.
* **The conversation was escalated from a [chat widget](/chat-widgets/overview).** The widget already tried the public path, so the ticket arrives on your team's side of the line.
* **Your [routing](/agents/routing) rules send it elsewhere.** A category that routes to the private agent, or a router decision that the thread now needs more oversight.
In each of these cases the work is not thrown away. The draft is still on the ticket, and the private agent's investigation is still there for whoever picks it up.
# Routing
Source: https://docs.decimal.app/agents/routing
Routing categories decide which tickets the public agent may answer, how its replies are delivered, and how long it waits before sending.
The **Routing** tab appears once the [public agent](/agents/public-agent) is enabled for your workspace. Without a public agent there is nothing to route between.
Once you have two agents, every ticket needs an answer to one question: who takes this one? **Routing categories** are how you answer it in advance, in your own words, for the kinds of tickets you actually get.
A category is a description of a recurring kind of ticket, plus a decision about how it should be handled. "Password reset requests go to the public agent, live." "Anything about billing goes to a human." "Bug reports get drafted by both agents, and we'll see which answer is better."
Open **Agents**, select **Support Agent**, then **Routing**.
## How a Ticket Gets Routed
Routing runs on every turn of a conversation, not just when the ticket arrives. A thread that started simple can stop being simple, and the routing follows it.
1. **The router reads the thread** and matches it against your approved categories. It judges the ticket on what the customer needs right now, not on the tone or the length of the message.
2. **The matched category sets the starting point.** A category that routes to the public agent starts the ticket there.
3. **The router can add oversight, never remove it.** From that starting point it asks whether this particular conversation has gone somewhere that needs more human involvement: an answer that didn't land, a question asked twice, a request that now turns on a decision only your team can make. It can move a ticket from public to both, or from either to private. It can never move a ticket the other way, so a category that routes to your team stays with your team.
4. **The agents run.** Which ones depends on the decision.
5. **When both ran, a comparison step picks the winner.** It reads both drafts and asks whether the private agent found something the public agent could not. If it did, the ticket stays internal.
6. **The reply is delivered** according to the category's delivery setting and response delay.
## Where a Category Can Route
**Routes to** is the core setting on a category. It has three values.
| Routes to | What runs | What the customer gets |
| ----------------- | ---------------------- | ------------------------------------------------------------------------------------------------------------------------------ |
| **Public agent** | Only the public agent | Its answer, subject to the verifier and your delivery setting |
| **Private agent** | Only the private agent | Nothing automatic. Your team reviews the draft and replies |
| **Both agents** | Both, in parallel | Whichever answer the comparison step picks. The public answer only wins if it covers the ticket as well as the private one did |
## Creating a Category
Click **Add category** to open the editor.
### Name and Description
Write the **Name** the way your team would say it out loud: "Billing refund request", "SSO setup question". The **Description** is where you say when the category applies. Be concrete about the boundary, because that is what the router leans on when a ticket sits between two categories.
### Example Tickets
Pick real tickets from your own history that belong in this category. They are not used for matching at runtime. They are fed to the model when it writes the AI definition below, and a handful of real examples does more for accuracy than another paragraph of description.
### AI-Enhanced Category Definition
Click **Generate** and Decimal expands what you wrote into the fuller definition the router actually reads: a classification description and a set of example phrasings.
You can open it, edit any part of it by hand, and save. If you later change the name, description, or example tickets, the definition is marked **Out of date** and the button becomes **Regenerate**. Regenerating overwrites manual edits, so Decimal asks you to confirm when it would.
A category cannot be saved or approved until this definition has been generated.
### Status
| Status | What it does |
| --------------------- | -------------------------------------------------------------------------------- |
| **Suggested (draft)** | Saved, but ignored by the router. Use it to draft a category before you trust it |
| **Approved** | Live. The router will match tickets against it |
Only approved categories with a generated definition are used for routing. You can approve a category from the list with the checkmark, or from the editor.
## Delivery: Preview and Live
Categories that route to the public agent (**Public agent** or **Both agents**) get a **Delivery** setting. This is the safety valve, and it is per category rather than per workspace.
* **Preview** (the default for every new category): the public agent does the full job, and its answer posts to the ticket as an internal note. Nothing reaches the customer. This is sometimes called shadow mode.
* **Live**: the answer is sent to the customer.
Every category starts in **Preview** on purpose. Leave it there through a full cycle of real traffic, read the notes it produces, and promote one category at a time. Preview is the only way to see how a category behaves on tickets you didn't think of when you wrote it.
Delivery is a floor, not a guarantee. A category set to **Live** still produces an internal note instead of a customer reply when the verifier blocks the answer, when a teammate has already replied, or when the router or comparison step moves the ticket to the private agent.
## Response Delay
An answer that lands a second after the customer hits send reads as a machine, however good the answer is. No person types that fast, and customers notice.
**Response delay** holds the reply for a set number of minutes so it arrives at a pace a teammate could plausibly have worked at. Set it up to **60** minutes, or leave it empty to reply as soon as the answer is ready.
The details worth knowing:
* **The clock starts at the customer's most recent message**, not at the moment the agent finished working. A five minute delay on an answer that took four minutes to produce sends one minute later, not five.
* **If the delay has already passed** by the time the answer is ready, the reply goes out immediately.
* **If the customer writes again during the delay, the pending reply is dropped.** The agent reprocesses the thread including the new message and answers the whole thing, rather than sending a reply to a question the customer has already moved past.
* **The delay applies in Preview too.** It holds the turn, so the internal note also waits.
Response delay is available on categories that route to the public agent. It has no effect on **Private agent** categories, whose replies are sent by your team anyway.
## When No Category Matches
The router returns no category when nothing in your list describes the ticket. What happens next depends on your workspace.
By default, an uncategorized ticket goes to **both agents** and the comparison step decides. If your workspace has automatic routing enabled, the comparison step is allowed to send a public reply on a ticket that matched no category at all.
That is the case the **Daily auto-routed public reply limit** exists for. It caps how many uncategorized tickets can receive a public reply in a rolling 24 hour window, and it defaults to **30**. Tickets that matched an approved public category are not counted against it, so the limit constrains only the tickets you never wrote a rule for. Once the cap is reached, uncategorized tickets fall back to your team until the window rolls forward.
Raise it as your categories get better and your confidence grows. Lower it, or set it to 1, if you want the public agent to answer only tickets you have explicitly described.
## What Overrides a Category
A category states an intent. Several things can still pull a ticket toward more human involvement, and none of them can push it the other way.
| Trigger | Result |
| --------------------------------------------------------------------------- | ---------------------------------------- |
| The customer asks for a person, or is frustrated with automated replies | Private agent |
| The router judges the thread now needs more oversight | Moved up one or two steps |
| The comparison step finds the private agent added something real | Private agent |
| The verifier blocks the public answer | Internal note, ticket left for your team |
| A teammate has already replied on the ticket | The agent stands down |
| Someone mentions Decimal directly on the ticket | Private agent |
| The conversation was escalated from a [chat widget](/chat-widgets/overview) | Private agent |
| The daily auto-routed limit is reached, on an uncategorized ticket | Private agent |
## A Suggested Rollout
1. **Start with your three most repetitive ticket types.** Look at what your team answers with near-identical wording every week. Those are the categories worth writing first.
2. **Choose a routing target for each one.** **Public agent** runs the public agent alone, which is the direct choice when you already know the answer lives in your documentation. **Both agents** runs both and shows you which draft the comparison step preferred. Either way, leave the category in **Preview** to start.
3. **Read the previews for a week.** You are checking one thing: would you have sent that?
4. **Switch the categories you trust to Live.** One at a time.
5. **Add a response delay** on the categories where an instant reply would feel out of place.
6. **Write private categories for the things you never want automated.** Billing disputes, security reports, anything with a contractual edge. A category that routes to the private agent is a rule the router cannot talk itself out of.
7. **Revisit the daily limit** once your categories cover most of your volume.
# Support Agent Settings
Source: https://docs.decimal.app/agents/settings
Decide which tickets the Support Agent answers, how many times it can reply, and what it may do without a human.
Open **Agents**, select **Support Agent**, then **Settings**. The [Slack agent](/agents/slack) has its own settings, unrelated to these.
## Skip Rules
Skip rules run before the agent does, so a skipped ticket costs nothing and never gets a draft. Each rule has its own switch, so you can keep a list without applying it.
* **Skip tickets from these senders**: an address or a whole domain. Enter `@acme.com` for everything from that domain, or a full address for one person. Use it for internal teammates, no-reply addresses, and vendors.
* **Skip tickets with these subject lines**: matches a phrase anywhere in the subject, one phrase per line. Replies that come back as "Re: ..." are caught too, so a campaign blast you want to handle by hand stays out.
* **Skip Slack-sourced tickets**: useful when your Slack tickets route through another system first and you'd rather the agent answered them there.
* **Drop messages from these author IDs**: hides individual messages, not whole tickets, before the agent reads them. Paste the platform's user ID for an automated agent or internal bot.
## Response Limits
**Maximum AI responses per ticket** is three by default. Once the agent hits the cap it stops replying to new messages on that ticket, which is what breaks the loop when a customer's automated mailer answers every reply.
## Public Agent
**Run the public agent** lets a second agent answer the customer directly using only publicly available information about your product. Left off, only the private agent runs and every answer stays internal for your team to send.
Turning it on adds a **Routing** tab to the Support Agent, where you decide which kinds of tickets it may answer. See [Public Agent](/agents/public-agent) and [Routing](/agents/routing).
## Auto Acknowledgement
If your workspace has it, the agent posts an immediate holding reply while it investigates, so the customer knows the ticket landed. The message is yours to edit.
## Refund Controls
These appear only when [Stripe](/integrations/stripe) is connected.
**Let the agent handle refunds** is the master switch. Off, the agent can still look payments up but never refunds. On, you choose how far it goes:
* **Approval**: **Recommend** has the agent propose a refund for an admin to approve from the ticket, so nothing leaves your Stripe account until someone clicks. **Issue** lets it refund on its own.
* **Only admins can approve refunds**: off, any member can approve a recommended refund and send it to Stripe.
* **Maximum amount per refund**: above this the agent recommends instead of issuing, even in **Issue** mode.
* **Maximum refunds per 24 hours**: after this many, it falls back to recommending.
# Slack Agent
Source: https://docs.decimal.app/agents/slack
Answer support questions in Slack, and control when the bot engages and what it says when it can't help.
In Slack, Decimal answers support questions in direct messages to the bot and in channels where someone has invited it. This needs the [Slack integration](/integrations/slack) connected first.
Open **Agents**, select **Slack**, then set its [tone and voice](/agents/tone-voice) or the settings below.
* **Reply to direct messages** controls whether a DM to the bot gets a real answer. Turn it off and DMs get your default response instead.
* **Monitor tagged threads** keeps the bot in a conversation once someone has mentioned it. On, it answers follow-ups in that thread without being mentioned again. Off, every question needs its own mention.
## Default Response
When the bot isn't answering somewhere, this is what it says instead. Write it as a message to the person who asked, and use variables like `{{user.first_name}}` to address them by name.
You can also name a fallback channel by its Slack channel ID, to point people at the place your team does want the question asked.
# Support Agent
Source: https://docs.decimal.app/agents/support-agent
The agent that investigates and answers support tickets, and everything you can configure about how it works.
The Support Agent picks up tickets as they sync, investigates them across your connected sources, and drafts an answer for your team. [Ticket Detail](/support/ticket#reading-the-answer) shows what that looks like on a ticket.
Open **Agents** and select **Support Agent**. It has more configuration than the other agents, spread across its tabs.
| Tab | What you set |
| ---------------------------------------------------- | ---------------------------------------------------------------------------------------------------- |
| [Tone & Voice](/agents/tone-voice) | How its replies read |
| [Investigation Format](/agents/investigation-format) | The sections its investigation summary follows |
| [Settings](/agents/settings) | Which tickets it answers, how often it replies, and what it may do without a human |
| [Reply Content](/support/reply-content) | What it posts on the ticket |
| [Full Autonomy](/support/full-autonomy) | Whether it sends replies to customers itself |
| [Routing](/agents/routing) | Which tickets the [public agent](/agents/public-agent) may answer, and how its replies are delivered |
| [Tools](/agents/tools) | Which external capabilities it can call |
**Routing** appears only when the [public agent](/agents/public-agent) is enabled for your workspace.
**Tone & Voice** and **Investigation Format** hold a draft while you edit, and the agent keeps using the published version until you press **Publish**. Both keep a version history you can compare and roll back to. The rest saves as you change it and applies on the agent's next run.
# Tone & Voice
Source: https://docs.decimal.app/agents/tone-voice
Set how the agent's replies read, using a preset or your own written instructions, and publish the change when you're ready.
Open **Agents**, select an agent, then **Tone & Voice**. This shapes how replies read, not what the agent investigates.
For example, you might make the Chat Widget warmer for the end users it talks to, and keep the Support Agent brief and direct for your team.
## Presets
Pick a starting point:
* **Technical**: precise and direct, for developer-facing support.
* **Friendly**: warmer and more conversational.
* **Concise**: shortest answer that resolves the ticket.
* **Empathetic**: leads by acknowledging the customer's situation.
* **Custom**: start from an empty box and write your own.
Selecting a preset fills the instructions with its wording, which you can then edit.
## Instructions
The instructions are plain language, applied to every reply the agent drafts. Write the things a new teammate would need to be told: sign-offs to use or avoid, words your customers don't know, whether to apologize, how formal to be.
## Publishing
Your edits stay a draft until you press **Publish**, so the agent keeps using the last published version while you work.
Under the version history, each version shows what changed. Compare any version against the one before it, and roll back if a change made replies worse.
If your workspace has the public agent turned on, you can give it a separate tone from the internal one and resync the two later.
# Tools
Source: https://docs.decimal.app/agents/tools
Choose which external capabilities the Support Agent can call while it investigates a ticket.
Open **Agents**, select **Support Agent**, then **Tools**. Each tool is a capability the agent can call while investigating: searching your code, querying logs, looking up a customer in your warehouse, reading a knowledge base article.
Only the Support Agent has this tab. The other agents don't expose tool controls.
Turn a tool off and the agent stops calling it, even if the integration behind it stays connected. The count in the top right is how many are on.
Tools appear here once the integration that provides them is connected, so the list grows as you add [integrations](/integrations/overview). An empty list means nothing is connected yet.
Turning a tool off narrows what the agent can find, which shows up as thinner investigations rather than an error. You can see which tools an investigation used on the ticket itself, under [Ticket Detail](/support/ticket#reading-the-answer).
# Get conversation
Source: https://docs.decimal.app/api-reference/chat/get-conversation
/openapi-v0.yaml get /v0/chat/{conversation_id}
Returns the conversation with all messages. Use this to poll for completion
after sending a message, checking the top-level `status` field.
# Send a message
Source: https://docs.decimal.app/api-reference/chat/send-a-message
/openapi-v0.yaml post /v0/chat
Send a message to get an AI-powered response. Omit `conversation_id` to
start a new conversation, or provide one to continue an existing conversation.
Returns `202 Accepted` immediately. The AI processes in the background.
Poll `GET /v0/chat/{conversation_id}` until `status` is `completed`.
# Escalate to ticketing integration
Source: https://docs.decimal.app/api-reference/escalation/escalate-to-ticketing-integration
/openapi-v0.yaml post /v0/chat/{conversation_id}/escalate
Escalate a completed conversation to an external ticketing integration
(Plain, Pylon, or Linear). Creates a ticket with the conversation transcript
and AI-generated summary.
Can only be called once per conversation. Subsequent calls return `409 Conflict`.
# Get current token info
Source: https://docs.decimal.app/api-reference/utility/get-current-token-info
/openapi-v0.yaml get /v0/me
Returns information about the authenticated API token and organization.
# Changelog
Source: https://docs.decimal.app/changelog
New features, improvements, and fixes in Decimal.
[August 2026](#august-12-2026)
[July 2026](#july-31-2026)
[June 2026](#june-25-2026)
[May 2026](#may-2026)
[April 2026](#april-2026)
[March 2026](#march-2026)
[February 2026](#february-2026)
## Connect Auth0, Clerk, or WorkOS
Identity questions no longer mean leaving the ticket. Connect your provider from **Settings → Integrations** and the agent checks SSO and directory sync while it investigates. See [Auth0](/integrations/auth0), [Clerk](/integrations/clerk), and [WorkOS](/integrations/workos).
## Secure links, roadmap answers, and your warehouse
The agent reads what a customer sent through a [SendSafely](/integrations/sendsafely) link, instead of stopping at the link. Before it tells someone a feature doesn't exist, it checks [Canny](/integrations/canny) for the idea, with status, votes, and any ETA. [BigQuery](/integrations/bigquery) answers the number a ticket turns on, and [Solana](/integrations/solana) looks up a Mainnet transaction by signature.
## Resize the ticket list to fit your work
Drag any column border, double-click to reset, and your widths are waiting next time. Titles fit now too: the Ticket column starts wider.
## Transcripts say what the agent did
A tool step names the log group it searched or the term it looked for, instead of handing you a result count and leaving you to guess.
## Format a signature the way you'd expect
Select text and press **⌘B**, **⌘I**, or **⌘U**. Paste a link over a selection and it becomes a hyperlink. The preview shows exactly what your customer will see. Markdown typed by hand used to sit there as literal text, which was easy to mistake for broken.
## Sharper answers in Ask Data
Ask something with an exclusion in it and you get one exact answer rather than an approximation. See [Ask Data](/playground/ask-data).
Zendesk connections also hold up under heavy API traffic, and can idle 60 days instead of 30.
## Refunds check who actually paid
Before issuing one, the agent compares the email that opened the ticket with the email on the payment. If they differ, the refund waits for a human, and the approval screen shows you both. Amounts now read **\$206.00** rather than 20600. See [Stripe](/integrations/stripe).
## Follow an article back to its ticket
Hover the linked ticket to see its number, title, status, and assignee. **For you** remembers your choice across refreshes, and you can decide what it means under **Settings → Preferences**.
## The ticket you searched for comes first
Search the list and the closest match sits at the top, instead of behind whatever arrived most recently. Column headers still sort explicitly, and clearing the search puts things back.
## Templates worth trusting, and a key for your voice
Break ticket volume down by account or requester. Customer hotspots drops spam and test tickets, so your top accounts are the real ones. One for the keyboard crowd: hold **Option** for push-to-talk, or tap it for hands-free.
## Charts worth looking at
Line charts have lost the white gap that sat at every data point. Hovering highlights the point you're on, and a full-size chart now sits in its own titled card, which helps when one answer carries several.
## Drafts that don't guess
When the agent drafts an acknowledgment, it reads your articles first, and it can't claim a feature, price, policy, or timeline that nothing backs up. Found nothing relevant? It acknowledges the message and stops there. These stay drafts for your team.
## Titles that tell you what happened
A conversation names itself while the answer is still streaming, something like "Stripe webhook signature verification failing". A title you set by hand always wins.
Admins can turn the public agent on or off in **Settings**.
## Zendesk over OAuth
Authorize through Zendesk's own login instead of minding an API token, and tokens refresh themselves. Already on a token? Move across without losing your sync settings. See [Zendesk](/integrations/zendesk).
**Yolo mode** is now called **Full autonomy**, which describes the toggle rather better. See [Full Autonomy](/support/full-autonomy).
## Article diffs you can actually read
Code blocks keep their special characters, ordered lists keep their numbering, and headings stop duplicating themselves halfway down.
## One Slack message, not two
Reasoning and answer now arrive together. With [ClickHouse](/integrations/clickhouse) connected, the agent finds and queries your log tables mid-investigation, and shows you the SQL it ran.
## Compare article edits the way you'd read them
The **diff** view now renders the whole article: headings, lists, code blocks. Changes show inline, green for an addition, struck-through red for a removal. Before this you got raw HTML tags and a few lines of context, and guessed at the rest.
## ClickHouse joins the logs integrations
Add your endpoint, credentials, and database under **Settings → Integrations** and map your columns, without picking a single table up front. See [ClickHouse](/integrations/clickhouse).
## Make the widget sound like you
Set your own header title and greeting from the embed snippet: add `headerTitle` and `greeting` to your `Decimal.theme()` call and the widget uses your wording instead of the default. A greeting with no subtitle collapses to a single line.
## Connect Intercom in one click
Connecting Intercom is now a **Connect with Intercom** button and an OAuth handshake, with no API key to copy. Already on a key? **Switch to OAuth** swaps it over and keeps your synced history. See [Intercom](/integrations/intercom).
## Attachments survive an escalation
Attach a screenshot or a log file to a ticket you escalate and it lands on the Jira issue as a real attachment. They were failing silently as a **415** before.
## Escalations file as the right issue type
A ticket tagged **Task** now creates a **Task**, rather than everything landing as a **Bug**. One for the triage queue: readiness checks run first, so an under-specified ticket comes back for detail before an issue exists.
## Hand over your MCP server's tools one at a time
After a connection test, check off only the tools the agent may use, with **Select all** if you change your mind. Reopen it later and your choices are already ticked. See [MCP Servers](/integrations/mcp).
## Notion pages inside toggles and columns sync
A page shared from inside a toggle, column, or callout used to vanish from both the sync and the shared list. It shows up now. See [Notion](/integrations/notion).
## Decide whether a re-run writes back
**Configure Re-run** has a new **Write to external system** checkbox. Leave it clear and the re-run stays local, a scratchpad for trying a different answer. Check it and the result flows to your ticketing system. Your everyday runs still write back automatically.
## Oodle links land in your region
Log explorer links point at **US1** or **AP1** instead of a subdomain that never resolved, and the connect screen now has a region picker. See [Oodle](/integrations/oodle).
## Two more log integrations: Render and Sumo Logic
Add **Render** under Observability with your **API Key** and the workspace ID starting `tea-`, or **Sumo Logic** with your region and access keys. Either way the agent pulls those logs into an investigation the way it already does for Datadog. See [Render](/integrations/render) and [Sumo Logic](/integrations/sumologic).
## Filter tickets by type and portal visibility
The filter dropdown gained **Type**, with a live count beside each one, and **Customer Portal**. Both apply to CSV exports, and both live in the URL, so a filtered view is something you can send a teammate.
## Long links stop breaking a conversation
A long URL from a log tool used to spill across the page. It now collapses into a **View link** chip, with the full address on hover, both in Slack and in the app.
## Fewer fields for Oodle, more control over Zendesk
Oodle takes two fields now, your instance and an API key, and fetches index patterns itself. On Zendesk, a field picker searches your live field list so you can leave custom fields out of a sync.
## Share a screenshot and the bot reads it
Drop an image or a PDF into a Slack thread and the bot looks at it: screenshots through vision, PDFs by pulling out their text, scanned pages as images. A file sent with only a short caption used to be skipped.
## Keep the agent out of a campaign's replies
**Support Agent Settings** gained **Skip tickets with these subject lines**. Paste in a phrase from the blast and every reply, `Re:` threads included, waits for a human. Your list stays put if you turn it off.
[Stripe](/integrations/stripe) also joined the integrations list this week, so the agent can verify a customer and find the payment a ticket is about.
## Work tickets from Slack
Ask the bot for a ticket by ID, or search your tickets without leaving the conversation.
## Auto-close, beyond the pilot
Auto-close and auto-acknowledgement opened up past the workspaces that trialled them. API keys moved to **Settings → API Keys**.
## Every agent, configured its own way
Tone presets, an on and off switch, and a Tools tab for turning individual tools off. See [Agents](/agents/overview).
## Speak to a widget, read it in English
Customers can talk instead of typing, and a reply can carry an English translation beside the original. The KB gap agent picked up write and review agents, so a proposed doc change arrives as a reviewed pull request. See [Automated Pull Requests](/knowledge-base/kb-gap-detection).
## Pull requests beside the ticket that caused them
A PR viewer lists pull requests with rendered diffs and links back to the ticket that prompted the work. Ticket pages gained previous and next, so you can work a queue without returning to the list.
## Approve before it goes live
Articles gained a visibility selector and nested collections, and routing categories and policies moved to a draft and approval flow. Connect more than one Slack workspace and filter conversations by workspace. Every API route now writes to an audit log.
## Doc gaps become pull requests
The KB gap agent shipped with a dry-run mode: what a ticket reveals about your docs arrives as a proposed pull request, rather than a task for someone to remember.
## Slack conversations, in one place
Slack conversations got a UI of their own, with an Observability dashboard alongside.
# JavaScript API
Source: https://docs.decimal.app/chat-widgets/api-reference
Control the chat widget programmatically with the Decimal JavaScript API.
The widget exposes a global `Decimal` object with the following methods.
## Decimal.boot(options)
Manually initializes the widget. Required when using `data-disable-autoboot`.
| Parameter | Type | Description |
| ------------ | ------ | ------------------------------------------------------------------------------------------------------------------------------- |
| `user_token` | string | A signed JWT for authenticated sessions. Required when [identity verification](/chat-widgets/identity-verification) is enabled. |
| `metadata` | object | Key-value pairs included with escalation tickets (e.g. account ID, plan type). |
```js theme={null}
Decimal.boot({
user_token: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...',
metadata: {
account_id: 'id_asdf',
plan: 'enterprise',
}
});
```
## Decimal.show(options)
Opens the chat widget programmatically. Equivalent to clicking the launcher button.
| Parameter | Type | Description |
| -------------- | ------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `presentation` | string | `'modal'` opens the widget as a centered modal with a backdrop instead of the corner popup. Defaults to the standard floating popup. Ignored in sidebar display modes. |
```js theme={null}
Decimal.show();
// Open as a centered modal
Decimal.show({ presentation: 'modal' });
```
If called before the widget has finished loading, the open is queued and runs once it's ready. In modal presentation, clicking the backdrop or pressing Esc closes the widget.
## Decimal.hide()
Closes the chat widget programmatically. Equivalent to clicking the launcher button again.
```js theme={null}
Decimal.hide();
```
## Decimal.showButton() / Decimal.hideButton()
Show or hide the launcher button without removing the widget. The `data-hide-button` attribute hides it for the whole session; these two toggle it at runtime, so you can drop the launcher on certain pages or reveal it after the user does something.
```js theme={null}
Decimal.hideButton();
Decimal.showButton();
```
The widget can still be opened while the button is hidden by calling [`Decimal.show()`](#decimalshowoptions).
## Decimal.shutdown()
Removes the chat widget completely. Call `Decimal.boot()` again to restart from scratch.
```js theme={null}
Decimal.shutdown();
```
## Decimal.update(options)
Updates widget metadata after initialization. Merged with existing metadata and included when escalating to a human.
| Parameter | Type | Description |
| ---------- | ------ | ------------------------------------------------ |
| `metadata` | object | Key-value pairs to merge with existing metadata. |
```js theme={null}
Decimal.update({
metadata: {
account_id: 'id_asdf',
plan: 'enterprise',
}
});
```
The widget tracks the current page itself and adds it to metadata as `_pageUrl` and `_pageTitle`, with query strings stripped so tokens and PII don't leak. Single-page-app navigation is picked up too, so route changes need no `update()` call from you.
## Decimal.theme(options)
Customizes widget appearance. Can be called before or after `Decimal.boot()`. To reset to defaults, call `Decimal.theme(Decimal.DEFAULT_THEME)`.
```js theme={null}
Decimal.theme({
colorScheme: 'dark',
primaryColor: '#3B82F6',
backgroundColor: '#18181B',
textColor: '#FAFAFA',
textColorSecondary: '#FFFFFF',
textColorMuted: '#A1A1AA'
});
```
### Colors
| Parameter | Description | Default |
| -------------------- | ----------------------------------------------------------------- | --------- |
| `colorScheme` | `'light'` \| `'dark'` \| `'auto'`. Controls browser color scheme. | `'light'` |
| `primaryColor` | Launcher button, user message bubbles, action buttons. | `#18181B` |
| `backgroundColor` | Widget background color. | `#FFFFFF` |
| `textColor` | Headings, body text, input labels, "Powered by Decimal". | `#18181B` |
| `textColorSecondary` | Text on primary-colored elements (user messages, buttons). | `#FFFFFF` |
| `textColorMuted` | Timestamps, secondary labels, metadata. | `#71717A` |
| `borderColor` | Widget border and internal dividers. | none |
Pass `null` for any color to reset it to the component default.
### Position & Size
These options only affect the widget container in floating mode, designed for use with `data-hide-button`. All values are CSS strings (e.g. `'20px'`, `'50%'`).
| Parameter | Description | Default |
| ----------------- | -------------------------- | -------------- |
| `width` | Widget width. | `380px` |
| `height` | Widget height. | `640px` |
| `top` | Distance from top edge. | `unset` |
| `bottom` | Distance from bottom edge. | `80px` |
| `left` | Distance from left edge. | `unset` |
| `right` | Distance from right edge. | `20px` |
| `transformOrigin` | Animation origin point. | `bottom right` |
### Button Position
Position the launcher button independently from the widget container.
| Parameter | Description | Default |
| -------------- | --------------------------------- | ------- |
| `buttonTop` | Button distance from top edge. | `unset` |
| `buttonBottom` | Button distance from bottom edge. | `20px` |
| `buttonLeft` | Button distance from left edge. | `unset` |
| `buttonRight` | Button distance from right edge. | `20px` |
### Content
`theme()` also accepts content overrides for the widget's header and greeting. These can be set here or via [data attributes](/chat-widgets/installation#data-attributes) on the script tag.
| Parameter | Description |
| ------------------- | ------------------------------------------------------------------------------ |
| `headerTitle` | Title shown in the widget header. |
| `headerSubtitle` | Subtitle shown under the header title. |
| `greeting` | Greeting headline shown on the empty conversation screen. |
| `greetingSubtitle` | Text shown under the greeting headline. |
| `placeholderText` | Placeholder text shown in the chat input field. Defaults to "Ask anything...". |
| `suggestedMessages` | Array of up to 6 prompt strings shown as one-click starters. |
```js theme={null}
Decimal.theme({
headerTitle: 'Acme Support',
greeting: 'Hi there 👋',
greetingSubtitle: 'Ask us anything about your account.',
suggestedMessages: [
'How do I reset my password?',
'Where can I find my invoices?',
],
});
```
# Conversations
Source: https://docs.decimal.app/chat-widgets/conversations
Review customer chat widget conversations, monitor AI responses, and export conversation data.
Open **Conversations** to see what customers are asking your widgets and how the agent answered. Read them regularly and the gaps show up on their own: a question the agent keeps fumbling is an article you haven't written yet.
Each row carries the conversation title and its feedback badge, the widget name when you run more than one, the visitor (name or email if they authenticated, otherwise anonymous), and when it was last updated.
Search by title or ID. Filter by widget, by feedback, by escalation status, or by whether a [policy](/policies) applied.
## Details
Click a conversation to read the full thread. Where a conversation was escalated, the header links to the resulting ticket in both Decimal and the external tool. The info popover holds the widget name, visitor details, domain, and start date.
## Export
Click **Export** to download conversations as CSV or JSON. Pick a time period, and narrow to one widget if you want.
# Identity Verification
Source: https://docs.decimal.app/chat-widgets/identity-verification
Authenticate widget users with JWT tokens for verified sessions.
Identity verification ties every widget session to a user your backend has already authenticated. With it on, the widget refuses to load without a valid JWT that you signed. With it off, visitors type their own email and name into an identity form.
## Turning It On
Open **Chat Widgets → \[your widget] → Security** and turn identity verification on. A JWT signing secret is generated for you.
Use the signing secret on your backend to generate JWTs. Never expose it in frontend code.
## Embed Code with Authentication
When identity verification is enabled, use `data-disable-autoboot` and call [`Decimal.boot()`](/chat-widgets/api-reference#decimalbootoptions) with the signed token:
```html theme={null}
```
The key differences from the [standard embed code](/chat-widgets/installation):
* `data-disable-autoboot` prevents the widget from loading until a token is provided.
* `Decimal.boot({ user_token })` initializes the widget with the signed JWT.
You can also pass `metadata` to `Decimal.boot()`, or update it later with [`Decimal.update()`](/chat-widgets/api-reference#decimalupdateoptions). Whatever it holds travels with the ticket when a conversation escalates to a human.
## Server-Side Token Generation
Token generation must happen on your backend server where the secret remains secure.
```javascript Node.js theme={null}
import jwt from 'jsonwebtoken';
const JWT_SECRET = process.env.DECIMAL_JWT_SECRET;
const token = jwt.sign(
{
email: 'user@example.com', // required
name: 'Jane Doe', // optional
disable_escalation: false, // optional
},
JWT_SECRET,
{ algorithm: 'HS256', expiresIn: '1h' }
);
```
```python Python theme={null}
import jwt
import os
from datetime import datetime, timedelta, timezone
JWT_SECRET = os.environ["DECIMAL_JWT_SECRET"]
now = datetime.now(timezone.utc)
token = jwt.encode(
{
"email": "user@example.com", # required
"name": "Jane Doe", # optional
"disable_escalation": False, # optional
"iat": now,
"exp": now + timedelta(hours=1),
},
JWT_SECRET,
algorithm="HS256"
)
```
## JWT Claims
| Claim | Required | Type | Description |
| -------------------- | -------- | ------- | -------------------------------------------------------------------- |
| `email` | Yes | string | User's email address. |
| `exp` | Yes | number | Token expiration timestamp (Unix seconds). Recommended: 1 hour max. |
| `name` | No | string | Display name shown in chat. |
| `disable_escalation` | No | boolean | Set to `true` to prevent this user from escalating to human support. |
Any other claim you add is stored and lands in the escalation ticket's metadata, which is how account IDs or plan types reach your support team. What the ticket does with them depends on the integration handling the escalation.
# Installation
Source: https://docs.decimal.app/chat-widgets/installation
Add the Decimal chat widget to your website with a simple script tag.
## Embed Code
Add this snippet before the closing `