
# Añadir un dominio personalizado

`POST /v1/custom-domains` · permiso `custom-domains:write`

Añade un dominio de inicio de sesión personalizado al entorno. El nombre se convierte a su A-label IDNA2008; se rechazan sufijos públicos, nombres de una sola etiqueta, direcciones IP y dominios de la plataforma. Un nombre es único en toda la plataforma: si otro entorno lo usa, o se liberó hace menos de 30 días (cuarentena), la solicitud falla con `409 custom_domain_taken`. El dominio empieza en `pending_dns`; publique los `dns_records` devueltos (un registro TXT de propiedad permanente y un CNAME al host edge del entorno) en su proveedor DNS y luego llame a `:verify` o espere a la comprobación automática.

## Solicitud

Cuerpo JSON (los campos desconocidos se rechazan con `400 unknown_field`):

| Campo | Tipo | Requerido | Descripción |
|---|---|---|---|
| `Idempotency-Key` | header | sí | Obligatorio. 16-64 caracteres `[A-Za-z0-9_-]`; repetir la misma clave con el mismo nombre devuelve el mismo dominio. |
| `hostname` | string | sí | El dominio que se añade (se admite Unicode), como máximo 253 bytes, por ejemplo `login.example.com`. |

## Respuesta

`201 Created` con el dominio y un encabezado `ETag`.

```json
{
  "id": "cdom_01j9xk3m7q8r2s4t6v8w0y2z4a",
  "hostname": "login.example.com",
  "is_primary": false,
  "status": "pending_dns",
  "failure_reason": null,
  "dns_records": [
    {
      "type": "TXT",
      "name": "_akp-verify.login.example.com",
      "value": "idp-verify=3q2-7wEXAMPLEtokenQ9"
    },
    {
      "type": "CNAME",
      "name": "login.example.com",
      "value": "acme.eu.edge.keenauth.app"
    }
  ],
  "certificate_expires_at": null,
  "last_checked_at": null,
  "next_check_at": "2026-10-05T09:36:00Z",
  "activated_at": null,
  "degraded_since": null,
  "status_changed_at": "2026-10-05T09:30:00.123456Z",
  "created_at": "2026-10-05T09:30:00.123456Z",
  "updated_at": "2026-10-05T09:30:00.123456Z"
}
```

## Errores

| HTTP | código | Cuándo |
|---|---|---|
| 400 | `malformed_request` | `Idempotency-Key` falta o no es válida. |
| 400 | `unknown_field` | El cuerpo contiene un campo desconocido. |
| 403 | `quota_exceeded` | La cuota de dominios personalizados del entorno está completa, o el entorno es de tipo `development`. |
| 409 | `custom_domain_taken` | El nombre lo usa otro entorno o está en su cuarentena de 30 días. |
| 409 | `conflict` | La cuenta o el entorno no está activo. |
| 415 | `unsupported_media_type` | El tipo de contenido no es `application/json`. |
| 422 | `validation_failed` | `hostname` no es un nombre de dominio válido para un dominio personalizado. |
| 422 | `idempotency_key_reuse` | La `Idempotency-Key` ya se usó con un cuerpo distinto. |
| 429 | `rate_limited` | Demasiados intentos de añadir dominios personalizados para la cuenta hoy; reintente después del periodo `Retry-After`. |
| 503 | `service_unavailable` | El registro de dominios de la plataforma o la información de la cuenta del entorno no está disponible temporalmente. |
| 401 | `unauthenticated` | La credencial falta, no es válida o fue revocada. |
| 403 | `insufficient_permissions` | La credencial no tiene el permiso requerido. |

## Ejemplo

```bash
curl -X POST https://api.eu.keenauth.com/v1/custom-domains \
  -H "Authorization: Bearer $KEENAUTH_SECRET_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{"hostname":"login.example.com"}'
```
