
# Crear un usuario

`POST /v1/users` · permiso `users:write`

Crea un usuario en el entorno de la clave de API. El usuario pertenece únicamente a ese entorno; la misma dirección de correo electrónico en dos entornos corresponde a dos usuarios distintos. Los valores únicos (`email`, `phone_number`, `username`, `external_id`) se comprueban por entorno. Envíe una cabecera `Idempotency-Key` para que los reintentos sean seguros.

## Solicitud

El cuerpo es un objeto JSON. Los campos desconocidos se rechazan con `unknown_field`.

| Campo | Tipo | Obligatorio | Descripción |
|---|---|---|---|
| `email` | string | no* | Dirección de correo electrónico principal. |
| `email_verified` | boolean | no | Marca la dirección de correo electrónico como verificada. Valor predeterminado `false`. |
| `phone_number` | string | no* | Número de teléfono principal en formato E.164. |
| `phone_verified` | boolean | no | Marca el número de teléfono como verificado. Valor predeterminado `false`. |
| `phone_country_code` | string | no | Código ISO 3166-1 alpha-2. Se deriva del prefijo del teléfono cuando está vacío. |
| `username` | string | no* | De 3 a 64 caracteres. Único en el entorno. |
| `external_id` | string | no | Su propio identificador, de 1 a 255 caracteres. Único en el entorno. |
| `name`, `given_name`, `family_name`, `middle_name`, `nickname` | string | no | Nombres del perfil. |
| `picture`, `website`, `profile_url` | string | no | URL `https://`, de hasta 2048 caracteres. |
| `locale`, `zoneinfo`, `gender`, `birthdate` | string | no | Atributos del perfil. `birthdate` tiene el formato `YYYY-MM-DD`. |
| `address` | object | no | Objeto `address` de OIDC, de hasta 2048 bytes. |
| `user_metadata`, `app_metadata` | object | no | Objetos JSON de formato libre, de hasta 16 KiB, profundidad 5, 100 claves de primer nivel. |

\* Se requiere al menos uno de `email`, `phone_number` o `username`.

## Respuesta

`201 Created`. El cuerpo es el objeto del usuario. La cabecera `ETag` contiene la versión del usuario.

Los datos personales se enmascaran cuando la clave no tiene el permiso `users:read_pii`: `email` pasa a ser `a***@e***.com`, `phone_number` conserva solo sus últimos 2 dígitos (`+**********67`), `name`, `given_name`, `family_name`, `middle_name` y `nickname` pasan a ser iniciales (`A. L.`), `username` conserva solo su primer carácter (`a***`), `birthdate` pasa a ser `****-**-**` y `address` pasa a ser `{"redacted": true}`. `user_metadata` y `app_metadata` no se enmascaran.

```json
{
  "id": "usr_0a1b2c3d4e5f6g7h8j9k0m1n2p",
  "kind": "regular",
  "status": "active",
  "external_id": null,
  "username": null,
  "name": "Ada Lovelace",
  "email": "ada@example.com",
  "email_verified": true,
  "phone_number": null,
  "phone_verified": false,
  "user_metadata": {},
  "app_metadata": {},
  "created_via": "admin_api",
  "created_at": "2026-01-15T09:30:00Z",
  "updated_at": "2026-01-15T09:30:00Z",
  "last_sign_in_at": null,
  "deletion_requested_at": null,
  "deletion_due_at": null
}
```

## Errores

Cada error es un cuerpo `application/problem+json` con un `code` estable.

| HTTP | `code` | Cuándo |
|---|---|---|
| 400 | `malformed_request`, `unknown_field` | El cuerpo no es JSON válido o tiene un campo que no está en el esquema. |
| 409 | `conflict` | El valor ya está en uso. `errors[]` indica el campo y el motivo (`email_taken`, `phone_taken`, `username_taken`, `external_id_taken`). |
| 415 | `unsupported_media_type` | `Content-Type` no es `application/json`. |
| 422 | `validation_failed` | Un valor no es válido; `errors[].pointer` indica el campo. |
| 401 | `unauthenticated` | Falta la clave de API, no es válida o ha sido revocada. |
| 403 | `insufficient_permissions` | La clave no tiene el permiso `users:write`. |
| 429 | `rate_limited` | Se ha superado el límite de frecuencia; respete `Retry-After`. |
| 503 | `service_unavailable` | Una dependencia no está disponible temporalmente; vuelva a intentarlo más tarde. |

## Ejemplo

```bash
curl -X POST https://api.eu.keenauth.com/v1/users \
  -H "Authorization: Bearer $KEENAUTH_SECRET_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{"email": "ada@example.com", "email_verified": true, "name": "Ada Lovelace"}'
```

## Datos personales

Este endpoint contiene datos personales: perfil del usuario final. [Datos personales en las API de KeenAuth](/docs/policies/personal-data) describe qué se almacena, durante cuánto tiempo se conserva y cómo se elimina. No envíe categorías especiales de datos personales (salud, datos biométricos, religión, opiniones políticas, orientación sexual) en ningún campo.
