
# Crear una clave de API

`POST /v1/api-keys` · permiso `api-keys:write` · `Idempotency-Key` obligatorio

Crea una clave de API de gestión para el entorno. Una clave `secret` accede a toda la API de gestión; una clave `restricted` solo tiene los permisos indicados (`<resource>:<action>`).

- **Clave en texto plano.** La respuesta incluye `key` una sola vez (`idp_sk_live_…`, `idp_sk_test_…`, `idp_rk_live_…` o `idp_rk_test_…`). No se puede recuperar de nuevo; guárdela de inmediato. La respuesta tiene `Cache-Control: no-store`.
- **Sin escalada.** Una clave no puede crear una clave cuyos permisos superen los suyos, y una clave `restricted` no puede crear una clave `secret`. La nueva clave no puede caducar después de la clave que la llama, y una clave que llama con `allowed_cidrs` solo puede crear claves limitadas a redes dentro de las suyas; si se omite `allowed_cidrs`, la nueva clave recibe la lista de la clave que llama (`permission_escalation`).
- **Límites.** Como máximo 50 claves activas por entorno, como máximo 20 bloques CIDR por clave, y caducidad como máximo a 730 días. Una clave con `allowed_cidrs` solo se acepta desde esas redes.
- **Repetición idempotente.** Repetir la solicitud con el mismo `Idempotency-Key` reproduce la respuesta almacenada sin la clave: el cuerpo tiene `secret_redacted: true` y no tiene `key`. Cree una clave nueva si perdió la anterior.

## Solicitud

Cuerpo:

| Campo | Tipo | Descripción |
|---|---|---|
| `name` | string | Obligatorio. De 1 a 100 caracteres. |
| `type` | string | Obligatorio. `secret` o `restricted`. |
| `permissions` | string[] | Obligatorio y no vacío para `restricted` (como máximo 200); ausente o vacío para `secret`. No puede superar los permisos del llamante. |
| `expires_at` | string (date-time) | Obligatorio, en el futuro, como máximo a 730 días. |
| `allowed_cidrs` | string[] | Opcional, como máximo 20 bloques CIDR. |

## Respuesta

`201 Created` con `Cache-Control: no-store`. El objeto de la clave como en la respuesta de lista, más `key`.

```json
{
  "id": "key_0000000000000000000000001z",
  "name": "ci",
  "type": "restricted",
  "permissions": ["users:read"],
  "allowed_cidrs": [],
  "last4": "xxxx",
  "created_by": "key_…",
  "created_at": "2026-10-01T10:00:00Z",
  "expires_at": "2027-10-01T10:00:00Z",
  "last_used_at": null,
  "last_used_ip": null,
  "rotated_from": null,
  "revoked_at": null,
  "revoke_reason": null,
  "key": "<shown once>"
}
```

## Errores

| HTTP | `code` | Cuándo |
|---|---|---|
| 401 | `unauthenticated` | La clave falta, no es válida o ha sido revocada. |
| 403 | `insufficient_permissions` | La clave no tiene el permiso requerido. |
| 403 | `permission_escalation` | La solicitud daría a una clave más permisos, un rango de red más amplio o una caducidad posterior a los de la clave que llama; una clave `restricted` intenta crear, rotar o revocar más allá de sus propios permisos; u otra clave intenta rotar o revocar una clave creada en el panel. |
| 409 | `api_key_limit_reached` | El entorno ya tiene el máximo de 50 claves activas. |
| 422 | `validation_failed` | El cuerpo no es válido: `name` falta o es demasiado largo, `type` desconocido, `restricted` sin `permissions`, `secret` con `permissions`, permiso o CIDR mal formado, `expires_at` en el pasado o a más de 730 días. |

## Ejemplo

```bash
curl -X POST https://api.eu.keenauth.com/v1/api-keys \
  -H "Authorization: Bearer $KEENAUTH_SECRET_KEY" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{"name":"ci","type":"restricted","permissions":["users:read"],"expires_at":"2027-10-01T10:00:00Z"}'
```
