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

# Add a custom domain

> Claims `hostname` for this website and registers it with the Cactal edge. Custom domains must first be enabled for the website (`websiteDomains.setEnabled`, owner-only — enabling is the billing moment); the request fails with 403 `custom_domains_disabled` otherwise. Adding or removing domains on an enabled website never changes billing. The domain is created in `pending_dns` status, and the returned `dnsRecords` list exactly what to create at your DNS provider: an ownership TXT record on `_cactal.<hostname>` plus a routing record (a CNAME for subdomains or an A record for apex domains). Hostnames must be lowercase ASCII domains (not IP addresses or Cactal platform hosts), each website can have at most 10 custom domains, and a hostname can be claimed by only one website; claims that never verify expire after 7 days. After creating the records, call the verify endpoint or wait for the automatic re-checks.



## OpenAPI

````yaml /api-reference/openapi.json post /websites/{websiteId}/domains
openapi: 3.1.0
info:
  title: Cactal API
  version: 1.0.0
  description: >-
    The Cactal public API. Create, edit, publish, and operate websites
    programmatically. Authenticate every request with an API key sent as
    `Authorization: Bearer <key>`.
servers:
  - url: https://api.cactal.ai/v1
security:
  - apiKey: []
tags:
  - name: Documentation
    description: >-
      Search and read the Cactal product documentation for concepts, guides,
      agent workflows, platform behavior, and API operations.
  - name: Feedback
    description: >-
      Submit free-form product feedback from users and agents to the Cactal
      feedback inbox.
  - name: Websites
    description: >-
      Create and manage websites — the top-level resource that owns source code,
      content, assets, domains, and analytics.
  - name: Website editors
    description: >-
      Grant, list, and revoke website-scoped editor access, and invite
      collaborators to a single website by email.
  - name: API keys
    description: >-
      Create, scope, rotate, and revoke the API keys that authenticate
      programmatic and agent access.
  - name: Source code
    description: >-
      Read and edit the framework source files of a website draft. Mutations
      require an edit lease.
  - name: Publishing
    description: Validate, build, publish, and roll back website versions.
  - name: CMS collections
    description: >-
      Define the content model: collections of structured content owned by a
      website.
  - name: CMS fields
    description: Manage the typed fields that make up a collection schema.
  - name: CMS items
    description: >-
      Create, query, publish, and organize the content entries inside a
      collection.
  - name: Domains
    description: >-
      Manage platform subdomains and custom domains, including DNS verification
      and the primary domain.
  - name: Assets
    description: Upload and manage website files and images served from the Cactal CDN.
  - name: Media generation
    description: >-
      Generate reference-guided website images that are stored as ordinary
      Cactal CDN assets.
  - name: Project Context
    description: >-
      Upload private durable reference material that the website agent can
      search, read, and inspect.
  - name: Analytics
    description: >-
      Read first-party traffic analytics for a website and export datasets as
      CSV.
  - name: Organizations
    description: Manage organizations, members, and organization-wide invitations.
  - name: Audit log
    description: >-
      Read the immutable record of actions performed in an organization by users
      and API keys.
  - name: Billing
    description: >-
      Read billing state and manage plans, site capacity, and prepaid usage
      balance. Every billing operation requires the organization owner role,
      which API keys cannot hold — today these operations are performed from the
      dashboard, return 403 for API-key callers, and are hidden from MCP tool
      lists.
paths:
  /websites/{websiteId}/domains:
    post:
      tags:
        - Domains
      summary: Add a custom domain
      description: >-
        Claims `hostname` for this website and registers it with the Cactal
        edge. Custom domains must first be enabled for the website
        (`websiteDomains.setEnabled`, owner-only — enabling is the billing
        moment); the request fails with 403 `custom_domains_disabled` otherwise.
        Adding or removing domains on an enabled website never changes billing.
        The domain is created in `pending_dns` status, and the returned
        `dnsRecords` list exactly what to create at your DNS provider: an
        ownership TXT record on `_cactal.<hostname>` plus a routing record (a
        CNAME for subdomains or an A record for apex domains). Hostnames must be
        lowercase ASCII domains (not IP addresses or Cactal platform hosts),
        each website can have at most 10 custom domains, and a hostname can be
        claimed by only one website; claims that never verify expire after 7
        days. After creating the records, call the verify endpoint or wait for
        the automatic re-checks.
      operationId: websiteDomains.createCustomDomain
      parameters:
        - name: websiteId
          in: path
          required: true
          schema:
            type: string
            minLength: 1
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                hostname:
                  type: string
                  minLength: 1
              required:
                - hostname
      responses:
        '200':
          description: >-
            The created domain in `pending_dns` status. Next: create the
            `dnsRecords` at your DNS provider, then call
            `websiteDomains.verifyCustomDomain`.
          content:
            application/json:
              schema:
                type: object
                properties:
                  id:
                    type: string
                    description: Unique domain id.
                  hostname:
                    type: string
                    description: >-
                      Fully-qualified lowercase hostname, e.g.
                      `blog.example.com`.
                  status:
                    type: string
                    enum:
                      - pending_dns
                      - pending_verification
                      - active
                      - failed
                      - removing
                      - suspended
                    description: >-
                      `pending_dns`: waiting for the required DNS records;
                      `pending_verification`: DNS found, waiting for the edge
                      host to become ready; `active`: serving traffic; `failed`:
                      verification failed (see `failureMessage`); `removing`:
                      being deregistered from the edge; `suspended`: disabled by
                      Cactal trust & safety. Platform subdomains are always
                      `active`.
                  kind:
                    type: string
                    enum:
                      - platform_subdomain
                      - custom
                    description: >-
                      Every website automatically gets one `platform_subdomain`;
                      `custom` domains are added through this API.
                  isPrimary:
                    type: boolean
                    description: >-
                      Whether this is the canonical custom domain that published
                      traffic redirects to. Always `false` for platform
                      subdomains.
                  dnsRecords:
                    type: array
                    items:
                      type: object
                      properties:
                        type:
                          type: string
                          enum:
                            - TXT
                            - CNAME
                            - A
                          description: DNS record type to create.
                        name:
                          type: string
                          description: Fully-qualified name (host) to create the record on.
                        value:
                          type: string
                          description: Exact value the record must resolve to.
                        purpose:
                          type: string
                          enum:
                            - ownership
                            - routing
                          description: >-
                            `ownership` records prove control of the hostname
                            (TXT); `routing` records point traffic at the Cactal
                            edge (CNAME for subdomains, A for apex domains).
                      required:
                        - type
                        - name
                        - value
                        - purpose
                      additionalProperties: false
                    description: >-
                      DNS records the domain owner must create for verification
                      to succeed. Empty for platform subdomains.
                  failureMessage:
                    anyOf:
                      - type: string
                      - type: 'null'
                    description: >-
                      What the most recent verification check found wrong,
                      including whether ownership is missing, the hostname is
                      unreachable, or traffic reaches a service other than
                      Cactal. `null` when nothing is wrong.
                  lastCheckedAt:
                    anyOf:
                      - type: string
                        format: date-time
                      - type: 'null'
                    description: >-
                      When DNS and edge status were last checked. `null` before
                      the first check.
                  createdAt:
                    description: When the domain record was created.
                    type: string
                    format: date-time
                required:
                  - id
                  - hostname
                  - status
                  - kind
                  - isPrimary
                  - dnsRecords
                  - failureMessage
                  - lastCheckedAt
                  - createdAt
                additionalProperties: false
        '400':
          description: >-
            Validation failed. The response `message` names the first invalid
            field.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ServiceError'
        '401':
          description: Missing, invalid, expired, or revoked API key.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ServiceError'
        '403':
          description: The authenticated principal lacks the required capability.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ServiceError'
        '404':
          description: >-
            The resource does not exist or is outside the principal’s access
            scope.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ServiceError'
        '409':
          description: The request conflicts with the current state of the resource.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ServiceError'
        '429':
          description: >-
            Rate limit exceeded. Retry after the number of seconds in the
            `Retry-After` header.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ServiceError'
components:
  schemas:
    ServiceError:
      type: object
      required:
        - kind
        - message
      description: >-
        Canonical error body returned by every non-2xx response. Extra fields
        carry error-specific details.
      properties:
        kind:
          type: string
          enum:
            - validation
            - unauthorized
            - forbidden
            - not_found
            - conflict
            - rate_limited
            - internal
          description: Stable, machine-readable error category.
        message:
          type: string
          description: Human-readable explanation of the failure.
        suggestion:
          type: string
          description: >-
            What to do next when the failure has a known fix; may name the exact
            operation to call.
        validValues:
          type: array
          items:
            type: string
          description: The acceptable values for the failing field, when the set is closed.
      additionalProperties: true
  securitySchemes:
    apiKey:
      type: http
      scheme: bearer
      description: >-
        Cactal API key. Create one in the dashboard or via `POST /apiKeys`. The
        plaintext key is shown once at creation.

````