GuidesCustom domains

Attach and verify a custom domain

Pointing your own domain at a store is three legs: claim the hostname, prove you control it with a domain-control-validation (DCV) TXT record, and route traffic with a CNAME. The API hands you the exact records for every leg; this guide walks all three.

Every route here gates on the manage:own_domains scope and is scoped to the calling tenant only — the tenant comes from your fdk_ credential, so one tenant’s key can never see or touch another tenant’s domain rows.

Before you start

  • An fdk_ tenant credential with the manage:own_domains scope (a pre-live build key carries it).
  • Access to your domain’s DNS zone.
  • The API origin (https://api.ruo.pro).

Steps

Claim the hostname

POST /v1/my/domains with a hostname. The hostname is shape-validated before a claim row is created, so a malformed value is a 400 invalid_hostname — never a row that can never verify:

curl -X POST "https://api.ruo.pro/v1/my/domains" \
  -H "Authorization: Bearer fdk_your_key_here" \
  -H "content-type: application/json" \
  -d '{ "hostname": "shop.yourbrand.com" }'

The 201 response gives you both DNS records to publish:

{
  "domain": {
    "id": "…",
    "hostname": "shop.yourbrand.com",
    "verified": false,
    "verificationStatus": "pending_dns",
    "dns": {
      "recordType": "CNAME",
      "recordName": "shop.yourbrand.com",
      "recordValue": "flightdeck-storefront.onrender.com",
      "proxied": false,
      "note": "If your DNS is on Cloudflare, set this record to DNS-only (grey cloud) — a proxied record breaks TLS issuance."
    },
    "dcv": {
      "recordType": "TXT",
      "recordName": "_xxco-challenge.shop.yourbrand.com",
      "recordValue": "xxco-domain-verify=…"
    }
  }
}

A hostname already claimed by another tenant is a 409 hostname_taken.

Publish the DCV TXT record

At your DNS provider, add the dcv record exactly as returned — a TXT record at _xxco-challenge.<your-hostname> whose value is the issued xxco-domain-verify=… token. This proves you control the zone; it grants no API access and is not a secret.

You have 7 days to publish the TXT record. A claim that never verifies within that window expires, and you re-claim to get a fresh token.

Publish the CNAME

Add the dns record — a CNAME at your hostname pointing at the storefront service (flightdeck-storefront.onrender.com by default). This is what actually routes visitor traffic and lets TLS be issued.

⚠️

If your zone is on Cloudflare, set this record to DNS-only (grey cloud). A proxied (orange-cloud) record breaks TLS issuance at the edge.

Verify

A background sweep re-checks pending claims periodically, but you can force a check now with POST /v1/my/domains/{id}/verify:

curl -X POST "https://api.ruo.pro/v1/my/domains/DOMAIN_ID/verify" \
  -H "Authorization: Bearer fdk_your_key_here"

When the observed TXT record matches the token, the claim flips to verified: true and the hostname is attached to the storefront edge so TLS can be issued. If the record has not propagated yet, the claim stays pending_dns — call verify again after DNS settles (the check only acts on a pending_dns claim; an already-resolved one is returned as-is, not an error).

Check status any time

curl "https://api.ruo.pro/v1/my/domains" \
  -H "Authorization: Bearer fdk_your_key_here"           # list all claims
 
curl "https://api.ruo.pro/v1/my/domains/DOMAIN_ID" \
  -H "Authorization: Bearer fdk_your_key_here"           # one claim

Each domain reports verificationStatus (pending_dns, verified, failed, or expired) and an honest edge block for the TLS/edge attachment — an unconfigured environment or a failed attach is stated as exactly that, never presented as live.

When the edge attach failed

DCV verification and edge attachment are separate: your domain can be verified while the edge attach failed (for example, a failed edge.status). Retry just the edge leg — no re-verification — with:

curl -X POST "https://api.ruo.pro/v1/my/domains/DOMAIN_ID/edge-retry" \
  -H "Authorization: Bearer fdk_your_key_here"

This only applies to a verified domain (an unverified one is a 409 not_verified); an already-attached domain is returned as-is.

Remove a domain

DELETE /v1/my/domains/{id} removes the claim and answers 204:

curl -X DELETE "https://api.ruo.pro/v1/my/domains/DOMAIN_ID" \
  -H "Authorization: Bearer fdk_your_key_here"
  • Custom domains — the resolution model and how domains map to tenants.
  • Errors — the status codes and error bodies these routes return.