# Reference

> Lookup tables for CustomDomain™: enums, DNS record types, webhook events, error codes, environment variables, webhook signatures and the default edge record.

Source: https://docs.customdomain.ai/docs/reference

## Enums

**ConnectionStatus**: `pending`, `propagating`, `live`, `failed`.

**SetupType**: `automatic`, `manual`, `async`, `mcp`.

**Role**: `owner`, `admin`, `member`, `viewer`.

**PlanId**: `starter`, `startup`, `growth`, `premium`, `enterprise` (and `free`, retired on 2026-09-29: it still names a legacy workspace moving to a paid plan, and is never offered).

**BillingState**: `trialing`, `active`, `past_due`, `grace`, `blocked`, `comped`, `canceled`, `legacy_free` (see [Plans & quotas](/docs/billing/plans-and-quotas#billing-states)).

**Environment**: `production`, `staging`, `development`.

**DNS record types**: `A`, `AAAA`, `CNAME`, `CAA`, `MX`, `NS`, `SRV`, `TXT`, plus the
meta-types `SPFM` (SPF-merge), `APEXCNAME` (a CNAME at the zone root, realized
per provider) and `REDIR301`.

**One-click setup template shapes** (the provider-hosted one-click protocol;
customdomain.ai catalog shipped in prod):
web: `apex-a`, `apex-aaaa`, `apex-cname`, `apex-www`, `subdomain`, `www`,
`wildcard`, `customdomain`, `website`, `clickfunnels`; ownership: `verify`, `connect-verified` (apex A + ownership TXT
applied together); `caa`; email: `email-spf`, `email-dkim`, `email-dmarc`,
`email-mx`, `email-full`; and `redirect` (301 forward).

**Webhook events** (the complete set; see
[webhooks](/docs/webhooks/overview)): `connection.created`,
`connection.applied`, `connection.live`, `connection.failed`,
`connection.records.updated`, `connection.reapply.failed`,
`connection.records_outdated`, `connection.disconnected`,
`domain.record_missing`, `domain.record_restored`, `domain.purchased`,
`purchase.error`, `purchase.confirmation.expired`, `secure_status`,
`power_status`, `certificate.issued`, `certificate.renewed`,
`certificate.failed`, `certificate.expiring`.

## Error envelope & codes

Every error is `{ "code", "title", "details"? }`. `code` is a stable machine
string:

| `code`                    | HTTP | Meaning                                                                                                                                                                                                                                                                                                                                                                                                                                                      |
| ------------------------- | ---- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `invalid_request`         | 400  | Malformed or missing input.                                                                                                                                                                                                                                                                                                                                                                                                                                  |
| `unauthorized`            | 401  | Missing/invalid credential.                                                                                                                                                                                                                                                                                                                                                                                                                                  |
| `forbidden`               | 403  | The credential is valid but may not do this (a role or scope too low).                                                                                                                                                                                                                                                                                                                                                                                       |
| `not_found`               | 404  | Object doesn't exist or isn't in your tenant.                                                                                                                                                                                                                                                                                                                                                                                                                |
| `conflict`                | 409  | The request conflicts with the resource's current state.                                                                                                                                                                                                                                                                                                                                                                                                     |
| `rate_limited`            | 429  | Too many requests; slow down and retry shortly.                                                                                                                                                                                                                                                                                                                                                                                                              |
| `reach_quota`             | 429  | The workspace has made as many reads at DNS providers, to find out what a key reaches, as it may this hour. `Retry-After` is the seconds until the hour ends. See [provider accounts](/docs/connect-flow/provider-accounts#checks-at-the-provider-have-an-hourly-limit).                                                                                                                                                                                     |
| `billing_required`        | 402  | The workspace has no active subscription or trial, so new connections and new credentials (API keys, applications, rotated secrets) are refused (existing ones keep working). A new workspace's first ten domains (its free domains) are the exception: they connect without a card, and the next one is refused. `details` says why and where an owner or admin can fix it. See [Plans & quotas](/docs/billing/plans-and-quotas#what-a-refusal-looks-like). |
| `connections_unavailable` | 402  | The same refusal as the tenant's end users see it, with a neutral message that says nothing about the tenant's billing or account. A connect-scoped widget token (your customer in the widget) gets it in place of `billing_required`, `quota_exceeded` and `workspace_suspended`.                                                                                                                                                                           |
| `quota_exceeded`          | 402  | A Starter workspace connected its allowance of 10 domains in any 12 months (only where the deployment enforces quotas).                                                                                                                                                                                                                                                                                                                                      |
| `workspace_suspended`     | 403  | CustomDomain™ support suspended the workspace. New connections, every connect step on a domain it already has (a key apply, a provider sign in, one-click setup, the Route 53 access role, the hosted zone and `:reapply`) and the start of a domain purchase are refused. Reads, rechecks and removals keep working, and connected domains keep their records. Only support can resume the workspace.                                                       |
| `sandbox_not_allowed`     | 403  | A [test mode](/docs/guides/test-mode) application's key or widget token, or a test mode domain, was used on something outside the test flow (SSL, Power, sign in, bulk, agents, purchases and the rest). `details` names what was refused.                                                                                                                                                                                                                   |
| `sandbox_domain_required` | 400  | A test mode application was given a name that does not end in `.test`.                                                                                                                                                                                                                                                                                                                                                                                       |
| `sandbox_domain_reserved` | 400  | A live application was given a `.test` name. Those are for test mode.                                                                                                                                                                                                                                                                                                                                                                                        |
| `sandbox_limit`           | 409  | The test mode allowance is used up: 3 test mode applications per workspace, 100 test domains per application.                                                                                                                                                                                                                                                                                                                                                |
| `service_unavailable`     | 503  | An optional engine (Sell, templates, billing, webhooks) isn't configured.                                                                                                                                                                                                                                                                                                                                                                                    |
| `internal_error`          | 500  | Server error (generic `title` + a logged request id).                                                                                                                                                                                                                                                                                                                                                                                                        |

## Environment variables

Control-plane variables read `CUSTOMDOMAIN_*` first and fall back to the legacy
`JUSTEASY_*` prefix. Variables that matter for API consumers are called out on
the page that uses them.

## Webhook signature

* Headers: `X-JE-Timestamp: <unix seconds>` and `X-JE-Signature: sha256=<hex>`.
* Algorithm: HMAC-SHA256 over `${timestamp}.${rawBody}` (the timestamp, a dot,
  then the exact request body), keyed by the endpoint's signing secret
  (`whsec_…`). Reject deliveries whose timestamp is outside a \~5-minute window.
  See [Verifying signatures](/docs/webhooks/verifying-signatures).

## Default edge record

A connection with no applied records yet points at the edge with a synthesized
`CNAME <host> → edge.customdomain.ai` (TTL 3600), overridable with
`JUSTEASY_EDGE_CNAME_TARGET`. At a zone root the record is realized per
provider (ALIAS/ANAME/flattened CNAME, or `A` records to the edge IPs); see
[Root domains](/docs/dns/root-domains).

## Resources

* [Architecture](/docs/concepts/architecture): the two-plane design, data
  model, and request flows.
* [`openapi-v1.yaml`](/docs/api-reference): the OpenAPI document the API
  reference is generated from; also served live at `GET /v1/openapi.json`.
