---
title: Add Custom Domain
protocol: rest
method: POST
endpoint: /v1/projects/{projectId}/domains
description: "Add a custom domain to a project"
---

# Add Custom Domain

Add a custom domain to serve your documentation from (e.g., `docs.example.com`).

<Endpoint method="POST" path="/v1/projects/{projectId}/domains" />

## Path Parameters

<ParamField path="projectId" type="string" required>
  The project ID (e.g., `prj_abc123`).
</ParamField>

## Request Body

<ParamField body="domain" type="string" required>
  The custom domain (e.g., `docs.example.com`).
</ParamField>

## Response

Returns the domain configuration with DNS instructions.

<ResponseField name="data" type="object">
  <Expandable title="properties">
    <ResponseField name="id" type="string">
      Domain identifier.
    </ResponseField>

    <ResponseField name="domain" type="string">
      The custom domain.
    </ResponseField>

    <ResponseField name="status" type="string">
      Domain status: `pending`, `active`, `failed`.
    </ResponseField>

    <ResponseField name="dnsRecords" type="array">
      Required DNS records to configure.

      <Expandable title="DNS Record">
        <ResponseField name="type" type="string">
          Record type: `CNAME` or `TXT`.
        </ResponseField>

        <ResponseField name="name" type="string">
          Record name (hostname).
        </ResponseField>

        <ResponseField name="value" type="string">
          Record value.
        </ResponseField>
      </Expandable>
    </ResponseField>

    <ResponseField name="sslStatus" type="string">
      SSL certificate status: `pending`, `active`.
    </ResponseField>

    <ResponseField name="createdAt" type="string">
      ISO 8601 timestamp.
    </ResponseField>
  </Expandable>
</ResponseField>

## Example

<CodeGroup>
```bash cURL
curl -X POST https://api.syntext.dev/v1/projects/prj_abc123/domains \
  -H "Authorization: Bearer stx_abc12345_..." \
  -H "Content-Type: application/json" \
  -d '{"domain": "docs.example.com"}'
```

```typescript SDK
import { Syntext } from '@syntext/sdk'

const client = new Syntext('stx_abc12345_...')

const domain = await client.domains.add('prj_abc123', {
  domain: 'docs.example.com',
})
```

```python Python
from syntext import Syntext

client = Syntext("stx_abc12345_...")

domain = client.domains.add(
    "prj_abc123",
    domain="docs.example.com",
)
```
</CodeGroup>

### Response

```json
{
  "data": {
    "id": "dom_xyz789",
    "domain": "docs.example.com",
    "status": "pending",
    "dnsRecords": [
      {
        "type": "CNAME",
        "name": "docs",
        "value": "prj-abc123.syntext.dev"
      },
      {
        "type": "TXT",
        "name": "_syntext.docs",
        "value": "syntext-verify=abc123xyz"
      }
    ],
    "sslStatus": "pending",
    "createdAt": "2026-06-28T12:00:00Z"
  }
}
```

## DNS Configuration

After adding a domain, configure these DNS records with your provider:

<Steps>
  <Step title="Add CNAME record">
    Point your subdomain to the Syntext edge:
    ```
    docs.example.com CNAME prj-abc123.syntext.dev
    ```
  </Step>
  <Step title="Add TXT verification">
    Add the verification record:
    ```
    _syntext.docs.example.com TXT syntext-verify=abc123xyz
    ```
  </Step>
  <Step title="Wait for propagation">
    DNS changes can take up to 48 hours, but typically complete within minutes.
  </Step>
</Steps>

## Error Responses

### 400 Bad Request

Returned when the domain format is invalid.

```json
{
  "error": {
    "code": "invalid_request",
    "message": "Invalid domain format"
  }
}
```

### 409 Conflict

Returned when the domain is already in use by another project.

```json
{
  "error": {
    "code": "conflict",
    "message": "Domain is already in use by another project"
  }
}
```

### 402 Payment Required

Returned when the custom domain limit has been reached.

```json
{
  "error": {
    "code": "quota_exceeded",
    "message": "Custom domain limit reached. Upgrade your plan to add more domains."
  }
}
```
