---
title: "Job Expire Grace"
method: POST
path: "/api/v1/admin/jobs/expire-grace"
tags: ["admin"]
---

# Job Expire Grace

`POST /api/v1/admin/jobs/expire-grace`

## Request

- Base URL: `https://core.mnemoverse.com`
- URL: `https://core.mnemoverse.com/api/v1/admin/jobs/expire-grace`
- Auth: API key in header `X-Admin-Key`

Hourly job over rows that carry a grace date.

Soft landing (mnemoverse-workspace DUNNING-DESIGN-2026-10-08): a past_due
episode ends when Stripe ends it — paid → active, cancelled → Free — so
this job never changes a past_due status. It does two things for them:

  - day 14 (7 days before grace_until): one reminder email per episode,
    recorded in payment_reminder_sent_at;
  - grace_until + PAST_DUE_UNRESOLVED_AFTER_DAYS: count the row as
    unresolved; the workflow fails on a non-zero count so a person looks.

over_limit rows whose grace expired are only reported; the write guard
enforces that block lazily.

Idempotent: a reminded row is not reminded again; nothing else is written.
Called every hour by .github/workflows/grace-expiration-cron.yml.

## Response `200`

Successful Response

- GraceExpirationResult
  - `scanned` integer, required: past_due and over_limit rows with a grace date
  - `reminded` integer, required: past_due rows claimed for the day-14 reminder in this run. The claim is recorded before the send, so a send that failed is counted here too and logged as payment_reminder_email_send_failed
  - `unresolved` integer, required: past_due rows Stripe should have ended days ago (lost webhook, changed Stripe settings); reported, not touched
  - `over_limit_expired` integer, required: over_limit rows whose grace expired (writes now blocked lazily)

## Other responses

- `400`: Validation error
- `401`: Unauthorized
- `403`: Forbidden
- `404`: Not found
- `429`: Rate limited
- `500`: Internal server error
- `503`: Service unavailable

---

[API](https://skmtc.dev/mnemoverse/apis/mnemoverse-core.md) · [All operations](https://skmtc.dev/mnemoverse/apis/mnemoverse-core/llms.txt) · [OpenAPI document](https://skmtc.dev/mnemoverse/apis/mnemoverse-core/revisions/1f5e0048f017?raw)
