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

# List Domain Pool

> List every domain the caller owns, with rotation + warmup state.

## Authentication

Requires `X-Agent-ID` header with your wallet address. Free read endpoint —
no x402 payment required.

## Response

<ResponseField name="agent_id" type="string">
  The caller's wallet (echoed).
</ResponseField>

<ResponseField name="domains" type="array">
  Every non-`removed` domain the caller owns. Ordered by `created_at`
  ascending (oldest first), matching how agents typically think about
  their pool (“first I bought…”).
</ResponseField>

### Each domain

<ResponseField name="domain" type="string">
  The bare domain — `oneshotagents.com`, `cina-lolucci.soulhunt.ai`, etc.
</ResponseField>

<ResponseField name="default_from" type="string">
  The canonical sending address for this domain (e.g. `agent@yourdomain.com`) — the
  default mailbox used when you don't pick a specific one. It's a real mailbox like
  any other: the first send from it incurs the one-time `mailbox_provisioning_fee`
  (it's in `addresses[]` as `active` afterward, then free). To use it, pass it as
  `from_address` on [`/email/quote`](/api-reference/email/quote) and `/email/send`.
  (Omitting `from_address` does not default to it on an explicit send — it triggers
  [domain rotation](/api-reference/email/quote#domain-rotation) at quote time, and
  on `/email/send` returns `400 missing_from_address` unless replaying a rotation
  quote or a threaded reply.)
</ResponseField>

<ResponseField name="addresses" type="object[]">
  The mailboxes already provisioned on this domain. You can send from any address on
  a domain you own; whether sending from a *new* one provisions a per-address mailbox
  (and bills a one-time `mailbox_provisioning_fee`) depends on the domain. Some
  domains provision + warm a real mailbox per address; relay/send-only domains send
  from any address without one. Don't infer pricing from an empty `addresses[]` —
  always read `mailbox_provisioning_fee` on the
  [`/email/quote`](/api-reference/email/quote) response (`0` = nothing extra billed).
  Each entry:

  <Expandable title="address entry">
    <ResponseField name="address" type="string">
      The full email address (lowercased), e.g. `sales@yourdomain.com`.
    </ResponseField>

    <ResponseField name="status" type="string">
      Mailbox provisioning state — `active`, `provisioning`, or `failed`. Only
      `active` counts as already-provisioned (free to send from).
    </ResponseField>

    <ResponseField name="warmup_state" type="string">
      Per-address reputation health — `warming`, `warmed`, or `degraded` (same
      meaning as the domain-level `warmup_state`). Each provisioned address is
      warmed individually.
    </ResponseField>
  </Expandable>
</ResponseField>

<ResponseField name="pool_status" type="string">
  **Rotation eligibility only.** One of:

  * `active` — eligible for [rotation](/api-reference/email/quote#domain-rotation).
  * `paused` — out of rotation. See `pause_reason` for why and whether it
    self-heals.
  * `removed` — never returned by this endpoint.

  (The legacy `warming` value is deprecated — warmup lifecycle now lives in
  `warmup_state`.)
</ResponseField>

<ResponseField name="warmup_state" type="string">
  **Reputation health, orthogonal to rotation.** A domain can be `paused`
  *and* `warming` at the same time. One of:

  * `warming` — building reputation, not yet graduated.
  * `warmed` — reputation `>= WARMUP_ACTIVE_THRESHOLD` (default 75); healthy.
  * `degraded` — reputation fell `< MIN_ROTATION_SCORE` (default 60) after
    the warmup grace period.
</ResponseField>

<ResponseField name="pause_reason" type="string | null">
  Why the domain is out of rotation (`null` when `active`):

  * `warming` — not yet graduated to rotation.
  * `low_reputation` — auto-demoted by the reconciler. **Self-heals**: returns
    to `active` automatically once `warmup_state` is `warmed` again. No manual
    resume needed.
  * `manual` — paused via [`/domains/:domain/pause`](/api-reference/email/domain-pause).
    Stays paused until you [resume](/api-reference/email/domain-resume) it; the
    reconciler will not auto-recover it.
</ResponseField>

<ResponseField name="provisioning_status" type="string">
  Underlying provisioning state — `unprovisioned`, `provisioning`,
  `verified`, or `blocked`. Distinct from `pool_status`: a `verified` row
  can still be out of rotation if `warmup_state` hasn't reached `warmed`.
</ResponseField>

<ResponseField name="warmup_score" type="integer | null">
  Latest reputation warmup score (0-100). Refreshed daily by the
  reconciler; `null` until the first poll lands. Drives `warmup_state`
  (`warmed` at `>= WARMUP_ACTIVE_THRESHOLD`, `degraded` at
  `< MIN_ROTATION_SCORE`), which in turn drives rotation auto-recovery.
</ResponseField>

<ResponseField name="warmup_score_updated_at" type="string | null">
  When `warmup_score` was last refreshed by the reconciler (ISO 8601),
  or `null` before the first poll.
</ResponseField>

<ResponseField name="warmup_started_at" type="string | null">
  When the domain was enrolled in warmup (ISO 8601). `null` for
  domains that predate the warmup integration and haven't been
  backfilled.
</ResponseField>

<ResponseField name="daily_send_limit" type="integer">
  Per-domain per-UTC-day cap consumed by the rotation selector. Defaults
  to `50`; freshly-enrolled domains start at `WARMUP_DAY1_LIMIT` (default
  20\) and ramp via the lifecycle reconciler.
</ResponseField>

<ResponseField name="daily_sent_count" type="integer">
  Count of recipient-units sent today (resets when `daily_sent_date`
  rolls over). Incremented by **both** rotation picks and pinned sends
  (explicit `from_address`), so it reflects total usage — but only rotation
  is *gated* by `daily_send_limit`; pinned sends count yet aren't blocked.
</ResponseField>

<ResponseField name="daily_sent_date" type="string | null">
  UTC date the current `daily_sent_count` belongs to.
</ResponseField>

<ResponseField name="last_used_at" type="string | null">
  When this domain was last picked by rotation (drives LRU ordering).
</ResponseField>

<RequestExample>
  ```bash cURL theme={null}
  curl -sS https://win.oneshotagent.com/v1/tools/email/domains \
    -H "X-Agent-ID: 0x..."
  ```

  ```javascript JavaScript theme={null}
  const res = await fetch(
    "https://win.oneshotagent.com/v1/tools/email/domains",
    { headers: { "X-Agent-ID": wallet } }
  );
  const { domains } = await res.json();
  ```

  ```typescript SDK theme={null}
  const { domains } = await agent.listDomains();
  // → [{ domain, pool_status, warmup_score, daily_send_limit, ... }, ...]
  ```
</RequestExample>

<ResponseExample>
  ```json Response theme={null}
  {
    "agent_id": "0x2b06a0b0bD111B83509C5850d934F5Bf2076B191",
    "domains": [
      {
        "domain": "oneshotagents.com",
        "default_from": "agent@oneshotagents.com",
        "addresses": [
          { "address": "agent@oneshotagents.com", "status": "active", "warmup_state": "warmed" },
          { "address": "sales@oneshotagents.com", "status": "active", "warmup_state": "warming" }
        ],
        "pool_status": "paused",
        "warmup_state": "degraded",
        "pause_reason": "low_reputation",
        "provisioning_status": "verified",
        "warmup_score": 48,
        "warmup_score_updated_at": "2026-06-22T10:00:46.988Z",
        "warmup_started_at": "2026-06-08T15:56:20.266Z",
        "daily_send_limit": 100,
        "daily_sent_count": 2,
        "daily_sent_date": "2026-06-21",
        "last_used_at": "2026-06-21T15:53:53.738Z"
      },
      {
        "domain": "soulhunt.ai",
        "default_from": "agent@soulhunt.ai",
        "addresses": [],
        "pool_status": "active",
        "warmup_state": "warmed",
        "pause_reason": null,
        "provisioning_status": "verified",
        "warmup_score": 82,
        "warmup_score_updated_at": "2026-06-22T10:00:46.988Z",
        "warmup_started_at": null,
        "daily_send_limit": 50,
        "daily_sent_count": 0,
        "daily_sent_date": null,
        "last_used_at": null
      }
    ]
  }
  ```
</ResponseExample>

## Notes

* This is a read-only inventory. To pause / resume rotation on a domain,
  see [pause](/api-reference/email/domain-pause) and
  [resume](/api-reference/email/domain-resume).
* Soul-owned domains (set via `domains.soul_agent_id`) are NOT returned
  here — this endpoint scopes by `agent_id` only.
* Use this before a high-volume send burst to confirm there's enough
  capacity left in the pool today. If `sum(daily_send_limit - daily_sent_count)`
  across `active` rows is below your batch size, consider buying another
  domain or waiting for the UTC rollover.
