---
title: "Update a domain"
method: PATCH
path: "/domains/{domain}"
tags: ["Domains"]
---

# Update a domain

`PATCH /domains/{domain}`

## Request

- Base URL: `https://api.spectate.net/v1`
- URL: `https://api.spectate.net/v1/domains/{domain}`
- Auth: HTTP bearer

Changes only the fields you send. A new `name` forgets the old registration data and is
looked up at once. Resuming (`enabled: true`) goes through the plan's domain limit.

## Path parameters

- `domain` string, uuid, required

## Request body

- UpdateDomain: Changes to a monitored domain; fields you leave out keep their value.
  - `name` string: Another domain to monitor instead; its registry data is looked up again
  - `enabled` boolean: Pause (`false`) or resume (`true`) monitoring. Resuming goes through the plan's domain limit
  - `expiry_threshold_days` integer: Days before expiry, 1 to 365, that the "expires soon" alert fires
  - `alert_on_registry_changes` boolean: Raise an alert when the registrar, nameservers or DNSSEC keys change
  - `project_id` string, uuid, nullable: Project of the domain; `null` for none
  - `escalation_path_ids` string[]: Escalation paths for the domain's alerts; replaces the current ones

## Response `200`

The updated domain.

- Domain: A monitored domain registration: Spectate looks it up at its registry (RDAP or WHOIS) every few hours and alerts before it expires and, optionally, when its registrar, nameservers or DNSSEC change.
  - `id` string, uuid, required: Domain ID
  - `name` string, required: The registered domain, lowercase, internationalised names in punycode
  - `enabled` boolean, required: Whether the domain is monitored. `false` when paused by a member or by the system (see `paused_reason`)
  - `paused_reason` 'plan_limit' | 'team_paused', required: Why the system (not the user) paused a monitor, host, domain or status page. | | |---| | `plan_limit` <br/> Over the plan limit (trial expired, downgrade); the oldest resources stay active. | | `team_paused` <br/> The whole team's monitoring is paused (no paid plan, staff action or scheduled deletion). |
  - `registrar` string, nullable, required: The registrar, as the registry reports it
  - `registered_at` string, date-time, nullable, required: When the domain was registered
  - `expires_at` string, date-time, nullable, required: When the registration expires
  - `registry_changed_at` string, date-time, nullable, required: When the registration last changed at the registry
  - `days_until_expiration` integer, nullable, required: Days until the registration expires; negative once expired
  - `is_expired` boolean, required: Whether the registration has expired
  - `is_expiring_soon` boolean, required: Whether it expires within `expiry_threshold_days`
  - `nameservers` string[], nullable, required: The domain's nameservers
  - `dnssec` boolean, required: Whether the registry publishes DNSSEC keys for the domain
  - `dnssec_keys` DomainDnssecKey[], nullable, required: The DNSSEC delegation signer records
    - `key_tag` integer, nullable, required: Key tag of the DNSKEY the record points at
    - `algorithm` integer, nullable, required: DNSSEC algorithm number, for example 13 (ECDSA P-256 with SHA-256)
    - `digest_type` integer, nullable, required: Digest type number, for example 2 (SHA-256)
    - `digest` string, nullable, required: The digest, in hexadecimal
  - `statuses` string[], nullable, required: EPP status codes, for example `client transfer prohibited`
  - `registry_source` 'rdap' | 'whois', required: Where a domain's registry data came from. | | |---| | `rdap` <br/> The registry's RDAP service. | | `whois` <br/> The registry's WHOIS server, for registries without RDAP. |
  - `registry_error` 'unsupported' | 'not_registered' | 'unavailable', required: Why the last registry lookup of a domain gave no data. | | |---| | `unsupported` <br/> The registry publishes neither RDAP nor WHOIS (e.g. .gr, .vn). | | `not_registered` <br/> The registry has no such domain: not registered (or a subdomain was entered). | | `unavailable` <br/> The registry didn't answer usefully, even after retries; tried again at the next check. |
  - `last_checked_at` string, date-time, nullable, required: When the registry was last checked
  - `expiry_threshold_days` integer, required: Days before expiry that the "expires soon" alert fires
  - `alert_on_registry_changes` boolean, required: Whether changes of the registrar, nameservers or DNSSEC keys raise an alert
  - `project_id` string, uuid, nullable, required: The project the domain belongs to; `null` for none
  - `escalation_paths` EscalationPathReference[], required: Escalation paths the domain's alerts follow. Empty: the project's paths, else the team's default path
    - `id` string, uuid, required: Escalation path ID
    - `name` string, required: Escalation path name
  - `created_at` string, date-time, required: When monitoring of the domain started

## Other responses

- `401`: `UNAUTHENTICATED`: no token was sent. `INVALID_TOKEN`: the token is unknown or revoked. `TOKEN_EXPIRED`: the token has expired.
- `403`: `PLAN_LIMIT_REACHED`: the plan doesn't allow another one; `details.feature` names the limit. `FORBIDDEN`: the token lacks an ability this endpoint requires (listed in `details.required_abilities`). `TEAM_PENDING_DELETION`: the team is scheduled for deletion. `TEAM_SUSPENDED`: Spectate suspended the team.
- `404`: `RESOURCE_NOT_FOUND`: there is no such resource in this team.
- `409`: `TEAM_MONITORING_PAUSED`: the team's monitoring is paused (no paid plan), so nothing can be resumed until it subscribes.
- `422`: `VALIDATION_FAILED`: the request is invalid; `details.errors` lists the fields.
- `429`: `RATE_LIMITED`: too many requests for this token. Wait for the number of seconds in `Retry-After`.

---

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