# Remove a custom domain from a brand

> The brands.domains.remove operation: DELETE /api/v1/brands/{id}/domains/{host} in the REST API and the brands_domains_remove tool in the MCP server.

Removes one of the brand's custom domains. Its hosted pages stop being served on it within a minute, links sent
earlier that use it stop working, and new links use Ownrecord's own address (or the brand's other verified
domain). The domain is then detached from Ownrecord's hosting in the background.

The domain stops counting against the plan's `custom_domains.max` at once, and can be added again later, to
this brand or another. Needs `brands:write`.

## At a glance

- **REST:** `DELETE /api/v1/brands/{id}/domains/{host}`
- **MCP tool:** `brands_domains_remove`
- **Operation ID:** `brands.domains.remove`
- **Scope:** Organization, or one of its legal entities or brands
- **Permission:** `brands:write`
- **Risk tier:** `write`
- **Dry run:** Supported (send `Ownrecord-Dry-Run: true`)
- **Idempotency:** `Idempotency-Key` optional
- **Modes:** Test and live
- **Authentication:** API key with the `brands:write` scope
- **Since:** M9

## Request

### Path parameters

| Field  | Type       | Description                                  |
| ------ | ---------- | -------------------------------------------- |
| `id`   | `brd_…` ID |                                              |
| `host` | string     | The domain's host name, e.g. `pay.acme.com`. |

### Body

A JSON object (`Content-Type: application/json`):

| Field    | Type   | Required | Description             |
| -------- | ------ | -------- | ----------------------- |
| `reason` | string | No       | Why, for the audit log. |

## Response

`200 OK` with a JSON object:

| Field     | Type                        | Description                                                      |
| --------- | --------------------------- | ---------------------------------------------------------------- |
| `object`  | `"brand_domain"`            |                                                                  |
| `host`    | string                      |                                                                  |
| `purpose` | one of `checkout`, `portal` | `checkout` serves hosted checkout, `portal` the customer portal. |
| `brandId` | string                      |                                                                  |
| `deleted` | `true`                      |                                                                  |

## Examples

### Remove the checkout domain

```http
DELETE /api/v1/brands/brd_01m4tx5nj8emwbyf7y9vcf47x4/domains/pay.acme-app.com
Authorization: Bearer or_test_…
Content-Type: application/json

{
  "reason": "Moving checkout to pay.acme.io"
}
```

Response (`200`):

```json
{
  "object": "brand_domain",
  "host": "pay.acme-app.com",
  "purpose": "checkout",
  "brandId": "brd_01m4tx5nj8emwbyf7y9vcf47x4",
  "deleted": true
}
```

## Errors

| Code                                                                                     | HTTP status | When                                                                     | What to do                                                                                           |
| ---------------------------------------------------------------------------------------- | ----------- | ------------------------------------------------------------------------ | ---------------------------------------------------------------------------------------------------- |
| [`validation_failed`](https://ownrecord.io/docs/reference/errors.md#validation_failed)   | 400         | A field is missing or malformed.                                         | Fix the fields listed in `details.issues` and send the request again.                                |
| [`resource_not_found`](https://ownrecord.io/docs/reference/errors.md#resource_not_found) | 404         | The brand isn't visible to the request, or has no domain with this host. | Check the ID and that your credentials are scoped to the right organization, entity, brand and mode. |
| [`version_conflict`](https://ownrecord.io/docs/reference/errors.md#version_conflict)     | 409         | The brand changed at the same time; retry.                               | Fetch the object again and retry the change.                                                         |
| [`permission_denied`](https://ownrecord.io/docs/reference/errors.md#permission_denied)   | 403         | You can't change this brand's settings.                                  | Ask an organization owner or admin for a role or scope that allows this action.                      |

It can also return these [common errors](https://ownrecord.io/docs/reference.md#common-errors): [`api_version_unsupported`](https://ownrecord.io/docs/reference/errors.md#api_version_unsupported), [`invalid_json`](https://ownrecord.io/docs/reference/errors.md#invalid_json), [`unsupported_media_type`](https://ownrecord.io/docs/reference/errors.md#unsupported_media_type), [`authentication_required`](https://ownrecord.io/docs/reference/errors.md#authentication_required), [`api_key_invalid`](https://ownrecord.io/docs/reference/errors.md#api_key_invalid), [`idempotency_key_reused`](https://ownrecord.io/docs/reference/errors.md#idempotency_key_reused), [`idempotency_in_progress`](https://ownrecord.io/docs/reference/errors.md#idempotency_in_progress), [`approval_required`](https://ownrecord.io/docs/reference/errors.md#approval_required), [`approval_rejected`](https://ownrecord.io/docs/reference/errors.md#approval_rejected), [`approval_expired`](https://ownrecord.io/docs/reference/errors.md#approval_expired), [`stale_approval`](https://ownrecord.io/docs/reference/errors.md#stale_approval), [`approval_policy_denied`](https://ownrecord.io/docs/reference/errors.md#approval_policy_denied), [`rate_limited`](https://ownrecord.io/docs/reference/errors.md#rate_limited), [`internal_error`](https://ownrecord.io/docs/reference/errors.md#internal_error).
