> ## 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.

# Verify Domain

> Re-run or poll DNS verification for a custom sending domain.

**CLI:**

```bash theme={null}
puffle email domain verify --id <id>
puffle email domain verify --id <id> --poll <poll>
```

## Overview

`POST /api/email/domains/{id}/verify` (`verifyEmailDomain`) has two modes:

* **Trigger mode (default).** Pre-marks the domain `verifying`, kicks off an async DNS check, reads the live status back, and persists it along with the latest expected DNS records. If the post-call status is still `verifying`, the `domain-verify-poller` background task is scheduled (idempotency keyed per domain) so the DB converges even if the user closes the page.
* **Poll mode (`?poll=true`).** Skip the verify trigger and just read the live status. Use this on every polling tick — re-triggering verification on each tick restarts the async DNS checker and can cause visible flicker between `verifying`, `failed`, and back to `verifying`.

## AI agent notes

<Note>
  **DNS dependency.** Verification only succeeds after the required DKIM/SPF/DMARC records resolve on the domain. Creating the domain via `createEmailDomain` auto-syncs these records when Puffle can manage the zone; otherwise the user must add the records manually at their DNS provider before calling this endpoint.

  **Polling recipe.** Use `verifyEmailDomain` (no flag) once to start the verification, then hit it with `?poll=true` every 30–60 seconds until `status` is `verified` or `failed`. The background `domain-verify-poller` will keep re-checking on exponential backoff (10m, 20m, 40m, 80m, 160m, 320m) for up to 12 hours even without client-side polling.

  **Idempotency is enforced.** Repeated trigger calls collapse into the original poller chain via a per-domain idempotency key.
</Note>


## OpenAPI

````yaml post /api/email/domains/{id}/verify
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/domains/{id}/verify:
    post:
      tags:
        - Senders
      summary: Verify Domain
      description: >-
        Re-run DNS verification for a custom sending domain. Without
        `?poll=true`, the row is pre-marked `verifying`, an async DNS check is
        kicked off, and the live status is read back and persisted with the
        latest DNS records. With `?poll=true`, no verification is re-triggered;
        only the live status is read on every polling tick to avoid restarting
        the async DNS checker. If the post-verify status is still `verifying`,
        the `domain-verify-poller` background task is scheduled so the DB
        converges even if the user closes the page. Idempotency is enforced via
        a per-domain key so repeated triggers collapse into the original poller
        chain.
      operationId: verifyEmailDomain
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
            minLength: 1
            description: Email domain (`email_domains.id`) UUID.
        - name: poll
          in: query
          required: false
          schema:
            description: >-
              If `true`, skip triggering a verification check and only read the
              current live status. Use this on every polling tick so the async
              DNS checker is not restarted repeatedly, which can cause flicker
              `verifying → failed → verifying`.
            type: string
            enum:
              - 'true'
              - 'false'
      responses:
        '200':
          description: >-
            Domain verification state after this call. `status` is `verified` on
            success, `verifying` if DNS is still propagating, or `failed` if the
            verification service rejected the records. `dns_records` is always
            refreshed with the live expected values.
          content:
            application/json:
              schema:
                type: object
                properties:
                  domain:
                    type: object
                    properties:
                      id:
                        type: string
                        format: uuid
                      user_id:
                        type: string
                        format: uuid
                      domain:
                        type: string
                      status:
                        type: string
                        enum:
                          - pending
                          - verifying
                          - verified
                          - failed
                    required:
                      - id
                      - user_id
                      - domain
                      - status
                    additionalProperties: {}
                    description: Verified email domain row.
                required:
                  - domain
                additionalProperties: false
        '401':
          description: Missing or invalid Bearer token.
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                required:
                  - error
                additionalProperties: false
        '404':
          description: Domain doesn't exist or isn't owned by the caller.
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                required:
                  - error
                additionalProperties: false
        '500':
          description: >-
            Database update failed after the verification check ran, or the
            verification service errored out.
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                required:
                  - error
                additionalProperties: false
components:
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      bearerFormat: pk_live_...

````