> ## Documentation Index
> Fetch the complete documentation index at: https://docs.fluz.app/llms.txt
> Use this file to discover all available pages before exploring further.

# Terminar una sesión del Widget

> Cancela un pago que ya entregaste al widget, para que el usuario no pueda completarlo.

Generas un `patToken`, se lo entregas al widget, y el usuario se va — o tu propio sistema cancela la orden un minuto después. El token permanece válido hasta el `exp` con el que lo firmaste, así que sin una forma de revocarlo el usuario podría volver más tarde y completar un pago que ya no quieres.

`terminateWidgetSession` finaliza la sesión del lado del servidor. Al usuario se le niega el acceso la próxima vez que navegue dentro del widget, y cualquier intento de pago contra esa sesión es rechazado.

<Info>
  **Requisitos previos:** la API Key de tu aplicación para autenticación Basic, y ya sea el operator token que emitiste o su `jti`.
</Info>

## Autenticación

Esta mutación se autentica con las credenciales de tu **aplicación**, no con un access token de usuario — el mismo encabezado `Basic` que ya usas para [`generateUserAccessToken`](/get-started/api-credentials):

```text theme={null}
Authorization: Basic <YOUR_API_KEY>
```

Envía la API Key del Developer Console tal cual; ya está codificada en base64 y decodifica al par `app_id:apiSecret` que verifica el servidor. Usa la key de la misma aplicación cuyo `apiSecret` firmó el operator token.

<Warning>
  Staging y producción son aplicaciones separadas con credenciales separadas. Una key del entorno incorrecto devuelve `401` con el mismo mensaje que una mal formada — consulta [If the token request returns 401](/get-started/api-credentials) para la lista completa de verificación.
</Warning>

Solo puedes terminar sesiones que pertenezcan a la aplicación con la que te autenticas. Un `jti` emitido por una aplicación diferente no se ve afectado por tu llamada — obtendrás una respuesta exitosa con `wasActive: false`, y la sesión de esa aplicación seguirá en ejecución.

La autenticación Basic no está disponible para aplicaciones con estado `PERSONAL`.

## Identificar la sesión

Proporciona **ya sea** el operator token o su `jti`. Se requiere al menos uno.

<Tabs>
  <Tab title="Por token (preferido)">
    Pasa el mismo `patToken` que entregaste al widget. Se verifica contra el secreto de tu aplicación, por lo que un token que no es tuyo se rechaza de inmediato.

    Un token ya expirado igualmente es aceptado — terminar una sesión expirada es inofensivo, y significa que no tienes que rastrear la expiración antes de llamar.

    El propio `exp` del token también limita cuánto tiempo se recuerda la terminación, por lo que esta es la mejor opción cuando aún lo tienes.
  </Tab>

  <Tab title="Por jti">
    Úsalo cuando ya no tengas el token. El `jti` es el UUID v4 que generaste cuando firmaste el `patToken` — consulta [Set Up Your Server](/developers/setting-up-your-server).

    También se devuelve a tu URL de callback como el parámetro de consulta `fluz_jti`, para que puedas terminar una sesión desde un callback sin haber almacenado el token.

    Debido a que no hay un token del cual leer un `exp`, una terminación solo con `jti` se recuerda por un período fijo en lugar de exactamente por el tiempo que la sesión podría haberse usado.
  </Tab>
</Tabs>

Proporcionar ambos está permitido siempre que describan la misma sesión. El token prevalece, y el `jti` se trata como una afirmación sobre este — un `jti` que no coincida con el propio del token se rechaza en lugar de ignorarse silenciosamente, por lo que una confusión no puede terminar la sesión equivocada.

## Argumentos

* **`input`** (`TerminateWidgetSessionInput!`): identifica la sesión a terminar.

### Campos de TerminateWidgetSessionInput

| Field   | Type     | Description                                                                              | Required                        |
| :------ | :------- | :--------------------------------------------------------------------------------------- | :------------------------------ |
| `token` | `String` | El operator token (`patToken`) que entregaste al usuario para abrir el widget.           | Al menos uno de `token` o `jti` |
| `jti`   | `String` | El claim `jti` de ese token. Mismo valor entregado a tu URL de callback como `fluz_jti`. | Al menos uno de `token` o `jti` |

## Mutación de ejemplo

```graphql theme={null}
mutation {
  terminateWidgetSession(input: { jti: "11111111-1111-4111-8111-111111111111" }) {
    jti
    wasActive
    terminatedAt
  }
}
```

## Ejemplo con cURL

```curl theme={null}
curl -X POST \
  https://transactional-graph.staging.fluzapp.com/api/v1/graphql \
  -H 'Content-Type: application/json' \
  -H 'Authorization: Basic YOUR_API_KEY' \
  -d '{
    "query": "mutation { terminateWidgetSession(input: { jti: \"11111111-1111-4111-8111-111111111111\" }) { jti wasActive terminatedAt } }"
  }'
```

## Respuesta de ejemplo

```json theme={null}
{
  "data": {
    "terminateWidgetSession": {
      "jti": "11111111-1111-4111-8111-111111111111",
      "wasActive": true,
      "terminatedAt": "2026-09-01T14:32:07.412Z"
    }
  }
}
```

## Campos de la respuesta

| Field          | Type        | Description                                                                                                                                                                                                                                    |
| :------------- | :---------- | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `jti`          | `String!`   | El identificador de la sesión que fue terminada.                                                                                                                                                                                               |
| `wasActive`    | `Boolean!`  | `true` cuando la sesión tenía una reserva activa que esta llamada revocó — el usuario estaba en el widget o podía haberlo estado. `false` cuando no había nada activo que revocar. Solo informativo; la sesión se termina de cualquier manera. |
| `terminatedAt` | `DateTime!` | Cuándo se registró la terminación.                                                                                                                                                                                                             |

<Note>
  **`wasActive: false` es un éxito, no un fallo.** Es la respuesta normal cuando el usuario nunca abrió el widget — que también es el momento más seguro para cancelar. Terminar una sesión que nunca se abrió está completamente soportado y es la forma recomendada de abortar un pago que ya entregaste.
</Note>

## Cuando se rechaza la terminación

La terminación es idempotente — terminar una sesión ya terminada tiene éxito. Se rechaza en exactamente dos casos, cada uno significando que la cuestión del dinero ya está resuelta:

| Error                           | Code         | Status | Qué significa                                                                                                                                                          |
| :------------------------------ | :----------- | :----- | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `WidgetSessionInProgress`       | `WIDGET-006` | `409`  | El pago de la sesión se está ejecutando actualmente. Espera el resultado — no reintentes a ciegas. Recibirás un evento de finalización o de fallo de cualquier manera. |
| `WidgetSessionAlreadyCompleted` | `WIDGET-007` | `409`  | El pago ya se realizó. No queda nada por terminar.                                                                                                                     |

Otros errores que puedes ver:

| Error                      | Code         | Status | Causa                                                                                                                                                       |
| :------------------------- | :----------- | :----- | :---------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `MissingParameter`         | `WIDGET-001` | `400`  | No se proporcionó ni `token` ni `jti`, o el token no tiene claim `jti`.                                                                                     |
| `InvalidParameter`         | `WIDGET-002` | `400`  | El token no verifica contra el secreto de tu aplicación, no fue emitido para esta aplicación, o el `jti` proporcionado no coincide con el propio del token. |
| `MisconfiguredApplication` | `WIDGET-003` | `400`  | La aplicación no está configurada para abrir sesiones del widget.                                                                                           |

## Lo que ve el usuario

La terminación entra en vigor en la **próxima navegación o actualización** del usuario dentro del widget. No cierra una pantalla que ya está renderizada.

Cuando vuelva a moverse, verá un mensaje de "Sesión finalizada" que nombra tu aplicación y le indica cerrar la ventana e iniciar de nuevo desde tu producto. Si llega hasta confirmar un pago, esa confirmación se rechaza con el mismo mensaje, y el pago se rechaza del lado del servidor con `WidgetSessionTerminated` (`WIDGET-005`, `410`).

<Warning>
  Terminar **no** detiene por sí mismo un pago que ya comenzó a ejecutarse — ese caso devuelve `409` en su lugar, y debes esperar el evento de finalización o de fallo en lugar de asumir que el dinero está detenido.
</Warning>

## Cuánto tiempo se recuerda una terminación

Una sesión terminada se rechaza durante tanto tiempo como de otro modo podría haberse usado:

* **Terminada por token** — hasta el propio `exp` del token, y nunca menos de una hora.
* **Terminada solo por `jti`** — por 30 días. Nada limita por cuánto tiempo puedes firmar un operator token, así que sin un `exp` que leer la terminación se conserva muy por encima de cualquier vida útil plausible de la sesión.

Después de esa ventana, el registro se descarta. En la práctica, el operator token ya habrá expirado hace tiempo, por lo que la sesión no puede usarse de todos modos.

## Próximos pasos

<CardGroup cols={2}>
  <Card title="Configura tu servidor" icon="server" href="/developers/setting-up-your-server">
    Genera el `patToken` y el `jti` que toma esta mutación.
  </Card>

  <Card title="Integra el widget" icon="code" href="/developers/adding-the-js-widget-to-your-page">
    Etiqueta de script, llamada de init, vinculación del botón.
  </Card>

  <Card title="Resumen de Widgets embebidos" icon="book-copy" href="/developers/widgets">
    Cómo encajan las sesiones del widget, grants de OAuth y tokens de transacción preaprobados.
  </Card>

  <Card title="Idempotencia" icon="repeat" href="/docs/idempotency-requests">
    Por qué cada llamada que mueve dinero necesita un `jti` único.
  </Card>
</CardGroup>
