# Domínio próprio

Escopo do token: `domains:write` (e `projects:read` para ler). O serviço precisa ser `public`.

## Passos

1. **Adicione** o domínio ao serviço. A resposta traz as instruções de DNS e, enquanto não provado, o registro TXT de posse.
2. **Crie no seu DNS** o que a resposta mandar:
   - subdomínio: `CNAME` para `cname.<APPS_DOMAIN>` (o valor exato vem na resposta);
   - apex (raiz): `A` (e `AAAA`, se vier) para os IPs da plataforma;
   - **TXT de posse**: nome `_nebular-verify.<seu-dominio>`, valor `nebular-verify=<token>`. É obrigatório antes da primeira ativação.
   - Com Cloudflare, deixe o registro em **DNS only** (nuvem cinza); o proxy laranja é recusado (`proxied`).
3. **Espere** a verificação (automática; propagação de DNS pode levar minutos): consulte o domínio com backoff (2 s, dobrando até 30 s, teto de ~10 min) até `status` ser `active`.

```bash
SUF=$(date +%s)-$RANDOM
P=$(curl -sS -X POST "$NEBULAR_API/v1/projects" \
  -H "Authorization: Bearer $NEBULAR_TOKEN" -H "Content-Type: application/json" \
  -H "Idempotency-Key: dom-proj-$SUF" \
  -d "{\"name\": \"demo-dom-$SUF\"}" | jq -r '.id')
S=$(curl -sS -X PATCH "$NEBULAR_API/v1/projects/$P/services/web" \
  -H "Authorization: Bearer $NEBULAR_TOKEN" -H "Content-Type: application/json" \
  -d "{\"visibility\": \"public\", \"slug\": \"demo-dom-$SUF\", \"source\": {\"type\": \"image\", \"ref\": \"ghcr.io/org/app:1.2\"}}" | jq -r '.id')

curl -sS -X POST "$NEBULAR_API/v1/projects/$P/services/$S/domains" \
  -H "Authorization: Bearer $NEBULAR_TOKEN" -H "Content-Type: application/json" \
  -H "Idempotency-Key: dom-add-$SUF" \
  -d "{\"hostname\": \"app-$SUF.exemplo.test\"}"
```
```json
{"id": "01j9zkfgny0v4n7d9agm9tb9ht", "hostname": "app.exemplo.test", "service_id": "01j9zk3jremq8fkd3sjt7h300r", "status": "pending_dns",
 "dns": {"type": "CNAME", "name": "app.exemplo.test", "value": "cname.apps.nebularws.com"},
 "verification": {"type": "TXT", "name": "_nebular-verify.app.exemplo.test", "value": "nebular-verify=7f3a9c"},
 "created_at": "2026-10-10T12:00:00Z"}
```

Acompanhar até ficar ativo:

```bash
SUF=$(date +%s)-$RANDOM
H="Authorization: Bearer $NEBULAR_TOKEN"
P=$(curl -sS -X POST "$NEBULAR_API/v1/projects" -H "$H" -H "Content-Type: application/json" \
  -d "{\"name\": \"demo-dom-$SUF\"}" | jq -r .id)
S=$(curl -sS -X PATCH "$NEBULAR_API/v1/projects/$P/services/web" -H "$H" -H "Content-Type: application/json" \
  -d "{\"visibility\": \"public\", \"slug\": \"demo-dom-$SUF\", \"source\": {\"type\": \"image\", \"ref\": \"ghcr.io/org/app:1.2\"}}" | jq -r .id)
D=$(curl -sS -X POST "$NEBULAR_API/v1/projects/$P/services/$S/domains" -H "$H" -H "Content-Type: application/json" \
  -d "{\"hostname\": \"app-$SUF.exemplo.test\"}" | jq -r .id)

delay=2
for i in $(seq 1 20); do
  st=$(curl -sS "$NEBULAR_API/v1/projects/$P/services/$S/domains/$D" -H "$H" | jq -r '.status')
  echo "tentativa $i: $st"
  [ "$st" = "active" ] && break
  sleep "$delay"; delay=$(( delay * 2 > 30 ? 30 : delay * 2 ))
done
[ "$st" = "active" ]
```

## Estados

| `status` | Significado | Ação |
|---|---|---|
| `pending_dns` | ainda sem verificação, ou a verificação achou um motivo definitivo (campo `error`: `no_records`, `wrong_target`, `proxied`, `txt_missing`) | Crie os registros da resposta (`dns` e `verification`) e espere; veja o motivo em [Problemas comuns](/dominios/problemas-comuns/). |
| `verifying` | a plataforma está verificando (inclusive após falha momentânea de DNS, `error = dns_error`) | Espere com backoff. |
| `active` | no ar; HTTPS emitido no primeiro acesso | Nada. |
| `error` | `error = misconfigured`: o DNS mudou e não aponta mais para a plataforma (após 3 verificações falhas seguidas); `error = conflict`: o domínio já está ativo em **outro projeto** | `misconfigured`: restaure os registros (volta a `active` sozinho). `conflict`: publique o TXT de posse de **este** domínio; com a prova, a plataforma o transfere para cá. Sem a prova, ele não é seu. |

## Remover

`DELETE /v1/projects/{p}/services/{s}/domains/{d}` (`domains:write`) remove o domínio; limpe também os registros DNS.

## Se algo falhar

| Resposta | O que fazer |
|---|---|
| `409 domain_taken` | Domínio já adicionado ao time ou ativo em outro projeto: use a prova TXT (acima). |
| `400 invalid_request` | Nome de domínio inválido. Corrija. |
| limite de domínios do projeto | Remova um domínio ou peça aumento (veja [Limites e cotas](/operacao/limites-e-cotas/)). |
| `404 not_found` | Projeto, serviço ou domínio inexistente ou de outro time. |
| `429 rate_limited` | Espere `Retry-After`. |

Veja também [TLS](/dominios/tls/) e [Erros](/erros/tabela/).
