Skip to main content

Inbox lifecycle hygiene — auto-close, and tags and dispositions at close

An open queue that never gets swept stops meaning anything. Customers who never reply leave rows parked in open or pending; queue length, per-agent open counts, and freshness metrics all inflate. The hygiene jobs fix that on two axes: deterministic cleanup (the auto-close sweep closes idle threads on a schedule) and consistent close-out metadata (tags and dispositions applied the same way at close, so reports can trust the label). This guide covers the auto-close sweep. SLA timers are a separate guide — see Inbox SLA timers.

1. The hygiene jobs

Auto-close is a per-workspace opt-in sweep that runs every 10 minutes and closes any conversation whose most recent message — customer, agent, or AI — is older than your configured idle window. Every auto-closed row is stamped 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 always separates platform-closed volume from agent-closed volume. Tags and dispositions at close are the second axis. A conversation closed with no disposition and no tags is a report row you cannot filter. Apply a customer-defined auto-closed tag and a customer-defined no-reply disposition whenever the sweep (or a human closing purely to clear the queue) closes a thread, and your report filters can exclude that whole class cleanly.

2. Where they live

Inbox → Settings → Auto-close (owner or admin) is the control surface for the sweep — the page header links the background job documentation; this guide owns the auto-close workflow end to end. Reference detail for the same page lives at Auto-close stale conversations — the two pages serve different reader needs (walkthrough vs. reference). Tags live at Inbox → Settings → Tags and dispositions at Inbox → Settings → Dispositions. Both consoles write the vocabulary that the close-time labels draw from; create the vocabulary there first, then close-time automation has something to apply.

3. What the sweep does on each tick

On every 10-minute tick the sweep:
  1. Reads the workspace-level configuration: enabled, idle-days bound (1–90, default 7), and eligible statuses (open, pending, or both).
  2. Skips the workspace entirely if the sweep is off, so an off-save is a full pause that preserves your other settings.
  3. Atomically claims up to 500 rows per tick per workspace (oldest-idle first) and flips them to closed. The claim guard keeps two replicas from double-closing a row; the per-tick cap keeps the sweep from blowing the transaction budget.
  4. Stamps each closed row with closed_reason = "auto_stale", sets the resolved timestamp, and fills in the resolution duration so dashboards display a coherent number.
  5. Fires the real-time inbox event plus the conversation.closed webhook per row, and writes the audit entry.

What downstream pipelines must tolerate

Any export, report, or data pipeline that reads conversations must tolerate the auto_stale marker, not just manual closes. Check:
  • Warehouse exports — the closed-reason column is nullable; treat null as an agent-driven close, and treat auto_stale as a platform-driven close.
  • Report filters — an Insights query that filters “closed conversations” over-counts if it doesn’t explicitly include closed_reason in the projection.
  • Webhook consumers — the conversation.closed payload carries a reason field exactly for this.

4. Walkthrough — bind the idle window, save, monitor

Open Inbox → Settings → Auto-close (owner or admin).
  1. Enable auto-close. The master switch; leave it off while you pick the window — turning the sweep on with a bad window is the one mistake this page can’t absorb.
  2. Set the idle-days bound. The slider is a whole number from 1 to 90 days, default 7. Fractions and out-of-range values are clamped on save.
  3. Pick the eligible statuses. open and pending are the only statuses the sweep can close; at least one must be selected, or the save is blocked.
  4. Save. Changes take effect on the next sweep — at most 10 minutes later.
  5. QA the sweep before it scales. If your queue carries a long-lived backlog, give the first save a narrow window (1–2 days), watch the audit trail for a few ticks at conversation.auto_closed_stale, and check that closed rows read the way your reports expect — then settle on the production window. That same audit filter is how you build the recurring QA panel: Settings → Audit log → filter on conversation.auto_closed_stale is the honest “top auto-close rows” view, sorted by close time.
  6. Monitor downstream. The sweep fires a conversation.closed webhook per closed row; if you want a Slack or dev notification on every auto-close, register a webhook endpoint subscribed to conversation.closed and filter on reason: "auto_stale". Endpoint creation is under Settings → Webhooks.
The sample CRON semantics: the sweep is a 10-minute periodic job, not a wall-clock cron expression. A conversation crossing the idle threshold is closed on the next tick, so the effective close lands between N days and N days plus 10 minutes after the last message. If you prefer the API, the same page reads and writes through the organization settings endpoints:
GET /api/v1/settings/general returns the same block. Values you write directly are subject to the same clamps the page applies — idle days are floored to a whole number and clamped to 1–90, and statuses outside the open/pending allow-list are filtered out. An empty statuses array re-expands to both statuses on the next read, so never persist an empty array to “pause” the sweep — use enabled: false.

5. Tags and dispositions applied at close

The sweep itself stamps only the closed-reason marker; tags and dispositions are a separate vocabulary you own. The recommended pattern for close-time consistency:
  1. Create a tag named auto-closed at Inbox → Settings → Tags (see Tags). Apply it whenever you close a thread purely because it went stale — manually or as part of a bulk tidy-up. The tag is the report-side marker that survives a reopen: a reopened-and-reclosed thread still carries it.
  2. Create a disposition set with a no-reply label at Inbox → Settings → Dispositions (see Dispositions). Instruct agents and any close-out automation to apply no-reply when the thread was closed because the customer never responded.
  3. Build report filters on the pair. Filter closed conversations on closed_reason = "auto_stale" for sweep-driven volume, on tag auto-closed for any staleness close regardless of who clicked it, and on disposition no-reply for the outcome the customer produced (silence). The three axes are deliberately independent — conflating them into one label makes the report lie on at least one of them.
A close without a disposition is not a report failure, but a close without a reason is. The closed-reason column is always authoritative; tags and dispositions layer the human-readable interpretation on top.

6. Failure modes

  • Reopened-after-close. A customer reopens an auto-closed thread the way any close is reopened — the closed_reason marker stays on the row for reporting, but the conversation is live again and the idle window restarts on the next message. Reopened volume for auto-closed threads is a real signal: if a material share of swept threads reopens, the idle window is shorter than your customers’ return cadence.
  • Quality-score consistency. AI Auto-QA scores completed agent-handled calls; the auto-close sweep is a conversation-side cleanup, so sweep closes never enter or block the call-side autoscore pipeline. The conversation-side QA risk is different — a conversation closed by the sweep with no agent interaction yet carries no agent context, so any evaluation a human reviewer later writes by hand on that thread measures the cleanup itself, not the agent. Treat auto-closed rows as a separate volume in your QA ledger and do not let a rising auto-close share inflate or deflate an agent’s evaluation sample.
  • Hospitality-score consistency. Any aggregate that divides by “number of closed conversations” includes sweep closes; any aggregate that divides by “number of agent-handled conversations” should not. Keep the denominators separate — conflating them manufactures a declining trendline when the only change is that the sweep is doing more cleanup.
  • Sweep closes in bounded batches of 500 per tick. If your first save lands on a long-idle queue with thousands of eligible rows, the sweep drains up to 500 per workspace per 10-minute tick — roughly 3,000 rows per hour until the backlog clears. That is the design trade: bounded transactions over instant drain. Reopen by disabling the sweep in the interim only if you actually want the backlog to stay live.

Related: Auto-close stale conversations · Inbox SLA timers · Tags · Dispositions · Quality management program