---
title: "Stale Sweep"
method: POST
path: "/api/support/bot/sweep"
tags: ["support-bot"]
---

# Stale Sweep

`POST /api/support/bot/sweep`

Run one stale-sweep pass: force-escalate bot-handled conversations that
sat unresolved past ``max_age`` (ADR-0049). Called every 10 min by the
``support-stale-sweep`` k8s CronJob — the safeguard's ONLY production
trigger since the webhook replaced the polling loop the sweep lived in.
The per-run escalation cap keeps the drain under the Yani watcher's
storm-breaker threshold.

The cron sends the secret as ``X-Webhook-Secret`` — a query secret lands in
the gunicorn access log on every run (144×/day). ``?secret=`` stays accepted
only because `_check_secret` is shared with the Crisp webhook, which can't
set headers.

The response reports denominators (``pages``/``candidates``) on purpose:
``escalated: 0`` alone can't distinguish "all clear" from "discovery went
blind" (digest-style rule 9).

## Query parameters

- `secret` string, nullable
- `max_age` number
- `cap` integer, nullable

## Headers

- `X-Webhook-Secret` string, nullable

## Response `200`

Successful Response

- object

## Other responses

- `422` — Validation Error

---

[API](https://skmtc.dev/explee/apis/explee-api.md) · [All operations](https://skmtc.dev/explee/apis/explee-api/llms.txt) · [OpenAPI document](https://skmtc-service-production.skmtc.workers.dev/v1/apis/explee/explee-api/revisions/aec0744a2cd1/schema)
