
# Crear una transacción de inicio de sesión

`POST /fapi/v1/transactions` · llamado desde el host de inicio de sesión del entorno

Inicia una transacción de inicio de sesión para una aplicación. La página alojada de inicio de sesión, los componentes de interfaz y los clientes headless llaman a este
endpoint en el host de inicio de sesión del entorno (un subdominio `keenauth.app` o un dominio personalizado verificado). La respuesta establece la
cookie de transacción `__Host-idp_ltx` (Secure, HttpOnly, SameSite=Lax, válida durante 15 minutos); los pasos posteriores usan esa cookie.

## Solicitud

Encabezados:

| Encabezado | Obligatorio | Descripción |
| --- | --- | --- |
| `Idp-Client` | sí | Identificador del SDK, `<package>/<version> (<runtime>/<version>)`. |
| `Origin` | sí | Debe ser exactamente `https://<sign-in host>`. |

Cuerpo:

| Campo | Tipo | Obligatorio | Descripción |
| --- | --- | --- | --- |
| `client_id` | string | sí | El ID de cliente de la aplicación. |
| `redirect_uri` | string (URI) | sí | Una de las URI de redirección registradas de la aplicación. |

## Respuesta

`201 Created` con el objeto de transacción:

```json
{
  "schema_version": 1,
  "state": "identifier_pending",
  "next_steps": [{ "step": "identifier", "fields": ["identifier"] }],
  "csrf_token": "<token>",
  "expires_at": "2026-10-05T10:15:00Z"
}
```

Envíe `csrf_token` de vuelta en el encabezado `Idp-Csrf-Token` en cada solicitud de esta transacción que modifique el estado.

Cuando la solicitud de autorización indica una organización que requiere SSO, la respuesta puede ser ya
`federated_redirect` con `redirect_url` (una sola conexión: navegue allí en la ventana de nivel superior) o incluir
`sso_connections` (varias: envíe la elección con el paso `sso_start`).

## Transacciones headless vinculadas a DPoP

Una SPA o una aplicación nativa de primera parte en su propio origen inicia un inicio de sesión headless con un encabezado `DPoP` (RFC 9449): una prueba
firmada con una clave que conserva el cliente (una clave no extraíble de WebCrypto en un navegador, el almacén de claves de la plataforma en un dispositivo),
con `htm` `POST` y `htu` `https://<sign-in host>/fapi/v1/transactions`. La transacción queda entonces vinculada a esa clave
en lugar de a una cookie: no se establece ninguna cookie y el objeto no tiene `csrf_token`. Cada solicitud posterior de la transacción envía una
nueva prueba firmada con la misma clave.

Campos adicionales del cuerpo, verificados con las reglas del endpoint de autorización:

| Campo | Tipo | Obligatorio | Descripción |
| --- | --- | --- | --- |
| `code_challenge` | string | sí | Desafío PKCE S256 (RFC 7636). |
| `code_challenge_method` | string | sí | `S256`. |
| `scope` | string | no | Ámbitos separados por espacios, por ejemplo `openid profile email offline_access`. |
| `state` | string | no | Se devuelve con el código de autorización. |
| `nonce` | string | no | El `nonce` del ID token. |
| `organization` | string | no | ID o nombre de la organización. |
| `ui_locales` | string | no | Idiomas preferidos. |
| `resource` | string (URI) | no | Indicador de recurso (RFC 8707). |

`Origin` puede ser el host de inicio de sesión o uno de los orígenes web permitidos de la aplicación; una aplicación nativa no envía ninguno. Solo
las aplicaciones de primera parte pueden iniciar una de estas transacciones. Un campo que el endpoint de autorización rechaza devuelve `422 validation_failed` con
el código de error OAuth en `errors[].code`. Cuando el servidor responde `401 use_dpop_nonce`, firme una nueva prueba con el valor
del encabezado de respuesta `DPoP-Nonce` y reintente. Enviar estos campos sin un encabezado `DPoP` devuelve
`422 validation_failed` (`dpop_required`).

## Cambiar de organización

Una aplicación que posee un token de acceso a la Front API para el usuario con sesión iniciada (véase [Token de acceso de Front API](/docs/api/fapi/front-api-token))
cambia al usuario a otra organización sin mostrar ninguna pantalla. Envíe el token en `Authorization: DPoP <token>` con una prueba
de la clave del token (con `ath`), y en el cuerpo, `flow` `organization_switch`, los campos headless vinculados a DPoP indicados arriba
(`client_id` de la aplicación del token, `redirect_uri`, `code_challenge`, `state`, `nonce`, `scope`) y
`organization`, el ID `org_…` de una organización obtenida de `GET /fapi/v1/me/organizations`.

La solicitud se resuelve de inmediato con la sesión del token, como lo haría un inicio de sesión que reutiliza la sesión: la
política de la organización (MFA, límite de inactividad, SSO, lista de IP), el consentimiento y los documentos legales pendientes. La respuesta es `201` con una
transacción `completed` que incluye `authorization_response`; canjee su `code` en el endpoint de token con su
`code_verifier` y una prueba de la misma clave. Los nuevos tokens incluyen la organización en `org_id`. No queda ninguna transacción abierta
ni se establece ninguna cookie.

```json
{
  "schema_version": 1,
  "state": "completed",
  "next_steps": [],
  "authorization_response": { "code": "<code>", "state": "<state>", "iss": "https://example.keenauth.app" },
  "expires_at": "2026-10-05T10:15:00Z"
}
```

| Estado | Código | Cuándo |
| --- | --- | --- |
| 401 | `unauthenticated` | El token no es válido, ha caducado, ha sido revocado o no está vinculado a una clave, su aplicación no es una aplicación de primera parte activa, o su sesión ha terminado. |
| 422 | `validation_failed` | `flow` no es `organization_switch`, `client_id` no es la aplicación del token, `organization` no es un ID `org_…`, o el usuario no puede cambiar a ella en esta aplicación (`not_eligible`). |
| 403 | `authorization_failed` | La organización necesita una pantalla que el cambio no puede mostrar; `error` es el error OAuth (`login_required`, `interaction_required`, `consent_required`). Inicie un nuevo inicio de sesión con `organization` definido. |

`flow` `organization_switch` sin el token devuelve `422 validation_failed` (`access_token_required`).

## Errores

| Estado | Código | Cuándo |
| --- | --- | --- |
| 400 | `malformed_request` | Falta `Idp-Client` o el cuerpo no es JSON válido. |
| 403 | `origin_not_allowed` | `Origin` no es el host de inicio de sesión. |
| 403 | `headless_not_allowed` | Una aplicación de terceros intentó iniciar un flujo headless. |
| 404 | `not_found` | El host no es un host de inicio de sesión de ningún entorno. |
| 422 | `validation_failed` | `client_id` no es una aplicación de este entorno, `redirect_uri` no está registrada para ella, o un campo no es válido. |
| 401 | `invalid_dpop_proof` | La prueba `DPoP` falta, no es válida o se reutilizó, o el host no sirve transacciones vinculadas a DPoP. |
| 401 | `use_dpop_nonce` | Firme una nueva prueba con el valor del encabezado de respuesta `DPoP-Nonce`. |
| 503 | `temporarily_unavailable` | Una dependencia no está disponible; reintente más tarde. |

## Ejemplo

```bash
curl -X POST https://example.keenauth.app/fapi/v1/transactions \
  -H "Idp-Client: my-app/1.0.0 (node/22.0.0)" \
  -H "Origin: https://example.keenauth.app" \
  -H "Content-Type: application/json" \
  -c cookies.txt \
  -d '{"client_id":"<client_id>","redirect_uri":"https://app.example.com/callback"}'
```

## Datos personales

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