> ## 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.

# What counts as a resolution

> Fini bills per resolution, a customer issue the Fini agent fully solves with no human involvement and no customer reply for 72 hours, and this page defines it, lists what counts and what doesn't, and maps it to the statuses you see in Analytics.

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>;
};

A resolution in Fini (usefini.com) is a customer issue that the Fini agent fully solves, with no human ever touching the conversation and no reply from the customer for 72 hours. It is the unit Fini bills on: escalated conversations are not charged, a conversation the customer reopens within 72 hours is not a resolution, and greetings, spam, and abandoned sessions are never billable.

The definition is deliberately strict. A conversation where the agent replied but a teammate still stepped in is not a resolution, even if the agent did most of the work. That keeps your bill tied to the outcome you care about (the customer's problem is gone) rather than to activity (the agent sent a message).

This page explains the definition, gives concrete examples, shows how it lines up with the **Conversation Status** you see in [Analytics](/en/analytics) and [Inbox](/en/testing/inbox), and walks you through checking your own numbers.

## The definition

A conversation counts as a resolution only when all of the following are true:

| Test | What it means in practice |
| - | - |
| **Fini fully solved the issue** | The customer got a complete answer, or the action they asked for was completed (a refund issued, an address changed, a subscription cancelled). Nothing is left pending on the customer's side or your team's side. The agent used your [Knowledge](/en/knowledge/overview), [Intent Rules](/en/automations/rulebook), and [Actions](/en/api-reference/actions) to get there. |
| **No human ever touched the conversation** | The agent did not escalate to your team, and no teammate replied to or worked on the conversation at any point. That includes flows where the agent only writes an internal note and a person sends the reply. |
| **The customer did not reply for 72 hours** | After the agent's last reply, the customer did not write back for 72 hours. A conversation the customer reopens within that window is not a resolution. |
| **It was a real request** | The conversation contained an actual support issue. Greetings with no follow-up, spam, and sessions the customer abandoned are never billable. |

<Info>
  **Why Fini bills on resolutions, not conversations or seats.** A per-conversation or per-seat price charges you whether or not the customer's problem was solved. Billing on resolutions puts the cost of a failed conversation on Fini: if the agent can't solve it and hands it to your team, you pay nothing for that conversation. See [How Fini pricing works](/en/billing/how-pricing-works) for the full model.
</Info>

## What counts and what doesn't

| Scenario | Counts as a resolution? | Why |
| - | - | - |
| The agent answers a policy question ("What's your refund window?") completely from your knowledge base, and the customer doesn't write back for 72 hours. | Yes | Fully solved, no human involved, no reply within 72 hours. |
| The agent runs an Intent Rule that verifies the customer, calls your billing API to cancel the subscription, and confirms the effective date. The customer doesn't write back. | Yes | The action was completed by the agent. This is the pattern in the [cancellation walkthrough](/en/walkthroughs/cancellation-flow). |
| The agent confirms that a background process will complete on its own, for example "Our finance team will process your payment automatically within 1-2 business days," and the customer doesn't write back. | Yes | Product rule: a complete acknowledgment of background work with no follow-up pending is tagged **Resolved**. No person has to take over the conversation. |
| The agent escalates to your team ("Let me connect you with our team"), or a [Guardrail](/en/configuration/guardrails) blocks a reply and Fini hands off. | No | Human handover. Escalations are free, and your team receives the full conversation and context. |
| The agent says the request was forwarded to an internal team **and** that the team will follow up with the customer directly. | No | Product rule: this is tagged **Escalated to Human Agent**, so it is a handover. |
| The customer asks for a human on their first message and the agent routes them. | No | Human handover. Analytics records it in the User family of [escalation reasons](/en/analytics#escalation-reasons), as a customer who requested a human immediately. |
| The agent asks for an order number and the customer never replies. | No | The conversation is **Waiting for Customer** and the issue was never solved. Abandoned sessions are never billable. |
| The customer only says "hi" or "thanks" and leaves, or the message is spam. | No | Greetings, spam, and abandoned sessions are never billable. |
| The agent answers, then the customer writes back within 72 hours. | No | The conversation reopened within 72 hours, so it is not a resolution. |
| The agent answers, and a teammate later adds a reply or works on the conversation. | No | A human touched the conversation. |
| The agent posts an **Internal Comment** (a note only your team sees) and a teammate sends the actual reply. | No | A person sent the customer-facing reply, so a human touched the conversation. See [Reply Rules](/en/automations/reply-behavior). |

<ScenarioChecker
  title="Try it"
  question="Does this count as a resolution?"
  labels={{ yes: "Counts", no: "Does not count", depends: "Depends" }}
  scenarios={[
{ label: "The agent answers a refund-window question completely from your knowledge base, and the customer doesn't write back for 72 hours.", verdict: "yes", title: "Fully solved", why: "The customer got a complete answer, nothing is pending, no person stepped in, and the customer did not reply within 72 hours." },
{ label: "An Intent Rule verifies the customer, cancels the subscription through your billing API, and confirms the date. The customer doesn't write back.", verdict: "yes", title: "Action completed by the agent", why: "The agent performed the step the customer asked for, with no human involved. This is the pattern in the cancellation walkthrough." },
{ label: "The agent confirms a payment will be processed automatically within 1-2 business days, and the customer doesn't write back.", verdict: "yes", title: "Background work acknowledged", why: "A complete acknowledgment of background work with no follow-up pending is tagged Resolved." },
{ label: "The agent says: Let me connect you with our team.", verdict: "no", title: "Human handover", why: "Escalations are free. Your team receives the full conversation and context." },
{ label: "A Guardrail blocks a reply and Fini hands off.", verdict: "no", title: "Human handover", why: "A guardrail handoff is an escalation, so it is never billed." },
{ label: "The agent says the request was forwarded and the team will follow up with the customer directly.", verdict: "no", title: "Tagged Escalated to Human Agent", why: "Promising a direct follow-up from your team is a handover by product rule." },
{ label: "The customer asks for a human on the first message.", verdict: "no", title: "Human handover", why: "Analytics records it in the User family of escalation reasons." },
{ label: "The agent asks for an order number and the customer never replies.", verdict: "no", title: "Waiting for Customer", why: "The issue was never solved. Abandoned sessions are never billable." },
{ label: "The customer only says hi or thanks, or the message is spam.", verdict: "no", title: "Not a real request", why: "Greetings, spam, and abandoned sessions are never billable." },
{ label: "The agent answers, and the customer writes back within 72 hours.", verdict: "no", title: "Reopened within 72 hours", why: "A resolution requires 72 hours with no customer reply. A reopen inside that window means it is not a resolution." },
{ label: "The agent posts an Internal Comment and a teammate sends the reply.", verdict: "no", title: "A human touched it", why: "A person sent the customer-facing reply. Anything a teammate replies to or touches is not a resolution." }
]}
/>

## How a resolution maps to Analytics statuses

Every conversation ends in exactly one of three **Conversation Status** values. Fini applies them with a fixed, ordered decision rule (see [Tags](/en/configuration/tags#mandatory-groups-conversation-status)), and the same tag drives the Inbox status badge, [Reply Rules](/en/automations/reply-behavior), and resolution analytics.

The labels differ slightly between pages of the dashboard. They are the same three states:

| Analytics label | Tags and Inbox label | Billing treatment |
| - | - | - |
| **Resolved by AI** | **Resolved** | The candidate set for billable resolutions. It becomes a resolution only if no human touched the conversation and the customer did not reply for 72 hours. Greetings and spam are never billable. |
| **Escalated to Human Team** | **Escalated to Human Agent** | Never billed. |
| **Waiting for Customer** | **Waiting for Customer** | Not billed while waiting. If the customer never comes back, the session is abandoned and is never billable. |

A conversation can move between statuses before it settles. The status it ends in decides whether it can be billed:

```mermaid theme={null}
---
title: How a conversation moves between statuses
---
stateDiagram-v2
    direction LR
    state "Resolved by AI" as Resolved
    state "Escalated to Human Team" as Escalated
    state "Waiting for Customer" as Waiting
    state "Abandoned session" as Abandoned

    [*] --> Resolved: agent solves the issue
    [*] --> Waiting: agent asks for details
    [*] --> Escalated: handover to your team
    Waiting --> Resolved: customer replies, agent solves it
    Waiting --> Escalated: customer replies, agent hands off
    Waiting --> Abandoned: customer never returns
    Resolved --> Waiting: customer replies within 72h, not a resolution
    Resolved --> Escalated: a teammate steps in
    Resolved --> [*]: billable after 72h with no reply, unless greeting or spam
    Escalated --> [*]: never billed
    Abandoned --> [*]: never billed

    classDef agent fill:#131415,color:#FFFFFF,stroke:#131415,stroke-width:3px
    classDef surface fill:#FFFFFF,color:#131415,stroke:#131415
    classDef source fill:#F7F7F7,color:#131415,stroke:#E8E8E8
    classDef human fill:#C3EE5E,color:#131415,stroke:#131415,stroke-width:2px
    class Resolved human
    class Escalated,Waiting surface
    class Abandoned source
```

```mermaid theme={null}
---
title: From conversation status to billable resolution
---
flowchart LR
    CONV(("Conversation"))
    RES["Resolved by AI"]
    ESC["Escalated to Human Team"]
    WAIT["Waiting for Customer"]
    EXCL["Not a resolution<br/>greetings · spam · customer reply within 72h · human touched"]
    BILL["Billable resolution"]
    FREE["Not billed"]

    CONV --> RES
    CONV --> ESC
    CONV --> WAIT
    RES -->|"no human touch, no reply for 72h"| BILL
    RES -.-> EXCL
    EXCL --> FREE
    ESC --> FREE
    WAIT -->|"customer never returns"| FREE
    WAIT -.->|"customer replies, agent solves it"| RES

    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 CONV agent
    class RES,ESC,WAIT surface
    class EXCL,FREE source
    class BILL human
```

### Resolution rate is not deflection rate

Analytics shows two different headline numbers, and only one of them matches billing:

* **AI resolution rate** counts only conversations with status **Resolved by AI**. This is the number that tracks your billable resolutions.
* **Deflection rate** is `100% - Human escalation rate`. Conversations still **Waiting for Customer** count as deflected unless they escalated, so deflection rate is always equal to or higher than AI resolution rate.

If you estimate spend from deflection rate, you will overestimate it, because waiting and abandoned conversations are never billed. Use AI resolution rate. [Resolution vs deflection](/en/performance/resolution-vs-deflection) explains the difference in more depth.

### Where the product status and the bill can differ

The **Resolved by AI** count in Analytics and the number of billable resolutions are close, but they can differ in the short term. The known reasons:

1. **The 72-hour window.** The **Resolved by AI** status can appear in Analytics before the 72-hour window closes. If the customer writes back inside the window, the conversation is not a resolution, so the billed count can be lower than the Analytics count for recent conversations.
2. **Greetings and spam.** The Conversation Status rule tags a conversation **Resolved** when the agent gave a complete answer and nothing is pending. A short greeting the agent answered politely can land in **Resolved by AI**, while billing never counts greetings or spam.
3. **Status changes after the fact.** Analytics filters on the latest status. A conversation that was **Waiting for Customer** at the end of one month and resolved early the next can move between periods.

## How to check your own numbers

You can reproduce the resolution count for any period yourself, from the dashboard or the API.

<Steps>
  <Step title="Open Analytics for the right agent and period">
    Open [Analytics](/en/analytics), pick the agent in the agent picker, and set the date range to the period you want to check (for example, last calendar month). KPI change pills compare against the preceding window of the same length.
  </Step>

  <Step title="Read the three-way status split">
    Scroll to **Conversation Status** in the Distribution section. It shows **Resolved by AI**, **Escalated to Human Team**, and **Waiting for Customer** as shares of total **Conversation volume**. Multiply the Resolved by AI share by conversation volume to get the resolved count.
  </Step>

  <Step title="Filter to resolved conversations">
    Set the pinned **Conversation status** filter to **Resolved by AI**. Every KPI card, chart, and table below the header now reflects only resolved conversations. Add **Channel** or **Source** from **+ Filter** to split by channel or helpdesk.
  </Step>

  <Step title="Spot-check in Inbox">
    Open the same slice in [Inbox](/en/testing/inbox) with the **Conversation status** filter, and read a sample. The **AI Steps** trace on each conversation shows the **Output Tag Selection** reasoning behind its status. Look for greetings, spam, customer replies within 72 hours, and conversations a teammate touched, none of which are billable resolutions.
  </Step>

  <Step title="Pull the numbers by API (optional)">
    For a repeatable monthly check, call [Get agent analytics](/en/api-reference/get-agent-analytics) (`GET /v2/bots/:id/hc-analytics/public`) with `startEpoch`, `endEpoch`, and the `latestStatus` filter, using an API key with the `read` scope. See the [Analytics API overview](/en/api-reference/analytics) for the full query model.
  </Step>
</Steps>

<Tip>
  If a status looks wrong on a specific conversation, read the AI Instructions on the **Conversation Status** tag group. The rules encode specific phrases, so a reply like "I have forwarded your request to our specialist team" is tagged as an escalation by design. Fix the reply wording in your [Prompts](/en/configuration/prompts) or Intent Rules rather than the tag.
</Tip>

## Related

<CardGroup cols={2}>
  <Card title="How Fini pricing works" icon="receipt" href="/en/billing/how-pricing-works">
    Usage-based pricing per resolution, what you are never charged for, and how to estimate spend.
  </Card>

  <Card title="Analytics" icon="chart-bar" href="/en/analytics">
    The Conversation Status split, AI resolution rate, and deflection rate as the product defines them.
  </Card>

  <Card title="Resolution vs deflection" icon="scale-balanced" href="/en/performance/resolution-vs-deflection">
    Why Fini treats resolution rate as the metric that matters.
  </Card>

  <Card title="Billing FAQ" icon="circle-question" href="/en/billing/billing-faq">
    Short answers to common questions about invoices, payment, and what is billed.
  </Card>
</CardGroup>


## Related topics

- [Fini FAQ](/en/faq.md)
- [Resolution vs deflection](/en/performance/resolution-vs-deflection.md)
- [Billing FAQ](/en/billing/billing-faq.md)


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