# Domains

> Generated and custom domains, DNS instructions, ownership verification and certificates.

Generated and custom domains, DNS instructions, ownership verification and certificates.

| Operation | Method and path |
| --- | --- |
| [List domains](#list-domains) | `GET /v1/projects/{project}/environments/{environment}/domains` |
| [Add a custom domain](#add-a-custom-domain) | `POST /v1/projects/{project}/environments/{environment}/domains` |
| [Get a domain](#get-a-domain) | `GET /v1/projects/{project}/environments/{environment}/domains/{domain}` |
| [Point a domain at a different service](#point-a-domain-at-a-different-service) | `PATCH /v1/projects/{project}/environments/{environment}/domains/{domain}` |
| [Remove a domain](#remove-a-domain) | `DELETE /v1/projects/{project}/environments/{environment}/domains/{domain}` |
| [Check DNS now](#check-dns-now) | `POST /v1/projects/{project}/environments/{environment}/domains/{domain}/verify` |

## List domains

```http
GET /v1/projects/{project}/environments/{environment}/domains
```

- **Operation:** `listDomains`
- **Scopes:** `projects:read`
- **CLI:** `guv domains list`
- **Paginated:** `?limit=` and `?cursor=`

**Parameters**

| Name | In | Type | Description |
| --- | --- | --- | --- |
| `project` * | path | string | Project id (`prj_…`) or slug (resolved in the `Guv-Workspace` workspace, or the caller's default). |
| `environment` * | path | string | Environment id (`env_…`) or name. |
| `service` | query | string |  |
| `status` | query | [DomainStatus](/docs/api/objects/domain-status/) |  |

**Responses**

| Status | Meaning | Body |
| --- | --- | --- |
| `200` OK | A page of Domain objects. | [DomainList](/docs/api/objects/domain-list/) |

**Errors:** `400`, `401`, `403`, `404`, `429`, `500`, as [problem+json](/errors/) with a stable `code`.

**Example**

```bash
curl https://api.guv.dev/v1/projects/shopfront/environments/production/domains \
  -H "Authorization: Bearer $GUV_TOKEN"
```

**Example response**

```json
{
  "data": [
    {
      "id": "dom_01jbx2m9k7q4r8t5v6w3y0z1dm",
      "hostname": "www.primecarers.co.uk",
      "kind": "custom",
      "environment_id": "env_01jbx2m9k7q4r8t5v6w3y0z1en",
      "service_id": "svc_01jbx2m9k7q4r8t5v6w3y0z1sv",
      "status": "pending",
      "status_text": "Waiting for your DNS records. This usually takes a few minutes.",
      "apex": false,
      "wildcard": false,
      "dns_records": [
        {
          "type": "CNAME",
          "name": "www.primecarers.co.uk",
          "value": "prj-k7q4r8t5.edge.guv.run",
          "purpose": "routing",
          "status": "missing",
          "observed": []
        },
        {
          "type": "TXT",
          "name": "_guv-challenge.www.primecarers.co.uk",
          "value": "guv-verify=8f3a2c1d9e7b6a5f",
          "purpose": "ownership",
          "status": "ok",
          "observed": [
            "guv-verify=8f3a2c1d9e7b6a5f"
          ]
        }
      ],
      "registrar": {
        "name": "123-reg",
        "instructions_url": "https://guv.dev/docs/domains/123-reg"
      },
      "checks": {
        "dns": "pending",
        "ownership": "ok",
        "certificate": "pending",
        "live": "pending"
      },
      "certificate": null,
      "caa_warning": null,
      "error": null,
      "last_checked_at": "2026-10-23T14:10:00Z",
      "next_check_at": "2026-10-23T14:11:00Z",
      "created_at": "2026-10-23T14:00:00Z"
    }
  ],
  "next_cursor": "string",
  "has_more": false
}
```

## Add a custom domain

```http
POST /v1/projects/{project}/environments/{environment}/domains
```

Returns the DNS records to create. Verification runs in the background; poll the domain or call verify.

- **Operation:** `addDomain`
- **Scopes:** `projects:write`
- **CLI:** `guv domains add`
- **Approval:** In environments with protection turned on (usually production), changes by agents and by roles outside `approver_roles` return `approval_required`.
- **Idempotency-Key:** required; supports `?dry_run=true`

**Parameters**

| Name | In | Type | Description |
| --- | --- | --- | --- |
| `project` * | path | string | Project id (`prj_…`) or slug (resolved in the `Guv-Workspace` workspace, or the caller's default). |
| `environment` * | path | string | Environment id (`env_…`) or name. |

**Request body** (`application/json`, required): [DomainCreate](/docs/api/objects/domain-create/)

| Field | Type | Description |
| --- | --- | --- |
| `hostname` * | string |  |
| `service` * | string | Service name or id that receives traffic. |

**Responses**

| Status | Meaning | Body |
| --- | --- | --- |
| `200` OK | Dry run. Nothing was changed; this is what would happen. | [Plan](/docs/api/objects/plan/) |
| `201` Created | Created. | [Domain](/docs/api/objects/domain/) |

**Errors:** `400`, `401`, `403`, `404`, `409`, `422`, `429`, `500`, as [problem+json](/errors/) with a stable `code`.

**Example**

```bash
curl -X POST https://api.guv.dev/v1/projects/shopfront/environments/production/domains \
  -H "Authorization: Bearer $GUV_TOKEN" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{
  "hostname": "www.primecarers.co.uk",
  "service": "string"
}'
```

**Example response**

```json
{
  "id": "dom_01jbx2m9k7q4r8t5v6w3y0z1dm",
  "hostname": "www.primecarers.co.uk",
  "kind": "custom",
  "environment_id": "env_01jbx2m9k7q4r8t5v6w3y0z1en",
  "service_id": "svc_01jbx2m9k7q4r8t5v6w3y0z1sv",
  "status": "pending",
  "status_text": "Waiting for your DNS records. This usually takes a few minutes.",
  "apex": false,
  "wildcard": false,
  "dns_records": [
    {
      "type": "CNAME",
      "name": "www.primecarers.co.uk",
      "value": "prj-k7q4r8t5.edge.guv.run",
      "purpose": "routing",
      "status": "missing",
      "observed": []
    },
    {
      "type": "TXT",
      "name": "_guv-challenge.www.primecarers.co.uk",
      "value": "guv-verify=8f3a2c1d9e7b6a5f",
      "purpose": "ownership",
      "status": "ok",
      "observed": [
        "guv-verify=8f3a2c1d9e7b6a5f"
      ]
    }
  ],
  "registrar": {
    "name": "123-reg",
    "instructions_url": "https://guv.dev/docs/domains/123-reg"
  },
  "checks": {
    "dns": "pending",
    "ownership": "ok",
    "certificate": "pending",
    "live": "pending"
  },
  "certificate": null,
  "caa_warning": null,
  "error": null,
  "last_checked_at": "2026-10-23T14:10:00Z",
  "next_check_at": "2026-10-23T14:11:00Z",
  "created_at": "2026-10-23T14:00:00Z"
}
```

## Get a domain

```http
GET /v1/projects/{project}/environments/{environment}/domains/{domain}
```

- **Operation:** `getDomain`
- **Scopes:** `projects:read`

**Parameters**

| Name | In | Type | Description |
| --- | --- | --- | --- |
| `project` * | path | string | Project id (`prj_…`) or slug (resolved in the `Guv-Workspace` workspace, or the caller's default). |
| `environment` * | path | string | Environment id (`env_…`) or name. |
| `domain` * | path | string | Domain id (`dom_…`) or hostname. |

**Responses**

| Status | Meaning | Body |
| --- | --- | --- |
| `200` OK | OK. | [Domain](/docs/api/objects/domain/) |

**Errors:** `400`, `401`, `403`, `404`, `429`, `500`, as [problem+json](/errors/) with a stable `code`.

**Example**

```bash
curl https://api.guv.dev/v1/projects/shopfront/environments/production/domains/www.example.co.uk \
  -H "Authorization: Bearer $GUV_TOKEN"
```

**Example response**

```json
{
  "id": "dom_01jbx2m9k7q4r8t5v6w3y0z1dm",
  "hostname": "www.primecarers.co.uk",
  "kind": "custom",
  "environment_id": "env_01jbx2m9k7q4r8t5v6w3y0z1en",
  "service_id": "svc_01jbx2m9k7q4r8t5v6w3y0z1sv",
  "status": "pending",
  "status_text": "Waiting for your DNS records. This usually takes a few minutes.",
  "apex": false,
  "wildcard": false,
  "dns_records": [
    {
      "type": "CNAME",
      "name": "www.primecarers.co.uk",
      "value": "prj-k7q4r8t5.edge.guv.run",
      "purpose": "routing",
      "status": "missing",
      "observed": []
    },
    {
      "type": "TXT",
      "name": "_guv-challenge.www.primecarers.co.uk",
      "value": "guv-verify=8f3a2c1d9e7b6a5f",
      "purpose": "ownership",
      "status": "ok",
      "observed": [
        "guv-verify=8f3a2c1d9e7b6a5f"
      ]
    }
  ],
  "registrar": {
    "name": "123-reg",
    "instructions_url": "https://guv.dev/docs/domains/123-reg"
  },
  "checks": {
    "dns": "pending",
    "ownership": "ok",
    "certificate": "pending",
    "live": "pending"
  },
  "certificate": null,
  "caa_warning": null,
  "error": null,
  "last_checked_at": "2026-10-23T14:10:00Z",
  "next_check_at": "2026-10-23T14:11:00Z",
  "created_at": "2026-10-23T14:00:00Z"
}
```

## Point a domain at a different service

```http
PATCH /v1/projects/{project}/environments/{environment}/domains/{domain}
```

- **Operation:** `updateDomain`
- **Scopes:** `projects:write`
- **Approval:** In environments with protection turned on (usually production), changes by agents and by roles outside `approver_roles` return `approval_required`.
- **Idempotency-Key:** required; supports `?dry_run=true`
- **Concurrency:** send the `ETag` you read as `If-Match`

**Parameters**

| Name | In | Type | Description |
| --- | --- | --- | --- |
| `project` * | path | string | Project id (`prj_…`) or slug (resolved in the `Guv-Workspace` workspace, or the caller's default). |
| `environment` * | path | string | Environment id (`env_…`) or name. |
| `domain` * | path | string | Domain id (`dom_…`) or hostname. |

**Request body** (`application/json`, required): [DomainUpdate](/docs/api/objects/domain-update/)

| Field | Type | Description |
| --- | --- | --- |
| `service` | string |  |

**Responses**

| Status | Meaning | Body |
| --- | --- | --- |
| `200` OK | OK. With `dry_run=true`: a Plan (application/vnd.guv.plan+json) and nothing changes. | [Domain](/docs/api/objects/domain/) |

**Errors:** `400`, `401`, `403`, `404`, `409`, `412`, `422`, `429`, `500`, as [problem+json](/errors/) with a stable `code`.

**Example**

```bash
curl -X PATCH https://api.guv.dev/v1/projects/shopfront/environments/production/domains/www.example.co.uk \
  -H "Authorization: Bearer $GUV_TOKEN" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{
  "service": "string"
}'
```

**Example response**

```json
{
  "id": "dom_01jbx2m9k7q4r8t5v6w3y0z1dm",
  "hostname": "www.primecarers.co.uk",
  "kind": "custom",
  "environment_id": "env_01jbx2m9k7q4r8t5v6w3y0z1en",
  "service_id": "svc_01jbx2m9k7q4r8t5v6w3y0z1sv",
  "status": "pending",
  "status_text": "Waiting for your DNS records. This usually takes a few minutes.",
  "apex": false,
  "wildcard": false,
  "dns_records": [
    {
      "type": "CNAME",
      "name": "www.primecarers.co.uk",
      "value": "prj-k7q4r8t5.edge.guv.run",
      "purpose": "routing",
      "status": "missing",
      "observed": []
    },
    {
      "type": "TXT",
      "name": "_guv-challenge.www.primecarers.co.uk",
      "value": "guv-verify=8f3a2c1d9e7b6a5f",
      "purpose": "ownership",
      "status": "ok",
      "observed": [
        "guv-verify=8f3a2c1d9e7b6a5f"
      ]
    }
  ],
  "registrar": {
    "name": "123-reg",
    "instructions_url": "https://guv.dev/docs/domains/123-reg"
  },
  "checks": {
    "dns": "pending",
    "ownership": "ok",
    "certificate": "pending",
    "live": "pending"
  },
  "certificate": null,
  "caa_warning": null,
  "error": null,
  "last_checked_at": "2026-10-23T14:10:00Z",
  "next_check_at": "2026-10-23T14:11:00Z",
  "created_at": "2026-10-23T14:00:00Z"
}
```

## Remove a domain

```http
DELETE /v1/projects/{project}/environments/{environment}/domains/{domain}
```

- **Operation:** `removeDomain`
- **Scopes:** `projects:write`
- **Approval:** In environments with protection turned on (usually production), changes by agents and by roles outside `approver_roles` return `approval_required`.
- **Idempotency-Key:** required; supports `?dry_run=true`
- **Concurrency:** send the `ETag` you read as `If-Match`

**Parameters**

| Name | In | Type | Description |
| --- | --- | --- | --- |
| `project` * | path | string | Project id (`prj_…`) or slug (resolved in the `Guv-Workspace` workspace, or the caller's default). |
| `environment` * | path | string | Environment id (`env_…`) or name. |
| `domain` * | path | string | Domain id (`dom_…`) or hostname. |

**Responses**

| Status | Meaning | Body |
| --- | --- | --- |
| `200` OK | Dry run. Nothing was changed; this is what would happen. | [Plan](/docs/api/objects/plan/) |
| `204` No Content | Done. No body. | none |

**Errors:** `400`, `401`, `403`, `404`, `409`, `412`, `422`, `429`, `500`, as [problem+json](/errors/) with a stable `code`.

**Example**

```bash
curl -X DELETE https://api.guv.dev/v1/projects/shopfront/environments/production/domains/www.example.co.uk \
  -H "Authorization: Bearer $GUV_TOKEN" \
  -H "Idempotency-Key: $(uuidgen)"
```

## Check DNS now

```http
POST /v1/projects/{project}/environments/{environment}/domains/{domain}/verify
```

- **Operation:** `verifyDomain`
- **Scopes:** `projects:write`
- **CLI:** `guv domains verify`
- **Idempotency-Key:** required

**Parameters**

| Name | In | Type | Description |
| --- | --- | --- | --- |
| `project` * | path | string | Project id (`prj_…`) or slug (resolved in the `Guv-Workspace` workspace, or the caller's default). |
| `environment` * | path | string | Environment id (`env_…`) or name. |
| `domain` * | path | string | Domain id (`dom_…`) or hostname. |

**Responses**

| Status | Meaning | Body |
| --- | --- | --- |
| `200` OK | OK. | [Domain](/docs/api/objects/domain/) |

**Errors:** `400`, `401`, `403`, `404`, `409`, `422`, `429`, `500`, as [problem+json](/errors/) with a stable `code`.

**Example**

```bash
curl -X POST https://api.guv.dev/v1/projects/shopfront/environments/production/domains/www.example.co.uk/verify \
  -H "Authorization: Bearer $GUV_TOKEN" \
  -H "Idempotency-Key: $(uuidgen)"
```

**Example response**

```json
{
  "id": "dom_01jbx2m9k7q4r8t5v6w3y0z1dm",
  "hostname": "www.primecarers.co.uk",
  "kind": "custom",
  "environment_id": "env_01jbx2m9k7q4r8t5v6w3y0z1en",
  "service_id": "svc_01jbx2m9k7q4r8t5v6w3y0z1sv",
  "status": "pending",
  "status_text": "Waiting for your DNS records. This usually takes a few minutes.",
  "apex": false,
  "wildcard": false,
  "dns_records": [
    {
      "type": "CNAME",
      "name": "www.primecarers.co.uk",
      "value": "prj-k7q4r8t5.edge.guv.run",
      "purpose": "routing",
      "status": "missing",
      "observed": []
    },
    {
      "type": "TXT",
      "name": "_guv-challenge.www.primecarers.co.uk",
      "value": "guv-verify=8f3a2c1d9e7b6a5f",
      "purpose": "ownership",
      "status": "ok",
      "observed": [
        "guv-verify=8f3a2c1d9e7b6a5f"
      ]
    }
  ],
  "registrar": {
    "name": "123-reg",
    "instructions_url": "https://guv.dev/docs/domains/123-reg"
  },
  "checks": {
    "dns": "pending",
    "ownership": "ok",
    "certificate": "pending",
    "live": "pending"
  },
  "certificate": null,
  "caa_warning": null,
  "error": null,
  "last_checked_at": "2026-10-23T14:10:00Z",
  "next_check_at": "2026-10-23T14:11:00Z",
  "created_at": "2026-10-23T14:00:00Z"
}
```
