
# Simular el aprovisionamiento SCIM

`POST /v1/directories/{directory_id}:simulate` · permiso `directories:write` · solo para desarrollo y staging

Ejecuta un escenario del simulador SCIM contra el endpoint SCIM real del directorio. Solo durante la ejecución, KeenAuth genera un token SCIM real, lo usa y luego lo revoca. Las comprobaciones del token, los límites de tasa, el disyuntor de desaprovisionamiento masivo y el registro de aprovisionamiento se ejecutan exactamente igual que con su proveedor de identidad. Los usuarios son un conjunto fijo y ficticio: 25 personas en `example.test` en 5 grupos. No contienen datos personales reales.

El simulador es una herramienta de desarrollo y modifica el directorio. Los usuarios y grupos que escribe permanecen en el directorio como cualquier otro registro aprovisionado. Use un directorio creado para pruebas.

| Escenario | Qué hace |
|---|---|
| `seed` | Crea los 25 usuarios y los 5 grupos con sus membresías. En un directorio que ya los contiene, el primer usuario recibe un SCIM `409` y la ejecución queda como `failed`. |
| `bulk_deactivate` | Envía `active=false` para el 60 % de los usuarios (15 de 25). El disyuntor solo se activa cuando `mass_deprovision_guard.absolute_min` del directorio es 15 o menos. Con el valor predeterminado de 25, no se activa. |
| `group_churn` | Mueve un usuario de un grupo a otro. |
| `attribute_update` | Cambia el nombre para mostrar y el apellido de todos los usuarios. |
| `conflict_email` | Crea un usuario con un `userName` existente y espera un SCIM `409 uniqueness`. |

Cuando el directorio está vacío, todos los escenarios excepto `seed` ejecutan `seed` primero.

El token de simulación nunca aparece en la lista y no cuenta para los 2 tokens válidos. Usarlo no inicia la rotación del token de su proveedor de identidad. Solo puede haber una ejecución en curso por directorio. La ejecución queda auditada como `directory.simulation_started` y `directory.simulation_finished`.

## Solicitud

| Campo | Tipo | Obligatorio | Descripción |
|---|---|---|---|
| `directory_id` | path | sí | ID del directorio SCIM (`dir_…`). |
| `scenario` | body, string | sí | `seed`, `bulk_deactivate`, `group_churn`, `attribute_update` o `conflict_email`. |
| `Idempotency-Key` | header | no | Reproduce la primera respuesta de una solicitud reintentada; el escenario no se vuelve a ejecutar. |

```json
{"scenario": "bulk_deactivate"}
```

## Respuesta

`200 OK` con el resultado de la ejecución. Una respuesta de error SCIM no hace fallar la solicitud. Hace que la ejecución quede como `failed`, completa `failure` y deja los recuentos en lo que tuvo éxito antes del error. El resultado solo contiene recuentos y estados: ningún usuario, ningún ID SCIM ni ningún token.

```json
{
  "directory_id": "dir_01j9xm2n4p6q8r0s2t4v6w8y0z",
  "scenario": "bulk_deactivate",
  "status": "completed",
  "users_created": 0,
  "groups_created": 0,
  "users_updated": 0,
  "groups_updated": 0,
  "users_deactivated": 15,
  "conflicts": 0,
  "circuit_breaker_tripped": true,
  "deprovision_hold": {"id": "0191e9b2-6f3a-7c4d-8e5f-0a1b2c3d4e5f", "pending_count": 6},
  "failure": null,
  "started_at": "2026-10-28T09:31:00.123456Z",
  "completed_at": "2026-10-28T09:31:01.654321Z"
}
```

| Campo | Descripción |
|---|---|
| `status` | `completed`, o `failed` cuando el endpoint respondió con un error SCIM, la ejecución tardó demasiado o una respuesta no fue la que esperaba el escenario. |
| `users_updated` | PATCH de usuarios distintos de desactivaciones. |
| `users_deactivated` | PATCH con `active=false` aceptados por el endpoint, incluidos los retenidos. |
| `conflicts` | Respuestas `409 uniqueness` esperadas (`conflict_email`). |
| `circuit_breaker_tripped` | Se abrió una retención por desaprovisionamiento masivo durante la ejecución. |
| `deprovision_hold` | La retención abierta del directorio tras la ejecución, o `null`. Apruébela o recházela con los endpoints de `deprovision-holds`. |
| `failure` | `null` cuando `completed`. En otro caso, `reason` (`scim_error`, `timeout` o `unexpected_response`), y para `scim_error` también `scim_status` (estado HTTP) y `scim_type` (`scimType` de SCIM, o `null`). |

## Errores

| HTTP | código | Cuándo |
|---|---|---|
| 400 | `unknown_field` | El cuerpo contiene un campo distinto de `scenario`. |
| 403 | `test_feature_not_in_production` | El entorno es un entorno de producción. |
| 404 | `not_found` | El directorio no existe en este entorno. |
| 409 | `conflict` | Hay otra ejecución de este directorio en curso, o el directorio está desactivado o en proceso de eliminación. |
| 422 | `validation_failed` | Falta `scenario` o es desconocido (`/scenario`). |
| 422 | `idempotency_key_reuse` | La `Idempotency-Key` se usó para una solicitud diferente. |
| 401 | `unauthenticated` | La credencial falta, no es válida o fue revocada. |
| 403 | `insufficient_permissions` | La credencial no tiene el permiso requerido. |
| 429 | `rate_limited` | Se superó el límite de tasa; reintente después del período `Retry-After`. |
| 503 | `service_unavailable` | La sincronización del directorio o el simulador no están disponibles temporalmente o no están configurados en este despliegue; reintente después del período `Retry-After`. |

## Ejemplo

```bash
curl -X POST "https://api.eu.keenauth.com/v1/directories/dir_01j9xm2n4p6q8r0s2t4v6w8y0z:simulate" \
  -H "Authorization: Bearer $KEENAUTH_SECRET_KEY" \
  -H "Content-Type: application/json" \
  -d '{"scenario": "seed"}'
```

```bash
keenauth directories simulate dir_01j9xm2n4p6q8r0s2t4v6w8y0z --scenario bulk_deactivate
```
