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

# Generate available keyword or AI domain names

> Supports three request shapes:

- A `keyword` request runs the deterministic Buy Domains engine with
  Partner-safe neutral modifiers. It does not call Spider or AI.
- `type: branded` requires a URL. Spider reads the website,
  then concurrent AI workers generate brand-led names.
- `type: generic` accepts either a URL or a description. A
  URL uses Spider; a description skips Spider. Generic names do not
  use the company brand.

AI requests have a 15-second end-to-end ceiling. If Spider or AI fails,
times out, or returns no usable names, generation falls back to the
deterministic Partner prefix and suffix engine inside that same ceiling.

Fastly registrar availability is always required. Google and
Microsoft tenant probes are attempted only for Fastly-available names.
If a tenant probe fails or times out, the endpoint falls back to the
Fastly result. A confirmed Google or Microsoft tenant claim is still
excluded.

An uncached registrar lookup can take several seconds. `limited` keys
can call this endpoint.

Sandbox keys use the same request and response shape, but return
deterministic local availability without calling a registrar or tenant
provider. A returned sandbox name passes the same sandbox availability
check when it is submitted to an order, unless another order used it in
the meantime.

`limit` is the number of domain names returned in total across every
requested TLD (default 50, max 100), not a per-TLD count. Defaults to `.com`
when `tlds` is omitted. Use `GET /domains/tlds` as the live allowlist.

Names are grouped by TLD. The response also includes the requested
subset of live `pricingTlds` rows. TLD group keys have no leading dot
(`com`, not `.com`), and empty groups are omitted. `limited` keys can
call this endpoint.




## OpenAPI

````yaml /openapi.yaml post /domains/generate
openapi: 3.1.0
info:
  title: Peeker Partner API
  version: 1.0.0
  description: >
    White-label Peeker's email infrastructure: Google Workspace and Microsoft

    365 inboxes, deliverability monitoring, and self-healing domain swaps,

    from your own app. Create a provider workspace target, order licenses with
    imported or

    Peeker-managed domains, and Peeker's backend handles provisioning,

    DNS, forwarding, and lifecycle webhooks.


    Create a provider workspace target with `POST /workspaces`, then send its

    `wrk_...` ID to `POST /orders`. For Smartlead, create one main workspace,

    then add `client_id` to an order only when it should go to a client

    workspace. Omit it to order into the main workspace.


    ## Read first


    - **[Authentication](/authentication)**: bearer keys, live vs sandbox,
    request IDs.

    - **[Rate limits](/rate-limits)**: 600/min per key, 429 backoff.

    - **[Webhooks](/webhooks)**: signed events and delivery rules.

    - **[Async jobs](/concepts/async-jobs)**: what to poll vs subscribe to.

    - **[Best practices](/best-practices)**: errors, paging, idempotency.


    ## Concepts


    - **[Orders](/concepts/orders)**: statuses, sizing, pending actions, cancel.

    - **[Domains](/concepts/domains)**: inventory, `usable_for`, import,
    forwarding.

    - **[Bundles](/concepts/bundles)**: saved templates and capacity.

    - **[Swaps](/concepts/swaps)**: standard vs premium, renames.


    ## Workflow guides


    - **[Provider ordering](/guides/provider-ordering)** — create a provider
    workspace target and order through it.

    - **[Buying domains & ordering](/guides/buying-domains)** — the default
    flow: bundle, availability, order, webhooks.

    - **[Importing domains](/guides/importing-domains)** — bring in existing
    customer domains.

    - **[Forwarding](/guides/forwarding)** — point a domain at a marketing site.

    - **[How to implement domain swaps](/guides/domain-swaps)** — standard vs
    premium swaps.

    - **[Renaming inbox senders](/guides/user-name-swaps)** — change mailbox
    personas on a warm domain.


    ## Public ID prefixes


    | Prefix | Resource |

    | --- | --- |

    | `cus_` | Customer tracking record |

    | `wrk_` | Provider workspace |

    | `bun_` | Bundle |

    | `ord_` | Order |

    | `dom_` | Domain |

    | `pcl_` | Pool reservation |

    | `prp_` | Pool replacement |

    | `prl_` | Pool release |

    | `imp_` | Domain import job |

    | `fwj_` | Domain forwarding job |

    | `brj_` | Burned-domain replacement job |

    | `swp_` | Domain swap |

    | `act_` | Pending action |

    | `evt_` | Webhook event |
servers:
  - url: https://api.peeker.ai/partner/v1
    description: >-
      Same base URL for live and sandbox. The key prefix (`pk_live_…` /
      `pk_test_…`) picks the environment.
security:
  - BearerAuth: []
tags:
  - name: Account
    x-group: Account
    description: >
      Confirm an API key with `GET /me`. Returns environment (live or sandbox),

      permission preset, and the partner profile. See
      [Authentication](/authentication).
  - name: Provider workspaces
    x-group: Provider workspaces
    description: |
      A provider workspace is one reusable provider connection. Create it once,
      keep the returned `wrk_...` ID, and use it in orders and pool attach.
      Optional customer tracking stays on the target. Provider credentials stay
      internal and are never echoed.

      EmailBison requires a workspace API-user key. Super-admin keys are
      rejected. Instantly and Smartlead connections require `api_key`.
      Smartlead workspace creation takes a main API key and a label. Do not send
      `client_id` or customer data. Its login email and password are optional,
      but must be sent together. Google orders do not need the pair, and orders
      never accept it. Smartlead Microsoft orders and pool attach still use the
      workspace-saved pair. Add
      `client_id` to the order destination when the order belongs to a client
      workspace; omit it for the main workspace.
      PlusVibe setup requires `api_key`, remote `workspace_id`, and its login
      email/password pair so orders and pool attach work immediately. Instantly
      login credentials belong on an order destination.
  - name: Bundles
    x-group: Bundles
    description: |
      Saved order template sized by monthly sending volume (`bun_…`). Pass
      `bundle_id` on an order instead of custom license counts.

      Lifecycle: [How bundles work](/concepts/bundles).
  - name: Domains
    x-group: Domains
    description: >
      Sending domains in your partner account (`dom_…`). Same ID whether or not

      the domain is on an order.


      **Status values**


      | Value | What it means |

      | --- | --- |

      | `available` | The domain is in inventory but not on an order yet. |

      | `in_progress` | We're setting it up. |

      | `active` | Live and warming or healthy. |

      | `failed` | Something broke that we can't fix automatically. |

      | `action_required` | We need your help (e.g. update nameservers). |


      **Inventory vs connected**


      - `category=inventory` — yours but not on any order. Inventory rows
        don't include `provider`.
      - `category=connected` — on an active order. The row carries the link
        fields `provider`, `customer_id`, `order_id`, `usable_for`, and
        `forwarding_url`.

      **`usable_for` matrix**


      When you check a domain's availability:


      | Who's on the domain | `usable_for` |

      | --- | --- |

      | Nobody, or just Google | `["google", "microsoft"]` |

      | Microsoft (or both) | `["google"]` |

      | Premium / invalid / errored | not orderable; `available: false` with a
      `reason` |


      **Imports and forwarding are jobs**


      Both **import** and **forwarding** are async jobs. Posting to those

      endpoints starts the job and gives you back a row with `status:

      "in_progress"`. Poll the job's GET endpoint to see when it finishes:


      - Import jobs: prefix `imp_…`. Includes the `nameserver_groups` your
        customer needs to set at their registrar.
        - Forwarding jobs: prefix `fwj_…`. Already-correct domains are
          returned in `completed` with newly updated domains.
  - name: Domain pool
    x-group: Domain pool
    description: |
      Assign an exact quantity from pre-warmed Google inventory. Each domain
      needs at least one active Google inbox on a paid Google order (commonly
      two), complete provider mailbox identity, and no explicit burned provider
      result. Attach is all-or-nothing: full quantity or
      `insufficient_inventory` with no pool change. Attach and release are
      async. Poll the resource or subscribe to `pool.*` webhooks.

      Guide: [Pre-warmed pool](/guides/pre-warmed-pool).
  - name: Orders
    x-group: Orders
    description: |
      One purchase of domains plus Google and/or Microsoft licenses for one
      customer (`ord_…`). Use a saved `bundle_id` **or** custom license counts,
      never both. Requires `Idempotency-Key`.

      Lifecycle: [How orders work](/concepts/orders).
  - name: Domain swaps
    x-group: Domain swaps
    description: |
      Replace a domain inside an existing order without losing the order
      (`swp_…`). For persona-only changes use `POST /swaps/user_names`.

      Statuses and standard vs premium: [How swaps work](/concepts/swaps).
  - name: Webhooks
    x-group: Webhooks
    description: |
      Signed JSON POSTs for orders, domains, imports, forwarding, pool, and
      swaps. Register the URL and secret in the
      [Partner portal](https://app.peeker.ai/partner/webhooks). Event IDs look
      like `evt_01HZX`.

      Delivery is at least once (up to 5 attempts). Verify `Peeker-Signature`
      and dedupe `Peeker-Event-Id` for at least 24 hours.

      Full catalog: [Webhooks](/webhooks).
paths:
  /domains/generate:
    post:
      tags:
        - Domains
      summary: Generate available keyword or AI domain names
      description: >
        Supports three request shapes:


        - A `keyword` request runs the deterministic Buy Domains engine with
          Partner-safe neutral modifiers. It does not call Spider or AI.
        - `type: branded` requires a URL. Spider reads the website,
          then concurrent AI workers generate brand-led names.
        - `type: generic` accepts either a URL or a description. A
          URL uses Spider; a description skips Spider. Generic names do not
          use the company brand.

        AI requests have a 15-second end-to-end ceiling. If Spider or AI fails,

        times out, or returns no usable names, generation falls back to the

        deterministic Partner prefix and suffix engine inside that same ceiling.


        Fastly registrar availability is always required. Google and

        Microsoft tenant probes are attempted only for Fastly-available names.

        If a tenant probe fails or times out, the endpoint falls back to the

        Fastly result. A confirmed Google or Microsoft tenant claim is still

        excluded.


        An uncached registrar lookup can take several seconds. `limited` keys

        can call this endpoint.


        Sandbox keys use the same request and response shape, but return

        deterministic local availability without calling a registrar or tenant

        provider. A returned sandbox name passes the same sandbox availability

        check when it is submitted to an order, unless another order used it in

        the meantime.


        `limit` is the number of domain names returned in total across every

        requested TLD (default 50, max 100), not a per-TLD count. Defaults to
        `.com`

        when `tlds` is omitted. Use `GET /domains/tlds` as the live allowlist.


        Names are grouped by TLD. The response also includes the requested

        subset of live `pricingTlds` rows. TLD group keys have no leading dot

        (`com`, not `.com`), and empty groups are omitted. `limited` keys can

        call this endpoint.
      operationId: generateDomains
      requestBody:
        required: true
        content:
          application/json:
            schema:
              oneOf:
                - title: Deterministic keyword generation
                  type: object
                  additionalProperties: false
                  required:
                    - keyword
                  properties:
                    keyword:
                      type: string
                      maxLength: 64
                      description: >-
                        Brand or search term. Spaces and a trailing TLD are
                        stripped.
                    tlds:
                      type: array
                      minItems: 1
                      maxItems: 50
                      default:
                        - .com
                      description: >-
                        Optional TLD list from `GET /domains/tlds`. Defaults to
                        `.com`.
                      items:
                        type: string
                    limit:
                      type: integer
                      minimum: 1
                      maximum: 100
                      default: 50
                      description: >-
                        Total number of names across all requested TLDs.
                        Defaults to 50.
                - title: Branded AI generation from a website
                  type: object
                  additionalProperties: false
                  required:
                    - type
                    - content
                  properties:
                    type:
                      type: string
                      enum:
                        - branded
                    content:
                      type: string
                      pattern: ^https?://
                      maxLength: 2048
                      description: >-
                        Website URL Spider should read. Branded AI requires a
                        URL.
                    tlds:
                      type: array
                      minItems: 1
                      maxItems: 50
                      default:
                        - .com
                      items:
                        type: string
                    limit:
                      type: integer
                      minimum: 1
                      maximum: 100
                      default: 50
                      description: >-
                        Total number of names across all requested TLDs.
                        Defaults to 50.
                - title: Generic AI generation from a website or description
                  type: object
                  additionalProperties: false
                  required:
                    - type
                    - content
                  properties:
                    type:
                      type: string
                      enum:
                        - generic
                    content:
                      type: string
                      maxLength: 4000
                      description: >-
                        Website URL (uses Spider) or plain company description
                        (skips Spider).
                    tlds:
                      type: array
                      minItems: 1
                      maxItems: 50
                      default:
                        - .com
                      items:
                        type: string
                    limit:
                      type: integer
                      minimum: 1
                      maximum: 100
                      default: 50
                      description: >-
                        Total number of names across all requested TLDs.
                        Defaults to 50.
            examples:
              keyword:
                summary: Deterministic Buy Domains keyword search
                value:
                  keyword: peeker
                  tlds:
                    - .com
                  limit: 50
              branded_ai:
                summary: Branded names from website data
                value:
                  type: branded
                  content: https://peeker.ai
                  tlds:
                    - .com
                    - .ai
                  limit: 50
              generic_ai:
                summary: Generic names from a description
                value:
                  type: generic
                  content: Software that manages outbound email infrastructure
                  tlds:
                    - .com
                    - .io
                  limit: 50
      responses:
        '200':
          description: >-
            Available names grouped by TLD with the requested live pricing
            subset.
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/SuccessEnvelope'
                  - type: object
                    properties:
                      data:
                        type: object
                        required:
                          - domains
                          - pricing
                        properties:
                          domains:
                            type: object
                            additionalProperties:
                              type: array
                              items:
                                type: string
                          pricing:
                            type: array
                            items:
                              $ref: '#/components/schemas/TldPricing'
              examples:
                grouped:
                  summary: Names grouped by TLD with requested pricing
                  value:
                    data:
                      domains:
                        com:
                          - peekerhq.com
                          - getpeeker.com
                        ai:
                          - peekerhq.ai
                      pricing:
                        - tld: .com
                          price_cents: 1300
                          renewal_price_cents: 1500
                          currency: usd
                        - tld: .ai
                          price_cents: 6900
                          renewal_price_cents: 7900
                          currency: usd
        '400':
          $ref: '#/components/responses/InvalidRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '429':
          $ref: '#/components/responses/RateLimited'
        '500':
          $ref: '#/components/responses/InternalError'
components:
  schemas:
    SuccessEnvelope:
      type: object
      required:
        - data
      properties:
        data: {}
    TldPricing:
      type: object
      required:
        - tld
        - price_cents
        - renewal_price_cents
        - currency
      properties:
        tld:
          type: string
          description: Normalized TLD key from the live `pricingTlds` catalog.
          example: .com
        price_cents:
          type: integer
          description: First-year registration cost in the listed currency.
          example: 1300
        renewal_price_cents:
          type: integer
          description: Yearly renewal cost in the listed currency.
          example: 1500
        currency:
          type: string
          example: usd
    ErrorEnvelope:
      type: object
      additionalProperties: false
      required:
        - error
      properties:
        error:
          type: object
          additionalProperties: false
          required:
            - code
            - message
            - request_id
          properties:
            code:
              type: string
              description: Stable machine-readable code. Branch on this field.
              enum:
                - invalid_request
                - unauthorized
                - forbidden
                - not_found
                - rate_limited
                - provider_not_supported
                - provider_mismatch
                - provider_credentials_invalid
                - provider_login_credentials_required
                - provider_unavailable
                - emailbison_super_admin_key
                - smartlead_connection_required
                - smartlead_client_id_required
                - smartlead_client_not_found
                - idempotency_key_required
                - idempotency_conflict
                - idempotency_in_progress
                - workspace_promotion_required
                - workspace_credentials_conflict
                - order_shape_conflict
                - domain_count_mismatch
                - insufficient_inventory
                - domain_not_imported
                - domains_not_submittable
                - premium_domain_not_supported
                - domain_not_usable_for_provider
                - domain_already_in_active_order
                - internal_error
              example: emailbison_super_admin_key
            message:
              type: string
              description: Human-readable explanation. Wording may change.
              example: >-
                Use an EmailBison workspace/user API key; super-admin keys are
                not accepted.
            request_id:
              type: string
              description: >-
                Stable request identifier, identical to the `Peeker-Request-Id`
                response header.
              example: 550e8400-e29b-41d4-a716-446655440000
            field:
              type: string
              description: Dot path to the invalid request property, when applicable.
              example: credentials.api_key
            details:
              type: object
              additionalProperties: true
              description: Structured context specific to `error.code`.
  responses:
    InvalidRequest:
      description: Bad request body, or fields that don’t belong to this provider.
      headers:
        Peeker-Request-Id:
          $ref: '#/components/headers/PeekerRequestId'
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorEnvelope'
    Unauthorized:
      description: Missing, invalid, or revoked API key.
      headers:
        Peeker-Request-Id:
          $ref: '#/components/headers/PeekerRequestId'
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorEnvelope'
    Forbidden:
      description: Valid key, but it doesn’t allow this action.
      headers:
        Peeker-Request-Id:
          $ref: '#/components/headers/PeekerRequestId'
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorEnvelope'
    RateLimited:
      description: Too many requests. Wait `error.details.retry_after_seconds`, then retry.
      headers:
        Peeker-Request-Id:
          $ref: '#/components/headers/PeekerRequestId'
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorEnvelope'
    InternalError:
      description: Unexpected server error. Retry with backoff and keep the request ID.
      headers:
        Peeker-Request-Id:
          $ref: '#/components/headers/PeekerRequestId'
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorEnvelope'
  headers:
    PeekerRequestId:
      description: Stable request identifier. Log it with the status and response body.
      schema:
        type: string
        example: 550e8400-e29b-41d4-a716-446655440000
  securitySchemes:
    BearerAuth:
      type: http
      scheme: bearer
      description: |
        Partner API key (`pk_live_…` or `pk_test_…`).
      x-default: Bearer pk_test_<your-test-key>

````