# Hosted subdomains

> List, add, check and remove the hosted subdomains that serve the browser SDK for a site that can run no proxy. Admin keys only.

Last updated: 2026-09-25

A [hosted subdomain](https://docs.fingerly.io/docs/hosted-subdomain) is a subdomain of your site, pointed at Fingerly with a `CNAME`, that serves the browser SDK when you can run no proxy. It needs no proxy key. Only **admin** management keys can manage them; a developer key answers `403`.

**Path parameter**

- `organization_id` (string, required): Your organization, from [Describe the key](https://docs.fingerly.io/reference/management/overview#describe-the-key). A path naming any other organization answers `404`.

## List hosted subdomains

```http
GET /api/v1/management/organizations/{organization_id}/hosted-domains
```

Authentication: Management key (`x-api-key: fly_mk_…`)

**Response**

- `available` (boolean): Whether hosted subdomains can be added on this deployment. Existing ones can always be listed and removed.
- `target` (string): What each subdomain's `CNAME` points at. Omitted when `available` is `false`.
- `domains` (HostedDomain[]): Every hosted subdomain.
  - `id` (string): The hosted subdomain's ID.
  - `hostname` (string): The subdomain, such as `k7.shop.example`.
  - `path` (string): Where the browser SDK posts on it, such as `/q3v8wz1p`.
  - `status` (string): `pending` while the record does not resolve or the certificate is being issued, `active` once it is served, or `failed`.
  - `problem` (string): Why the certificate is not issued yet, or why it failed. Omitted when there is nothing to report.
  - `checked_at` (string): When its DNS and certificate were last checked.
  - `activated_at` (string): When it became `active`. Omitted until then.
  - `created_at` (string): When it was added.

## Add a hosted subdomain

```http
POST /api/v1/management/organizations/{organization_id}/hosted-domains
```

Authentication: Management key (`x-api-key: fly_mk_…`)

**Body**

- `hostname` (string, required): A subdomain of your site, such as `k7.shop.example`, never the domain itself. A label a content blocker would match, such as `fp`, `metrics` or `tracking`, is refused.
- `path` (string): Where the browser SDK will post on it. Omit it for a random one, which is what we recommend. It follows the rules of a [proxy path](https://docs.fingerly.io/reference/management/proxy-keys#paths).

Answers `201` with the hosted subdomain, `pending` until its `CNAME` to `target` resolves and its certificate is issued. Create the record, then point the browser SDK's `endpoints` at `https://<hostname><path>`.

Pending subdomains are checked every 30 seconds, so there is no need to poll. Read the list, or check one at once, to follow it.

## Check a hosted subdomain now

```http
POST /api/v1/management/organizations/{organization_id}/hosted-domains/{hosted_domain_id}/check
```

Authentication: Management key (`x-api-key: fly_mk_…`)

Checks the subdomain's DNS and certificate at once, rather than at the next scheduled check, and answers with the hosted subdomain as it is now. This is **Check now** in the dashboard.

## Remove a hosted subdomain

```http
DELETE /api/v1/management/organizations/{organization_id}/hosted-domains/{hosted_domain_id}
```

Authentication: Management key (`x-api-key: fly_mk_…`)

Stops serving the subdomain at once, drops its certificate, and answers `204`. Delete the `CNAME` at your DNS host afterwards. There is no undo: adding the name again starts over with a new certificate.

## Errors

| Status | Code | When |
| --- | --- | --- |
| `404` | `hosted_domain_not_found` | No such hosted subdomain in your organization. |
| `409` | `hosted_domains_unavailable` | Hosted subdomains cannot be added on this deployment. `available` says so in advance. |
| `409` | `hosted_domain_taken` | The name is already a hosted subdomain, of your organization or another. |
| `422` | `hosted_domain_rejected` | The name is not usable: not a subdomain, not a valid hostname, one of Fingerly's own, or a label content blockers match. `error.message` says which. |
| `422` | `proxy_path_rejected` | The `path` is not valid, or contains a word content blockers match. `error.message` names it. |

## Example request

```bash Add
curl -X POST "https://api.fingerly.io/api/v1/management/organizations/01a0a7f2-3c18-7b40-8d2e-5f6a9b1c0d37/hosted-domains" \
  -H "x-api-key: $FINGERLY_MANAGEMENT_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "hostname": "k7.shop.example"
  }'
```

```bash Check now
curl -X POST "https://api.fingerly.io/api/v1/management/organizations/01a0a7f2-3c18-7b40-8d2e-5f6a9b1c0d37/hosted-domains/01a0a863-7f40-7c12-a3e5-8b9c0d1e2f3a/check" \
  -H "x-api-key: $FINGERLY_MANAGEMENT_KEY"
```

## Example response

```json 201
{
  "id": "01a0a863-7f40-7c12-a3e5-8b9c0d1e2f3a",
  "hostname": "k7.shop.example",
  "path": "/q3v8wz1p",
  "status": "pending",
  "checked_at": "2026-09-16T09:24:40Z",
  "created_at": "2026-09-16T09:24:40Z"
}
```

```json 422
{
  "error": {
    "code": "hosted_domain_rejected",
    "message": "content blockers match on \"metrics\"",
    "status": 422
  },
  "request_id": "01a0a84c-0f11-7a3e-9c2d-4b5e6f708192"
}
```

```json 409
{
  "error": {
    "code": "hosted_domain_taken",
    "message": "that hostname is already in use",
    "status": 409
  },
  "request_id": "01a0a84c-0f11-7a3e-9c2d-4b5e6f708192"
}
```
