> ## Documentation Index
> Fetch the complete documentation index at: https://docs.usefini.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Regulated industries: disputes and complaints controls

> Configure Fini to recognize complaints and payment disputes, capture the details your process requires, keep the agent from answering where it shouldn't, route to the right team, and keep an audit trail.

export const ScenarioChecker = ({title = "Try it", question, scenarios = [], labels = {
  yes: "Yes",
  no: "No",
  depends: "It depends"
}}) => {
  const FV = {
    lime: "#C3EE5E",
    ink: "#131415",
    line: "rgba(127,127,127,0.28)",
    soft: "rgba(127,127,127,0.07)",
    softer: "rgba(127,127,127,0.04)",
    muted: "rgba(127,127,127,0.95)",
    pass: "#C3EE5E",
    warn: "#FFB020",
    fail: "#FF4D4D",
    radius: 14
  };
  const fvCard = {
    border: `1px solid ${FV.line}`,
    borderRadius: FV.radius,
    padding: 18,
    margin: "20px 0",
    background: FV.softer
  };
  const fvChip = active => ({
    border: `1px solid ${active ? FV.lime : FV.line}`,
    background: active ? FV.lime : "transparent",
    color: active ? FV.ink : "inherit",
    borderRadius: 999,
    padding: "6px 12px",
    fontSize: 13,
    fontWeight: 600,
    cursor: "pointer",
    lineHeight: 1.2
  });
  const fvBtn = primary => ({
    border: `1px solid ${primary ? FV.lime : FV.line}`,
    background: primary ? FV.lime : "transparent",
    color: primary ? FV.ink : "inherit",
    borderRadius: 10,
    padding: "7px 14px",
    fontSize: 13,
    fontWeight: 600,
    cursor: "pointer"
  });
  const fvLabel = {
    fontSize: 11,
    fontWeight: 700,
    letterSpacing: "0.08em",
    textTransform: "uppercase",
    opacity: 0.6,
    marginBottom: 8
  };
  const [k, setK] = useState(null);
  const s = k === null ? null : scenarios[k];
  const col = {
    yes: FV.pass,
    no: FV.fail,
    depends: FV.warn
  };
  return <div style={fvCard}>
      <div style={fvLabel}>{title}</div>
      {question && <div style={{
    fontSize: 16,
    fontWeight: 700,
    marginBottom: 12
  }}>{question}</div>}
      <div style={{
    display: "grid",
    gridTemplateColumns: "repeat(auto-fill, minmax(220px, 1fr))",
    gap: 8
  }}>
        {scenarios.map((sc, i) => <button key={i} onClick={() => setK(i)} style={{
    textAlign: "left",
    padding: "10px 12px",
    borderRadius: 10,
    cursor: "pointer",
    fontSize: 13.5,
    lineHeight: 1.4,
    color: "inherit",
    border: `1px solid ${k === i ? FV.lime : FV.line}`,
    background: k === i ? "rgba(195,238,94,0.14)" : "transparent"
  }}>{sc.label}</button>)}
      </div>
      <div style={{
    marginTop: 14,
    minHeight: 64,
    padding: "12px 14px",
    borderRadius: 10,
    border: `1px solid ${s ? col[s.verdict] : FV.line}`,
    background: FV.soft,
    transition: "border-color .25s"
  }}>
        {s ? <div>
            <b>{labels[s.verdict]}</b>{s.title ? <b>{`: ${s.title}`}</b> : null}
            <div style={{
    fontSize: 14,
    marginTop: 4,
    lineHeight: 1.55
  }}>{s.why}</div>
          </div> : <span style={{
    fontSize: 13.5,
    opacity: 0.6
  }}>Pick a scenario to see the answer.</span>}
      </div>
    </div>;
};

Fini (usefini.com) gives financial services teams five controls for complaint and dispute intake: tags that recognize them, Rulebook flows that capture the required details, Reply Rules that limit the agent to internal notes, escalation and routing to the right team, and the AI Steps trace as a per-reply audit record. You configure each one in your workspace, and you test the whole setup with Test Suite before it reaches customers.

<Warning>
  Fini provides the controls; your organization remains responsible for compliance determinations. Whether a message is a complaint, whether a dispute is a regulated error notice, which deadlines apply and what you must tell the customer are decisions for your compliance and legal teams. Regulations differ by product and jurisdiction, for example Regulation E and Regulation Z in the US, or your national regulator's complaint-handling rules in Europe. Nothing on this page is legal advice.
</Warning>

## Why complaints and disputes need their own setup

Most support conversations are fine to resolve end to end. Complaints and disputes are different in three ways:

* **Recognition matters.** A customer rarely says "I'm filing a complaint." They write "this is the third time you've charged me" or "I never authorized this payment." If your process treats those as complaints or error notices, the agent must recognize them consistently.
* **The record matters.** Your process usually needs specific facts captured (dates, amounts, what the customer is asking for) and a reviewable trail of what was said.
* **The wrong answer is costly.** A confident AI reply that promises a refund, denies liability or sets a resolution date can create an obligation your team did not intend.

The setup below addresses each one.

```mermaid theme={null}
---
title: Complaint and dispute handling in Fini
---
flowchart LR
    MSG["Customer message"] --> TAG["Tags<br/>Complaint · Dispute"]
    TAG --> RR{"Reply Rules"}
    RR -->|"Internal Comment"| NOTE["Internal note<br/>for your team"]
    RR -->|"Direct Reply allowed"| RB["Rulebook intake<br/>Read · Form · Tool"]
    RB --> CASE["Case created in<br/>your system"]
    NOTE --> ESC["Escalation<br/>routed to team"]
    CASE --> ESC
    ESC --> HUMAN["Your complaints<br/>or disputes team"]
    TRACE["AI Steps trace<br/>on every reply"] -.-> NOTE
    TRACE -.-> RB

    classDef source fill:#F7F7F7,color:#131415,stroke:#E8E8E8
    classDef agent fill:#131415,color:#FFFFFF,stroke:#131415,stroke-width:3px
    classDef surface fill:#FFFFFF,color:#131415,stroke:#131415
    classDef human fill:#C3EE5E,color:#131415,stroke:#131415,stroke-width:2px

    class MSG,TRACE source
    class TAG,RR,RB agent
    class NOTE,CASE,ESC surface
    class HUMAN human
```

## 1. Recognize complaints and disputes with tags

Create a Custom tag group so every conversation gets a consistent classification. Open **Tag Groups**, click **New Group**, and configure:

| Setting | Recommendation |
| - | - |
| Name | `Complaint or Dispute` |
| Tags | `complaint`, `transaction_dispute`, `billing_error`, `not_applicable` (use the categories your policy defines) |
| Tag Selection | "Exactly one tag is selected" |
| Tag Group available in Rulebooks | **ON**, so Rulebook Checks can branch on it |
| AI Instructions | Your own definitions, written as you would brief a new agent, with example phrasings for each tag and for `not_applicable` |

Write the AI Instructions from your complaint policy, not from general intuition. If your policy says any expression of dissatisfaction is a complaint, say so, and give examples. Tag accuracy depends on how specific these instructions are. See [Tags](/en/configuration/tags).

The default groups add context you can use alongside it: **Sentiment** (Positive, Neutral, Negative), **Type of Issue**, and **Escalation Reason**, whose Policy triggers family explains escalations caused by your rules.

<Tip>
  If you use Zendesk, map these Fini tags to Zendesk ticket tags with **Fini tags → Zendesk tags** on the Zendesk deploy page, so your Zendesk views, triggers and reports pick up the classification. See [Zendesk](/en/deploy/zendesk).
</Tip>

## 2. Keep the agent from answering where it shouldn't

Decide, per category, whether the agent may reply to the customer at all. Then encode it in [Reply Rules](/en/automations/reply-behavior):

| Your policy | Reply Rules card | Condition |
| - | - | - |
| A human writes every complaint response | **Internal Comment** | `Complaint or Dispute In complaint, transaction_dispute, billing_error` |
| Never engage once a human owns the case | **No Reply** | `Human Agent Assigned Equals True` |
| Stay out of escalated conversations entirely | **No Reply** | `Escalated Conversation Equals True` |

With the **Internal Comment** card, the agent posts a note your team sees in the helpdesk (an *Internal Note* in Zendesk and Intercom, an *Internal Comment* in Front, a *Case Comment* in Salesforce) and nothing reaches the customer. The stricter card always wins, so a broad **Direct Reply** setup elsewhere cannot override these.

<Note>
  Tag Group conditions wait until the conversation has been classified. System fields such as **Human Agent Assigned** resolve immediately. Put time-critical blocks on system fields or User Attributes where you can.
</Note>

## 3. Capture what your process requires

Where your policy allows the agent to take the intake, build an Intent Rule that collects the facts deterministically instead of leaving it to free-form conversation. See [Rulebook](/en/automations/rulebook).

* **Check** nodes branch on the `Complaint or Dispute` tag and on User Attributes such as account type.
* **Read** nodes extract structured values from the conversation into tree variables: transaction date, amount, merchant, what the customer is asking for.
* A **Form** node collects typed input in the [widget](/en/deploy/widget) when you need exact values. Email channels cannot render Forms, so use Read nodes there.
* A **Tool** node calls an [Action](/en/api-reference/actions) that creates the case in your complaints or disputes system, with the captured values and the conversation reference.
* A **Reply** node acknowledges receipt with the wording your compliance team approved, including the case reference your system returned.
* The **Reply** is also the handoff: it tells the customer a person will follow up, and the conversation is recorded as **Escalated to Human Agent**. To route complaint topics to people before any rule runs, add them to *Escalation Topics* in the Planning Prompt or set the article-level **Escalation** field to **Yes** on the relevant articles; for widget conversations, a Business Rule with the **On Escalation** trigger creates the ticket in your helpdesk.

Keep the Reply wording factual. Acknowledge, confirm what was captured, and say a person will follow up. Promises about outcomes and timelines belong to your team.

## 4. Escalate and route

* **Planning Prompt escalation triggers.** Fini's default **Escalation Topics** already include regulator or ombudsman complaints and threats of legal action. Add your own, for example unauthorized transactions or account-takeover signals. See [Prompts](/en/configuration/prompts#controlling-when-the-agent-escalates).
* **Agent groups.** For widget and native email tickets, map your complaint and dispute tags to an agent group such as `Disputes`. When the agent escalates, Fini routes the ticket to that group and assigns an available member. See [Agent groups](/en/configuration/agent-groups).
* **Helpdesk routing.** For helpdesk channels, the escalation and internal note land in the ticket in your helpdesk; route from there with your helpdesk's own rules.

## 5. Guard the wording of every reply

Add [Guardrails](/en/configuration/guardrails) that check replies before delivery:

* A **Custom rule** that fails any reply promising a refund, credit, reversal or resolution date, or admitting or denying fault.
* **Banned terms** for phrases your compliance team has ruled out.
* **Confidential attributes** for account data that must never appear in a reply.

Fini automatically masks sensitive data, including card numbers and health details, everywhere it stores conversation data (transcripts, Inbox and AI Steps traces). Fields you hide from the AI are also redacted in AI Steps. Don't ask customers for full card numbers or CVVs in a dispute; identify the transaction from your own records and route card actions through your payment provider via Actions. Guardrails are an extra layer on what the agent says. See [Data handling](/en/security/data-handling#masking-sensitive-data).

A failing reply is rewritten once; if the rewrite still fails, Fini sends a handoff message and escalates. Guardrails are not fail-closed, so a check error can let the original reply through. Review the per-check verdicts in AI Steps, and rely on Reply Rules, not Guardrails, for categories where the agent must never reply.

<ScenarioChecker
  title="Try it: the example setup on this page"
  question="Does the agent answer the customer?"
  scenarios={[
{ label: "Message tagged complaint, with the Internal Comment rule above", verdict: "no", title: "Internal note only", why: "The agent posts a note your team sees in the helpdesk, and nothing reaches the customer. The stricter card wins over any broad Direct Reply setup." },
{ label: "A teammate is already assigned to the ticket", verdict: "no", title: "No Reply", why: "The condition Human Agent Assigned Equals True on the No Reply card keeps the agent out once a human owns the case. System fields resolve immediately." },
{ label: "The conversation was already escalated", verdict: "no", title: "No Reply", why: "The condition Escalated Conversation Equals True on the No Reply card keeps the agent out of escalated conversations entirely." },
{ label: "Your policy allows agent intake and the dispute Intent Rule runs", verdict: "yes", title: "Approved acknowledgment", why: "The Rulebook captures the facts, a Tool node creates the case in your system, a Reply node sends the wording your compliance team approved, including the case reference, and says a person will follow up, which hands the case to your team." },
{ label: "A drafted reply promises a refund date", verdict: "depends", title: "Rewritten or escalated", why: "A Custom rule guardrail fails the reply. Fini rewrites it once; if the rewrite still fails, Fini sends a handoff message and escalates." },
{ label: "A guardrail check errors on a disputed charge reply", verdict: "depends", title: "Not fail-closed", why: "A check error can let the original reply through. For categories where the agent must never reply, rely on Reply Rules, not Guardrails." },
{ label: "The customer mentions a regulator or ombudsman", verdict: "no", title: "Escalates", why: "Regulator or ombudsman complaints are already in Fini's default Escalation Topics, so the agent hands the conversation to your team." }
]}
  labels={{ yes: "Agent answers", no: "Agent does not answer", depends: "Depends" }}
/>

## 6. Audit what happened

Every Fini reply carries an **AI Steps** trace in [Inbox](/en/testing/inbox). For a complaint or dispute conversation it shows:

| Section | What it records |
| - | - |
| **Planning** | How the agent interpreted the message and whether it chose to escalate |
| **Executed User Attributes** | Which customer data was loaded, and whether each lookup succeeded |
| **Executed Rule** | Every rule and node that ran, in order, including which Check stopped a rule |
| **Generate Answer** | Interaction Reasoning, Prompt Reasoning and Final Answering Strategy for generated replies |
| **Output Tag Selection** | The tags applied, with a reasoning paragraph |
| **Guardrails** | Each policy verdict and the outcome: **Passed**, **Rewritten**, **Escalated to a human** or **Check failed, sent as generated** |

To review a period, filter Inbox by **Tags** (your complaint tags) and date range, and save it as a **View**. Use **Feedback Notes** to record reviewer findings on individual replies. [Analytics](/en/analytics) breaks conversations down by tag and shows escalation reasons.

<Note>
  Inbox and AI Steps are a review surface, not your system of record. Keep the case file in your complaints or disputes system, created by the Tool node in step 3 or by your team after escalation.
</Note>

## 7. Test before and after every change

Build [Test Suite](/en/testing/test-suite) coverage for this flow and keep it in one collection:

* Create test cases from real Inbox conversations tagged as complaints, plus conversations you create in Inbox for edge cases: indirect complaints, a dispute raised mid-conversation about something else, a customer who mentions a regulator. A criteria group's picker can add up to 50 conversations at once.
* Add a criteria group with an AI judgement written to your policy: pass when complaints and disputes escalate or receive only the approved acknowledgment, fail when the agent resolves them alone. Add an exact check for the handoff and mark both **Required to pass**.
* Add a second criteria group with an AI judgement that catches promises and legal-sounding statements.

Run the collection after every prompt, knowledge, tag or rule change. Compare results in **Runs** to see whether a change made the agent better or worse at recognizing these conversations, and check the recorded run configuration before blaming a changed verdict on the agent.

## Related

<CardGroup cols={2}>
  <Card title="Reply Rules" icon="turn-down-right" href="/en/automations/reply-behavior">
    Direct Reply, Internal Comment and No Reply conditions.
  </Card>

  <Card title="Tags" icon="tag" href="/en/configuration/tags">
    Custom tag groups, AI Instructions and Rulebook availability.
  </Card>

  <Card title="Fintech setup" icon="building-columns" href="/en/industry-setup/fintech">
    Recommended configuration for banking and fintech support.
  </Card>

  <Card title="Security overview" icon="shield-halved" href="/en/security/overview">
    Fini's certifications, data handling and reviewer FAQ.
  </Card>
</CardGroup>


## Related topics

- [Introduction](/en/introduction.md)
- [Setting up Fini for fintech and banking](/en/industry-setup/fintech.md)
- [Setting up Fini for healthcare](/en/industry-setup/healthcare.md)


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.