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

# Create a domain

> Connect a custom domain to the workspace bound to your API key and receive its DNS records.

Connect a domain you already own to the workspace bound to your API key. This
endpoint does not buy or register a domain.

## Authentication and permission

Use a workspace API key with **Custom domains: Write**
(`custom_domains.create`). Do not send a workspace ID; the key determines it.
The workspace plan must also include custom domains.

```bash theme={null}
curl --request POST \
  --url https://biq.li/api/v1/domain \
  --header 'Authorization: Bearer biqli_your_workspace_api_key' \
  --header 'Accept: application/json' \
  --header 'Content-Type: application/json' \
  --data '{"host":"go.example.com"}'
```

| Field  | Type             | Description                                                                                                     |
| ------ | ---------------- | --------------------------------------------------------------------------------------------------------------- |
| `host` | string, required | Apex domain or subdomain, without a path. A full HTTP(S) URL is normalized to its host. Maximum 100 characters. |

Biqli rejects its own application domain, malformed hosts, unsafe or
blacklisted hosts, and domains claimed by another account. Unknown fields and
internal numeric IDs are not accepted.

## Successful response

A new claim returns `201 Created`. Add every record exactly as returned:

```json theme={null}
{
  "domain": {
    "id": "biq_dom_01M18D4A8QRJY5G6K3N2W7X9TZ",
    "host": "go.example.com",
    "url": "https://go.example.com",
    "status": "pending_dns",
    "dns_status": "pending",
    "ssl_status": "pending",
    "dns_verified": false,
    "active": false,
    "is_subdomain": true,
    "links_count": 0,
    "claim_expires_at": "2026-08-30T14:30:00+00:00",
    "dns_last_checked_at": null,
    "dns_verified_at": null,
    "ssl_last_checked_at": null,
    "use_default_redirect": false,
    "default_redirect_url": null,
    "use_not_found_redirect": false,
    "not_found_redirect_url": null,
    "use_expired_redirect": false,
    "expired_redirect_url": null,
    "created_at": "2026-08-30T02:30:00+00:00",
    "updated_at": "2026-08-30T02:30:00+00:00"
  },
  "dns_config": {
    "host": "go.example.com",
    "is_subdomain": true,
    "records": [
      {"type":"CNAME","name":"go","value":"biq.li","ttl":"auto"},
      {"type":"TXT","name":"_verify.example.com","value":"domain-verify=...","ttl":"auto"}
    ]
  },
  "created": true,
  "attached": true,
  "status": "success"
}
```

For an apex host such as `example.com`, the routing record is an `A` record
whose name is `@`. Subdomains use a `CNAME`. The TXT record proves ownership.
Use the returned values rather than assuming a target.

Biqli also sends the domain owner a professional setup email containing these
records for a brand-new claim. It does not send that email again when an
already-owned domain is attached to another workspace.

## Idempotent attachment

If the same API-key owner already owns the host, Biqli safely attaches it to
the current workspace and returns `200 OK`. `created` is `false`; `attached` is
`true` only when this call created a new workspace attachment. Its existing DNS
verification and SSL state are preserved.

## Next steps

1. Publish both records from `dns_config` at your DNS provider.
2. Use [Retrieve DNS configuration](/docs/api-reference/domains/dns-config) whenever
   you need the exact values again.
3. Call [Verify a domain](/docs/api-reference/domains/verify) after DNS propagation.
4. Wait until the returned domain has `status: active` before using it for
   production links.

## Errors

| HTTP status | Error code            | Meaning                                                           |
| ----------- | --------------------- | ----------------------------------------------------------------- |
| `401`       | `invalid_token`       | The workspace API key is missing, invalid, malformed, or revoked. |
| `403`       | `insufficient_scope`  | The key or its user cannot create domains in this workspace.      |
| `403`       | `upgrade_required`    | The workspace plan does not include custom domains.               |
| `409`       | `domain_taken`        | Another Biqli account has already claimed this host.              |
| `422`       | `validation_error`    | The host or payload is invalid, unsafe, or unsupported.           |
| `429`       | `rate_limit_exceeded` | The workspace exceeded its API request limit.                     |

Every error includes a `request_id`, also returned in `X-Biq-Request-Id`.

## Shared API behavior

Authentication is workspace-scoped; see [Authentication](/docs/api-reference/authentication). Errors use the standard envelope and request IDs described in [Errors](/docs/api-reference/errors), and requests are subject to [Rate limits](/docs/api-reference/rate-limits).


## OpenAPI

````yaml POST /v1/domain
openapi: 3.1.0
info:
  title: Biqli API
  version: 1.0.0
  description: Workspace-scoped REST API for Biqli.
servers:
  - url: https://biq.li/api
security:
  - bearerAuth: []
paths:
  /v1/domain:
    post:
      tags:
        - Domains
      summary: Create a domain
      description: >-
        Claims a new host or attaches an already-owned domain to the API key's
        workspace. Requires custom_domains.create.
      operationId: domain.store
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateDomainRequest'
      responses:
        '200':
          description: An already-owned domain was returned or attached.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/CreateDomainResponse'
        '201':
          description: A new domain claim was created.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/CreateDomainResponse'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '409':
          $ref: '#/components/responses/Conflict'
        '422':
          $ref: '#/components/responses/UnprocessableEntity'
        '429':
          $ref: '#/components/responses/RateLimited'
        '500':
          $ref: '#/components/responses/InternalError'
components:
  schemas:
    CreateDomainRequest:
      type: object
      additionalProperties: false
      required:
        - host
      properties:
        host:
          type: string
          maxLength: 100
          examples:
            - go.example.com
    CreateDomainResponse:
      type: object
      additionalProperties: false
      required:
        - domain
        - dns_config
        - created
        - attached
        - status
      properties:
        domain:
          $ref: '#/components/schemas/Domain'
        dns_config:
          $ref: '#/components/schemas/DomainDnsConfig'
        created:
          type: boolean
        attached:
          type: boolean
        status:
          type: string
          const: success
    Domain:
      type: object
      additionalProperties: false
      required:
        - id
        - host
        - url
        - status
        - dns_status
        - ssl_status
        - dns_verified
        - active
        - is_subdomain
        - links_count
        - claim_expires_at
        - dns_last_checked_at
        - dns_verified_at
        - ssl_last_checked_at
        - use_default_redirect
        - default_redirect_url
        - use_not_found_redirect
        - not_found_redirect_url
        - use_expired_redirect
        - expired_redirect_url
        - created_at
        - updated_at
      properties:
        id:
          type: string
          pattern: ^biq_dom_[0-9A-HJKMNP-TV-Z]{26}$
        host:
          type: string
          examples:
            - go.example.com
        url:
          type: string
          format: uri
        status:
          type: string
          enum:
            - pending_dns
            - verifying_dns
            - dns_failed
            - provisioning_ssl
            - ssl_failed
            - active
        dns_status:
          type: string
          enum:
            - pending
            - verifying
            - verified
            - failed
        ssl_status:
          type: string
          enum:
            - pending
            - processing
            - active
            - failed
        dns_verified:
          type: boolean
        active:
          type: boolean
        is_subdomain:
          type: boolean
        links_count:
          type: integer
          minimum: 0
          description: Links using this domain in the API key's workspace only.
        claim_expires_at:
          type:
            - string
            - 'null'
          format: date-time
        dns_last_checked_at:
          type:
            - string
            - 'null'
          format: date-time
        dns_verified_at:
          type:
            - string
            - 'null'
          format: date-time
        ssl_last_checked_at:
          type:
            - string
            - 'null'
          format: date-time
        use_default_redirect:
          type: boolean
        default_redirect_url:
          type:
            - string
            - 'null'
          format: uri
        use_not_found_redirect:
          type: boolean
        not_found_redirect_url:
          type:
            - string
            - 'null'
          format: uri
        use_expired_redirect:
          type: boolean
        expired_redirect_url:
          type:
            - string
            - 'null'
          format: uri
        created_at:
          type:
            - string
            - 'null'
          format: date-time
        updated_at:
          type:
            - string
            - 'null'
          format: date-time
    DomainDnsConfig:
      type: object
      additionalProperties: false
      required:
        - host
        - is_subdomain
        - records
      properties:
        host:
          type: string
        is_subdomain:
          type: boolean
        records:
          type: array
          minItems: 2
          maxItems: 2
          items:
            $ref: '#/components/schemas/DnsRecord'
    ApiError:
      type: object
      required:
        - error
        - request_id
      properties:
        error:
          type: object
          required:
            - code
            - message
          properties:
            code:
              type: string
              enum:
                - invalid_token
                - insufficient_scope
                - upgrade_required
                - quota_exceeded
                - resource_not_found
                - domain_taken
                - alias_taken
                - external_id_taken
                - folder_name_taken
                - tag_name_taken
                - pixel_name_taken
                - biolink_name_taken
                - method_not_allowed
                - url_blocked
                - dns_verification_failed
                - validation_error
                - rate_limit_exceeded
                - internal_server_error
            message:
              type: string
            details:
              type: object
              additionalProperties: true
        request_id:
          type: string
          description: Request identifier to include when contacting support.
    DnsRecord:
      type: object
      additionalProperties: false
      required:
        - type
        - name
        - value
        - ttl
      properties:
        type:
          type: string
          enum:
            - A
            - CNAME
            - TXT
        name:
          type: string
        value:
          type: string
        ttl:
          type: string
          const: auto
  responses:
    Unauthorized:
      $ref: '#/components/responses/ApiErrorResponse'
      description: The workspace API key is missing, invalid, or revoked.
    Forbidden:
      $ref: '#/components/responses/ApiErrorResponse'
      description: >-
        The key lacks a required scope, the workspace must upgrade, or its quota
        is exhausted.
    Conflict:
      $ref: '#/components/responses/ApiErrorResponse'
      description: >-
        A unique alias, external ID, custom domain, or workspace resource name
        is already in use.
    UnprocessableEntity:
      $ref: '#/components/responses/ApiErrorResponse'
      description: >-
        The payload is invalid, a destination was blocked, or domain DNS
        verification is not ready.
    RateLimited:
      description: The workspace exceeded its plan's API rate limit.
      headers:
        RateLimit-Policy:
          description: Current IETF HTTPAPI quota policy as a structured field.
          schema:
            type: string
            example: '"workspace-api";q=1000;w=60'
        RateLimit:
          description: Current IETF HTTPAPI service limit as a structured field.
          schema:
            type: string
            example: '"workspace-api";r=0;t=17'
        Retry-After:
          description: Seconds to wait before retrying the request.
          schema:
            type: integer
            minimum: 0
            example: 17
        X-RateLimit-Limit:
          description: Legacy maximum request count for the current window.
          schema:
            type: integer
            minimum: 1
            example: 1000
        X-RateLimit-Remaining:
          description: Legacy remaining request count.
          schema:
            type: integer
            minimum: 0
            example: 0
        X-RateLimit-Reset:
          description: Legacy reset time as a UTC Unix timestamp.
          schema:
            type: integer
            format: int64
            example: 1788126519
        X-Biq-Request-Id:
          description: Request identifier for support and tracing.
          schema:
            type: string
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ApiError'
    InternalError:
      $ref: '#/components/responses/ApiErrorResponse'
      description: The request failed unexpectedly.
    ApiErrorResponse:
      description: API error.
      headers:
        X-Biq-Request-Id:
          description: Request identifier for support and tracing.
          schema:
            type: string
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ApiError'
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      bearerFormat: Workspace API key
      description: A workspace API key beginning with biqli_.

````