Fetch current Instantly warmup analytics and auto-apply status transitions for every warming/warmed/active email account.
GET /api/email/accounts so the UI can render the account list immediately and lazy-load the slower warmup data without blocking the page. Two things happen in one pass:
warmup_status ∈ {warming, warmed, active} and a set email_address, we pull total_sent, total_received, health_score, warmup_reputation (0–100), and daily_data from Instantly. Fetches are serialised to avoid Instantly’s rate limits.transitions map:
instantly_warmup_status is -1 (banned), -2 (spam unknown), or -3 (suspended), we set our warmup_status to banned/suspended and status to error.warming account has warmup_reputation ≥ 90 AND total_sent ≥ 200, we flip both warmup_status and status to active.warmup_reputation climbs slowly and the daily counts update incrementally. Expect graduation (warming → active) in roughly 2–3 weeks for a new inbox, not hours. Polling this endpoint more than once every few minutes is wasteful.Reading the response:analytics is keyed by accounts.id — not by email address.analytics. Check the account list for which IDs you expected.transitions is a diff, not a snapshot. It only contains entries for rows that changed status on this call — empty object {} means nothing flipped.status: "active", not warmup_status. An active account is send-eligible; a warming account blocks campaign emails.When an account turns banned: alert the user. There is no retry path — the user must create a new email address on the same domain (or a new domain).Chains with: retryAccountWarmup for stalled pending accounts, launchCampaign once all senders are active.Bearer authentication header of the form Bearer <token>, where <token> is your auth token.
Per-account warmup analytics plus any status transitions applied on this call.
Map of accounts.id → analytics payload. Only accounts with warmup_status ∈ {warming, warmed, active} and a set email_address are included. Accounts that failed to fetch (Instantly-side error) are silently omitted.
Map of accounts.id → the status change applied during this call. Present only when a graduation or ban/suspend actually flipped the row — empty object {} if nothing changed. Use this to refresh UI state without re-reading accounts.