> ## Documentation Index
> Fetch the complete documentation index at: https://docs.puffle.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Get Warmup Analytics

> Fetch current warmup analytics and auto-apply status transitions for every warming/warmed/active inbox.

**CLI:**

```bash theme={null}
puffle email account warmup-analytic
```

## Overview

Separated from `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:

1. **Analytics fetch.** For every account with `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 the warmup provider. Fetches are serialised to avoid provider rate limits.
2. **Auto-transitions.** Two transitions are applied inline and reflected in the `transitions` map:
   * **Ban / suspend:** if the provider warmup status is `-1` (banned), `-2` (spam unknown), or `-3` (suspended), we set our `warmup_status` to `banned`/`suspended` and `status` to `error`.
   * **Graduate:** if a `warming` account has `warmup_reputation ≥ 90` AND `total_sent ≥ 200`, we flip both `warmup_status` and `status` to `active`.

## AI agent notes

<Note>
  **Warmup is a multi-day process.** `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.
  * Accounts that failed their warmup analytics fetch are silently omitted from `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.

  **Gate campaigns on `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`.
</Note>


## OpenAPI

````yaml get /api/email/accounts/warmup-analytics
openapi: 3.0.3
info:
  title: Puffle API
  version: 1.0.0
  description: >-
    HTTP API for the Puffle GTM platform - Feed and Lead Finder search
    preparation, campaign-backed Outbound execution, Puffle Agent runs, sender
    management, and Unibox reply workflows. Designed for operation by both
    humans and autonomous AI agents. Agents should start at the [Agent
    Playbook](/guides/agent-playbook) which prescribes a workspace-context check
    (`GET /api/context`) and core user journeys with exact call ordering.
  contact:
    name: Puffle Support
    url: https://puffle.ai
servers:
  - url: https://app.puffle.ai
    description: Production
security:
  - bearerAuth: []
tags:
  - name: Campaigns
    description: >-
      Campaign-backed Outbound execution. These endpoints manage draft,
      launching, active, paused, and completed Outbound runs with sequence
      nodes, contacts, and sender accounts.
  - name: Accounts
    description: Signed-in user account, settings, and workspace context endpoints.
  - name: Billing
    description: Billing customer portal and account billing endpoints.
  - name: Senders
    description: >-
      Connected sender accounts, email inboxes, sending domains, DNS
      verification, warmup, and sender capacity.
  - name: Socials
    description: >-
      Read connected LinkedIn and X accounts, review current and archived posts,
      and reconcile publication status. Creating, editing, scheduling,
      publishing, OAuth connection, analytics, and mentions remain
      dashboard-managed workflows and are not part of the public Bearer-token
      API.
paths:
  /api/email/accounts/warmup-analytics:
    get:
      tags:
        - Senders
      summary: Get Warmup Analytics
      description: >-
        Fetch current warmup analytics for every email account the caller owns
        whose `warmup_status` is `warming`, `warmed`, or `active`. Separated
        from the main accounts endpoint so the UI can render the account list
        immediately and lazy-load the slower warmup calls. Also performs two
        synchronous side effects per account: (1) if the warmup provider reports
        the account banned (`-1`) or suspended (`-2`/`-3`), we set
        `warmup_status` to `banned`/`suspended` and `status` to `error`; (2) if
        a `warming` account has reputation ≥ 90 and total_sent ≥ 200, we
        auto-promote it to `active` / `active`. Both transitions are reflected
        in the `transitions` field of the response. Fetches are serialized to
        avoid warmup-provider rate limits.
      operationId: getWarmupAnalytics
      parameters: []
      responses:
        '200':
          description: >-
            Per-account warmup analytics plus any status transitions applied on
            this call.
          content:
            application/json:
              schema:
                type: object
                properties:
                  analytics:
                    type: object
                    additionalProperties:
                      type: object
                      properties:
                        email:
                          type: string
                          format: email
                        total_sent:
                          type: integer
                          minimum: 0
                          maximum: 9007199254740991
                          description: Lifetime warmup emails sent from this inbox.
                        total_received:
                          type: integer
                          minimum: 0
                          maximum: 9007199254740991
                          description: Lifetime warmup emails received into this inbox.
                        health_score:
                          type: number
                          description: >-
                            Deliverability health score. Starts at 100 and
                            degrades on spam placement.
                        health_score_label:
                          type: string
                        warmup_reputation:
                          type: number
                          description: >-
                            0–100. Climbs over time as warmup traffic lands in
                            the inbox. Use this (not `health_score`) to decide
                            whether warmup is 'done'.
                        instantly_warmup_status:
                          type: integer
                          minimum: -9007199254740991
                          maximum: 9007199254740991
                          description: >-
                            Warmup provider status code. 1=Active, 0=Paused,
                            -1=Banned, -2=Spam Folder Unknown, -3=Permanent
                            Suspension.
                        daily_data:
                          type: array
                          items:
                            type: object
                            properties:
                              date:
                                type: string
                                description: YYYY-MM-DD, oldest-first ordering.
                              sent:
                                type: integer
                                minimum: 0
                                maximum: 9007199254740991
                              received:
                                type: integer
                                minimum: 0
                                maximum: 9007199254740991
                            required:
                              - date
                              - sent
                              - received
                            additionalProperties: {}
                            description: One day of warmup activity for a single account.
                      required:
                        - email
                        - total_sent
                        - total_received
                        - health_score
                        - health_score_label
                        - warmup_reputation
                        - instantly_warmup_status
                        - daily_data
                      additionalProperties: {}
                    description: >-
                      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 because of a warmup-provider error are silently
                      omitted.
                  transitions:
                    type: object
                    additionalProperties:
                      type: object
                      properties:
                        warmup_status:
                          type: string
                          enum:
                            - warming
                            - active
                            - banned
                            - suspended
                            - not_started
                            - paused
                          description: >-
                            New `accounts.warmup_status` applied during this
                            GET. `active` means warmup finished (reputation ≥ 90
                            and total_sent ≥ 200). `banned` / `suspended` are
                            mirrored from negative warmup provider status codes.
                        status:
                          type: string
                          enum:
                            - active
                            - error
                            - warming
                            - pending
                          description: >-
                            New `accounts.status` applied during this GET.
                            `error` is set alongside `banned`/`suspended`;
                            `active` alongside a warmup graduation.
                      required:
                        - warmup_status
                        - status
                      additionalProperties: false
                    description: >-
                      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.
                required:
                  - analytics
                  - transitions
                additionalProperties: false
        '401':
          description: Missing or invalid Bearer token.
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                required:
                  - error
                additionalProperties: false
        '500':
          description: Database read failed or unexpected server error.
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                required:
                  - error
                additionalProperties: false
components:
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      bearerFormat: pk_live_...

````