# `Accrue.Jobs.DetectExpiringCards`
[🔗](https://github.com/szTheory/accrue/blob/accrue-v0.3.0/lib/accrue/jobs/detect_expiring_cards.ex#L1)

Scheduled Oban worker for expiring-card detection (D3-71..78, BILL-24).

Scans `accrue_payment_methods` with non-nil `exp_month` / `exp_year`,
computes days-until-expiry (end of expiry month), and emits a
`card.expiring_soon` event + telemetry for each PM whose remaining
days matches one of the configured thresholds.

Thresholds come from `Accrue.Config.get!(:expiring_card_thresholds)`
(default `[30, 7, 1]`).

## Dedup via accrue_events

To prevent re-emission on subsequent sweeps, the worker queries
`accrue_events` for any `card.expiring_soon` event with matching
`(subject_id, data.threshold)` within the last 365 days. The 1-year
window covers the typical card lifecycle without leaving a stale
dedup entry forever.

No new column is added to `accrue_payment_methods` for dedup — the
event ledger IS the dedup source of truth (D3-14, EVT-04).

---

*Consult [api-reference.md](api-reference.md) for complete listing*
