---
title: "Connect external domains"
method: POST
path: "/v1/domains/connect"
tags: ["Domains"]
---

# Connect external domains

`POST /v1/domains/connect`

## Request

- Base URL: `https://api.winnr.app`
- URL: `https://api.winnr.app/v1/domains/connect`
- Auth: HTTP bearer

Connect one or more domains you already own to your Winnr account.

**Standard flow:** Creates DNS zones and returns nameservers that you must
configure at your domain registrar. After updating nameservers, use
`POST /v1/domains/check-ns` to verify and trigger provisioning.

**Cloudflare flow:** If your domains are already on Cloudflare, you can pass
a `cloudflare_api_token` with Zone:DNS:Edit and Zone:Zone:Edit permissions.
We'll create the necessary DNS records (MX, SPF, DKIM) directly in your
Cloudflare account — no nameserver changes needed. Provisioning starts
immediately.

**Manual flow:** Pass `manual_dns: true` to receive the DNS records to
create yourself (fetch via `GET /v1/domains/{domain_id}/dns-records`,
verify via `POST /v1/domains/{domain_id}/verify-dns`).

**Subdomain format (non-default):** Pass `subdomain_labels` to connect in
the Subdomain Strategy shape: the apex becomes a container parent whose
DNS is never touched, and each label becomes a full child email domain
(own DKIM/SPF/MX/DMARC, up to 10 mailboxes). Requires `manual_dns: true`
or a `cloudflare_api_token` — nameserver delegation is rejected for
subdomain format because it would replace the domain's entire zone.

## Request body

- object
  - `domains` string[], required: List of domain names to connect
  - `cloudflare_api_token` string: Optional Cloudflare API token. When provided, skips CloudDNS zone creation and nameserver changes. Instead, DNS records are created directly in your Cloudflare account and provisioning starts immediately. The token needs Zone:DNS:Edit and Zone:Zone:Edit permissions.
  - `manual_dns` boolean: Manual DNS mode — no zone is created and no records are written; the expected records are computed for you to create yourself.
  - `subdomain_labels` string[]: Connect in subdomain format: each label becomes a child email domain (`label.domain`) and the apex becomes an untouched container parent. Requires manual_dns or cloudflare_api_token. Labels follow the Subdomain Strategy rules (lowercase LDH, max 30 chars; reserved and cold-email-signaling labels rejected).

## Response `200`

Domains connected

- object
  - `meta` Meta
    - `request_id` string
    - `timestamp` string, date-time
  - `data` object
    - `domains` object[]
      - `domain` string
      - `domain_id` string, nullable
      - `status` 'created' | 'already_exists' | 'error'
      - `dns_provider` string
      - `nameservers` string[]
      - `error` string, nullable
      - `subdomains` object[]: Child domains created in subdomain format
        - `domain` string
        - `domain_id` string
        - `job_id` string
        - `status` string
    - `nameservers` string[]: Nameservers to set at your registrar (empty when using Cloudflare token)
    - `domains_used` integer
    - `domain_limit` integer
    - `cloudflare_mode` boolean: Whether Cloudflare fast-path was used
    - `manual_mode` boolean: Whether manual DNS mode was used
    - `subdomain_format` boolean: Whether the domains were connected in subdomain format

## Other responses

- `400`: Validation error
- `401`: Authentication required or token invalid
- `403`: Domain limit exceeded

---

[API](https://skmtc.dev/winnr/apis/winnr-api.md) · [All operations](https://skmtc.dev/winnr/apis/winnr-api/llms.txt) · [OpenAPI document](https://skmtc.dev/winnr/apis/winnr-api/revisions/a4f960beb1eb?raw)
