---
title: "Day-1 nudge email to stalled sign-ups, dry run by default (GET)"
method: GET
path: "/cron/stalled-signup-nudge"
tags: ["Cron"]
---

# Day-1 nudge email to stalled sign-ups, dry run by default (GET)

`GET /cron/stalled-signup-nudge`

## Request

- Base URL: `https://api.apphandoff.com/api`
- URL: `https://api.apphandoff.com/api/cron/stalled-signup-nudge`
- Auth: none required

HO-18477. Emails ONE reminder to each user who confirmed their address 24-72h
ago and has no workspace membership, no successful MCP call, no OAuth grant,
no invite, is not a superadmin or an E2E identity, and has not unsubscribed.
Exactly-once per user (pending -> sending -> sent | failed | unknown; a
delivery-unknown send is never retried). Each email carries List-Unsubscribe
and List-Unsubscribe-Post headers pointing at /email/unsubscribe/{token}.
DRY RUN BY DEFAULT: without an explicit `dry_run=0` (query, or JSON body
`dry_run` 0 / "0" / false) the route only counts the cohort (`would_claim`)
and claims and sends nothing. The pg_cron job
`stalled-signup-nudge` (scheduled inactive) passes `dry_run=0`. Protected by
CRON_SECRET via the x-cron-secret header.

## Query parameters

- `dry_run` string

## Response `200`

Nudge run counts

- CronStalledSignupNudgeResult
  - `ok` boolean, required: False on any error.
  - `dry_run` boolean, required: True unless the caller sent dry_run=0.
  - `would_claim` integer, nullable, required: Dry run only — users a live tick would claim now; null on a live run or a failed preview.
  - `claimed` integer, required: Users claimed by this run.
  - `sent` integer, required: Nudges accepted by Mailgun.
  - `skipped` integer, required: Claimed users deliberately not emailed (E2E identities, or no longer eligible at send time).
  - `failed` integer, required: Definite pre-delivery failures; retried after the lease until the attempt ceiling.
  - `unknown` integer, required: Sends whose delivery is unknown (timeout/abort); terminal, never retried.
  - `deferred` integer, required: Claimed users not attempted this run (the circuit breaker after a failed or unknown send, or the 90s send deadline); left pending and re-claimed after the lease.
  - `errors` integer, required: Failures of any kind (preview, claim, send, or outcome bookkeeping).

## Other responses

- `403`: 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)
