Domains and DNS

Domain access tiers, shared vs custom domains, verification flow, and readiness gating.

Domains and DNS

This guide explains how Nimriz models domains, how domain access tiers work, and how custom domains become ready for live traffic.

Core model

  • Domains are stored as host-only lowercase values.
  • Host matching is strict. example.com and www.example.com are separate records.
  • Redirect lookup is domain-bound: Host -> domain_id -> (domain_id, short_code).

Domain access tiers

Nimriz uses domains.custom_settings.api_access to decide who can call control-plane endpoints for a domain.

  • private: default; requires control-plane auth
  • public: can allow unauthenticated low-trust create and slug-check flows

Public access does not mean unrestricted access. Expiration policy, quotas, and validation rules still apply.

Shared versus custom domains

Shared Nimriz Built-in domains

Shared domains are org-owned and can be granted to multiple workspaces through account_domains. In those flows:

  • the domain belongs to the organization rather than to one workspace
  • a specific workspace can be allowed to create links on it through an explicit grant
  • delegated access should resolve from the workspace-domain grant model rather than a workspace-owner shortcut

Custom branded domains

Custom domains belong to the organization and must pass verification and Cloudflare activation checks before they are ready for traffic. After verification, org admins decide which workspaces can use them.

Recommended custom-domain flow

  1. Create the domain record in Nimriz.
  2. Publish the TXT and routing records Nimriz expects.
  3. Call POST /api/domains/verify.
  4. Review verified, verification_status, ready_for_traffic, and domain_status.
  5. If needed, call POST /api/domains/cloudflare-sync to refresh custom-hostname state.
  6. Only start creating or serving production links when the domain is fully ready.

POST /api/domains/verify

Checks DNS ownership, TXT-based certificate validation, routing alignment, and Cloudflare custom-hostname state.

Request body

{
  "domain_id": "11111111-1111-4111-8111-111111111111"
}

Successful response

{
  "ok": true,
  "domain_id": "11111111-1111-4111-8111-111111111111",
  "verified": true,
  "verification_status": "verified",
  "verification_error": null,
  "ready_for_traffic": true,
  "domain_status": "active",
  "txt": {
    "name": "_acme-challenge.links.example.com",
    "expected_value": "cf-token",
    "matched": true,
    "source": "cloudflare_dcv"
  },
  "cname": {
    "target": "cname.nimriz.dev",
    "matched": true
  }
}

Important notes

  • First-party domains do not use customer DNS verification.
  • The endpoint uses a JSON body with domain_id; it is not a path-parameter endpoint.
  • A 200 response can still report verified: false while the domain remains pending.

POST /api/domains/cloudflare-sync

Refreshes Cloudflare custom-hostname state for a customer domain and reports whether traffic can safely start.

Request body

{
  "domain_id": "11111111-1111-4111-8111-111111111111",
  "create_if_missing": true
}

Response highlights

  • ready_for_traffic
  • domain_status
  • cloudflare.custom_hostname_id
  • cloudflare.hostname_status
  • cloudflare.ssl_status

Readiness gating

Custom domains are not considered ready just because a domain record exists. Link creation and redirect serving can remain blocked until:

  • DNS ownership validation succeeds
  • certificate validation TXT records match
  • routing points to the expected target
  • Cloudflare custom-hostname and SSL statuses are active

If readiness fails, link creation can return custom_domain_not_ready.

Common failure modes

Wrong host

The most common issue is verifying or routing the wrong hostname. links.example.com and www.example.com are not interchangeable.

DNS record mismatch

The TXT value or routing target is stale, truncated, or published on the wrong label.

Cloudflare activation still pending

DNS can be correct while the hostname or SSL state is still pending.

Automation recommendations

  • Treat domain verification as a state machine, not a single yes/no check.
  • Persist domain_id in your system and poll or re-run verification until ready_for_traffic is true.
  • Keep fallback landing pages off the short-link host itself to avoid loops.

Related guides