Domainee Docs

Errors and edge cases

HTTP status codes, monitor states, idempotency, and rate limits.

Every API error returns a JSON body of the shape:

{
  "error": "<machine-readable-code>",
  "message": "<human-readable explanation>",
  "details": { ... }
}

details is sometimes present — for example, a list of preflight warnings when domain creation fails preflight.

HTTP status reference

StatusWhen
200Success
201Resource created
400bad_request — your input is invalid (bad hostname, bad URL)
400preflight_failed — domain create blocked by CAA / SSRF
401unauthorized — missing or invalid Bearer token
402billing_required — free quota exceeded, no payment method on file
403forbidden — token valid, but action not allowed (workspace mismatch)
404not_found — the resource id doesn't exist (or doesn't belong to you)
409conflict — hostname already in use
429rate_limited — too many requests; check Retry-After header
500internal_error — our problem; report it

Monitor states

The monitorStatus field on a Domain reflects runtime health, computed from DNS + cert + origin reachability signals every ~60 seconds. The accompanying monitorMessage gives a customer-facing explanation.

monitorStatusWhat it meansWhat to show your customer
unknownWe haven't probed yet"Setup in progress"
dns_not_resolvingThe hostname doesn't resolve at all"Add the CNAME record at your registrar"
dns_incorrectDNS resolves but not to our edge"Update your CNAME — it points elsewhere"
pending_sslDNS is correct, waiting for cert"Almost there — SSL is being issued"
active_sslVerified and serving traffic"Your site is live" (✅)
target_not_loading(Reserved for future origin health checks)
ssl_failedCert issuance failed irrecoverably"We couldn't issue an SSL cert. Check CAA records."
ssl_expiredThe cert window elapsed without renewal"Your domain's certificate has expired. Re-verify DNS."

Idempotency

For idempotent retries on POST requests, send an Idempotency-Key header. Same key + same path + same workspace within 24 hours returns the cached original response, with header idempotent-replay: true.

curl -X POST https://api.domainee.dev/v1/domains \
  -H "Authorization: Bearer $DOMAINEE_API_KEY" \
  -H "Idempotency-Key: order-123-domain-create" \
  -H "content-type: application/json" \
  -d '{ "hostname": "shop.acme.com", "originUrl": "https://acme.fly.dev" }'

The key is scoped to your workspace — different workspaces with the same key don't collide.

Rate limits

Default: 60 requests per minute per API key across all /v1/* endpoints.

Some endpoints have additional, tighter limits:

EndpointPer-key limit
POST /v1/domains100/hour
POST /v1/domains/bulk5/hour (×100 domains = 500 hostnames/hour ceiling)
POST /v1/domains/:id/check60/min
/v1/dns/check-records-*600/hour

When you hit a limit you get:

HTTP/1.1 429 Too Many Requests
Retry-After: 42
x-ratelimit-limit: 60
x-ratelimit-remaining: 0
x-ratelimit-reset: 1714572420

{
  "error": "rate_limited",
  "message": "Too many requests for action 'create_domain'. Try again in 42s.",
  "details": { "action": "create_domain", "retryAfter": 42 }
}

Respect Retry-After (in seconds) to avoid hammering us during cool-down.

SSRF protection

When you submit an originUrl, we resolve its hostname and reject any value that points at:

  • Private RFC 1918 ranges (10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16)
  • Loopback (127.0.0.0/8, ::1)
  • Link-local — including AWS/GCP metadata (169.254.169.254)
  • CGNAT (100.64.0.0/10)
  • Multicast and reserved ranges
  • Hostnames like localhost, *.local, *.internal

This protects us (and you) from being used as a tunnel to internal infrastructure.

CAA records

If a customer's domain has CAA records that don't authorize Let's Encrypt or ZeroSSL, cert issuance will fail when first traffic arrives. We surface this as a preflight warning when you create the domain:

{
  "warnings": [
    {
      "code": "caa_blocks_lets_encrypt",
      "message": "This domain has CAA records that don't authorize Let's Encrypt or ZeroSSL...",
      "caaRecords": ["digicert.com"]
    }
  ]
}

Treat this as fatal even though the domain is created — traffic will never work until the customer fixes their CAA. The customer needs to add a CAA record permitting letsencrypt.org or remove their existing CAA records.

When in doubt

  • Check the x-domainee-request-id response header on any failure — paste it in support requests so we can find the exact log line.
  • The dashboard's Developers page shows recent API calls per key.

On this page