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

# Auto-close stale conversations

> Automatically close inbox conversations that have gone idle for a set number of days. Configure the idle window and the statuses a background sweep is allowed to close, understand the rows it never touches, and split auto-closed volume from agent-driven closes in reporting.

# Auto-close stale conversations

Idle threads pile up. Customers who never come back leave rows stuck in the open queue, distorting queue length, per-agent open counts, and the inbox list every agent works from. Auto-close is the tenant-owned control that sweeps those rows away: a background job checks every workspace every 10 minutes and closes conversations that have passed a configurable idle window — no customer message for N days.

Every auto-closed row is marked `closed_reason: "auto_stale"`, fires the same `conversation.closed` webhook a manual close fires, and is logged to the audit trail as `conversation.auto_closed_stale` — so downstream reporting splits platform-closed volume from agent-closed volume.

The feature ships **off**. Nothing changes for your conversations until an owner or admin turns it on.

## Configure auto-close

Open **Inbox → Settings → Auto-close stale conversations** (owner or admin). The page controls three things:

* **Enable auto-close** — the master switch. Off by default; off pauses the sweep without losing your other settings.
* **Idle window** — how many days a conversation can sit without a new message before the sweep closes it. A whole-number slider from **1 to 90 days**, default **7**. Fractions and out-of-range values are clamped on save.
* **Statuses to close** — which statuses the sweep is allowed to close: **open**, **pending**, or both. At least one must be selected; the save button is disabled otherwise.

The organisation is the scope: the configuration is workspace-wide, not per-channel or per-queue. A single ownership boundary means one agent team can't inherit another team's silence threshold.

Saved changes take effect on the next sweep — at most 10 minutes later.

## What counts as idle

Idle is measured from the conversation's most recent message timestamp, on either party. Any message — customer, agent, or AI — restarts the window, so an active thread is never swept. A conversation with no messages at all is also never swept: a never-messaged row is treated as bootstrap noise, not staleness.

The idle window is a floor, not a precision timer. A conversation that crosses the threshold is closed on the next 10-minute sweep, so the effective close lands between N days and N days plus 10 minutes after the last message.

## What auto-close never touches

The sweep applies several guardrails in every pass, independent of your configuration:

* **Resolved, closed, archived, and snoozed threads** — terminal and paused statuses are excluded from the sweep regardless of the statuses you select.
* **Anything already closed** — a double check alongside the status filter, so a row can't be re-processed.
* **Never-messaged threads** — as above.
* **Threads still inside the idle window** — any row whose last message is younger than the configured window.

Two adjacent lifecycle guardrails live outside the sweep itself and interact with it:

* **Pending reply approvals.** A reply awaiting supervisor approval is a message row on the conversation (`pending` state) and therefore restarts the idle timer — a thread can't be swept while an approval is outstanding. See [Reply approvals](/inbox/reply-approvals).
* **AI auto-deflection.** Auto-deflect's post of a KB answer counts as a message for idleness. On the negative-sentiment guardrail, the AI answer is posted but the thread is deliberately **held open** for a human — it stays in `open` until your configured scope and idle window eventually sweep it. Shorten the window or un-scope `open` only if the intent is for swept negative-sentiment threads to stop waiting on an agent.

## How auto-close fits the conversation lifecycle

Auto-close is a full-status close — not a soft-hide. It does exactly what an agent clicking **Close** does, with three deliberate differences:

1. **`closed_reason: "auto_stale"` is stamped on the conversation.** Agent-driven closes leave the reason null. Every reports surface and the conversation list filter the two.
2. **The `conversation.closed` webhook fires**, exactly as it does for a manual close — payload below. A subscribed CRM updates on the sweep, not just on human action.
3. **The audit event differs**: `conversation.auto_closed_stale` rather than `conversation.closed`, so an audit filter separates platform decisions from human ones.

The real-time inbox event also fires on the same `conversation.closed` channel, so an agent watching the thread sees it leave their queue in under a second.

Reopening works identically either way: reopen an auto-closed thread and the closed-reason marker stays on the row for reporting, but the conversation is live again.

### Webhook payload on an auto-close sweep

```json theme={null}
{
  "conversation_id": "conv_01HF…",
  "status": "closed",
  "reason": "auto_stale",
  "channel": "whatsapp",
  "closed_at": "2026-08-30T14:11:07.412Z"
}
```

The `reason` field is what tells your CRM the sweep did it, not a person. Subscribe under **Settings → Webhooks** with the `conversation.closed` event, same as for manual closes.

## Reporting auto-closed vs agent-resolved volume

Filter on the closed-reason column; it is the single split point:

* **Auto-close volume for a period** — count conversations closed with `closed_reason = 'auto_stale'` in the window. Counted once per close.
* **Agent-driven close volume for the same period** — count conversations closed with a null closed reason.

A large auto-close share usually means one of two things: agents are leaving resolved work in `open` instead of closing it, or the idle window is longer than customer patience. Check the trend before changing the window — the settings page is deliberately low-friction, so a trend-based correction is cheap, but changing the number without a diagnosis tends to just move the same misclassification.

## Troubleshooting

| Symptom                                                   | Cause                                                                                                                                         | Fix                                                                                                                                                                                                                                           |
| --------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **The idle timer keeps resetting on quiet threads**       | AI auto-deflection keeps answering every customer ping, and each answer restarts the timer. Or pending-approval replies keep the thread warm. | Decide whether deflected threads should wait for a human — if not, shorten the window, or scope both `open` and `pending`. Pending approvals are working as designed; clear the approval queue faster or accept that those threads stay open. |
| **A conversation an agent was typing in was auto-closed** | Typing is not a message. The timer only stops when the reply is actually sent.                                                                | Long idle windows make this rare; if it happens, reopen the thread — the reply sends after reopening. Encourage agents to send partial replies (or close the thread deliberately) rather than hold long drafts.                               |
| **Threads closed despite the toggle being off**           | The toggle was never off, or the off-save failed silently and the old on-config was still live.                                               | Re-open the settings page, confirm **Enable auto-close** reads off, then check the timestamps on the audit trail entries (`conversation.auto_closed_stale`) — all entries predate the last successful off-save.                               |
| **A snoozed thread still got closed**                     | By design, never. If this happens, the thread was in `open` or `pending` at sweep time — snoozed is excluded from the sweep scope.            | Check the conversation's status history; a re-open dropped the snooze.                                                                                                                                                                        |
| **The sweep seems to skip everything**                    | The sweep is per-tenant opt-in; if `enabled` was saved on but the sweep sees no eligible rows, it logs nothing.                               | Verify new incoming threads are actually reaching `open`/`pending` and ageing out; confirm with a narrow window (1 day) on a test queue before settling on the production window.                                                             |

***

Related: [Reply approvals](/inbox/reply-approvals) · [Webhooks — conversation.closed](/webhooks/events) · [Inbox SLA timers](/guides/inbox-sla-timers)
