---
title: "Ticket lifecycle sweeps, dry run by default (POST)"
method: POST
path: "/cron/stale-in-progress"
tags: ["Cron"]
---

# Ticket lifecycle sweeps, dry run by default (POST)

`POST /cron/stale-in-progress`

## Request

- Base URL: `https://api.apphandoff.com/api`
- URL: `https://api.apphandoff.com/api/cron/stale-in-progress`
- Auth: none required

Scheduled hourly as the `stale-in-progress` stage of the Slipstream `hourly-sweeps`
schedule (`scripts/cron-stale-in-progress.sh`, which sends `dry_run=1` unless
`TICKET_LIFECYCLE_LIVE=1`). Same behaviour and parameters as GET; `dry_run` may also
be sent as a JSON body field (`{"dry_run": 0}`), the query string winning when both
are present. Protected by CRON_SECRET via the x-cron-secret header.

## Query parameters

- `dry_run` '0' | '1'

## Request body

- object
  - `dry_run` union: Only an explicit 0 (or the string "0", or false) runs for real.
    - integer
    - string
    - boolean

## Response `200`

Lifecycle sweep result

- CronStaleInProgressResult
  - `ok` boolean, required: AND of the three sweeps' `ok`. The best-effort retention sweep never affects it.
  - `dry_run` boolean, required: True unless the caller sent an explicit `dry_run=0`.
  - `closing_line_close` CronLifecycleSweepResult, required
    - `ok` boolean, required: False when a read the sweep depends on failed, or the sweep threw. A truncation never sets it.
    - `dryRun` boolean, required
    - `scanned` integer, required: Candidate rows read.
    - `acted` integer, required: Tickets closed, moved or archived (in a dry run, the tickets that would be).
    - `skipped` integer, required: Eligible tickets left alone — a lost race, a refused write, or a read that failed closed.
    - `errors` integer, required
    - `truncated` boolean, required: True when the per-tick cap, the shared deadline or the scan cap stopped the sweep before every candidate was seen.
    - `samples` object[], required: Up to 25 tickets the sweep acted on or skipped.
      - `ticketId` string, required
      - `number` integer, nullable, required
      - `action` string, required: closed | would_close | returned | would_return | archived | would_archive | skipped
      - `reason` string
  - `in_progress_return` CronLifecycleSweepResult, required
    - `ok` boolean, required: False when a read the sweep depends on failed, or the sweep threw. A truncation never sets it.
    - `dryRun` boolean, required
    - `scanned` integer, required: Candidate rows read.
    - `acted` integer, required: Tickets closed, moved or archived (in a dry run, the tickets that would be).
    - `skipped` integer, required: Eligible tickets left alone — a lost race, a refused write, or a read that failed closed.
    - `errors` integer, required
    - `truncated` boolean, required: True when the per-tick cap, the shared deadline or the scan cap stopped the sweep before every candidate was seen.
    - `samples` object[], required: Up to 25 tickets the sweep acted on or skipped.
      - `ticketId` string, required
      - `number` integer, nullable, required
      - `action` string, required: closed | would_close | returned | would_return | archived | would_archive | skipped
      - `reason` string
  - `stale_archive` CronLifecycleSweepResult, required
    - `ok` boolean, required: False when a read the sweep depends on failed, or the sweep threw. A truncation never sets it.
    - `dryRun` boolean, required
    - `scanned` integer, required: Candidate rows read.
    - `acted` integer, required: Tickets closed, moved or archived (in a dry run, the tickets that would be).
    - `skipped` integer, required: Eligible tickets left alone — a lost race, a refused write, or a read that failed closed.
    - `errors` integer, required
    - `truncated` boolean, required: True when the per-tick cap, the shared deadline or the scan cap stopped the sweep before every candidate was seen.
    - `samples` object[], required: Up to 25 tickets the sweep acted on or skipped.
      - `ticketId` string, required
      - `number` integer, nullable, required
      - `action` string, required: closed | would_close | returned | would_return | archived | would_archive | skipped
      - `reason` string
  - `agent_notification_retention` object, required
    - `ok` boolean, required

## Other responses

- `401`: Missing or invalid CRON_SECRET

---

[API](https://skmtc.dev/apphandoff/apis/apphandoff-api.md) · [All operations](https://skmtc.dev/apphandoff/apis/apphandoff-api/llms.txt) · [OpenAPI document](https://skmtc.dev/apphandoff/apis/apphandoff-api/revisions/9f138fe46d56?raw)
