> ## 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.

# Terminate a Widget Session

> Cancel a payment you have already handed off to the widget, so the user can no longer complete it.

You generate a `patToken`, hand it to the widget, and the user walks away — or your own system cancels the order a minute later. The token stays valid until whatever `exp` you signed it with, so without a way to revoke it the user can come back later and complete a payment you no longer want.

`terminateWidgetSession` ends the session server-side. The user is refused the next time they move inside the widget, and any payout attempt against that session is rejected.

<Info>
  **Prerequisites:** your application's API Key for Basic auth, and either the operator token you issued or its `jti`.
</Info>

## Authentication

This mutation is authenticated with your **application's** credentials, not a user access token — the same `Basic` header you already use for [`generateUserAccessToken`](/get-started/api-credentials):

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

Send the API Key from the Developer Console verbatim; it is already base64-encoded and decodes to the `app_id:apiSecret` pair the server checks. Use the key for the same application whose `apiSecret` signed the operator token.

<Warning>
  Staging and live are separate applications with separate credentials. A key from the wrong environment returns `401` with the same message as a malformed one — see [If the token request returns 401](/get-started/api-credentials) for the full checklist.
</Warning>

You can only terminate sessions belonging to the application you authenticate as. A `jti` issued by a different application is not affected by your call — you will get a successful response with `wasActive: false`, and that application's session keeps running.

Basic auth is not available to applications with `PERSONAL` status.

## Identifying the session

Supply **either** the operator token or its `jti`. At least one is required.

<Tabs>
  <Tab title="By token (preferred)">
    Pass the same `patToken` you handed to the widget. It is verified against your application's secret, so a token that is not yours is rejected outright.

    An already-expired token is still accepted — terminating an expired session is harmless, and it means you do not have to track expiry yourself before calling.

    The token's own `exp` also bounds how long the termination is remembered, which is why this is the better option when you still hold it.
  </Tab>

  <Tab title="By jti">
    Use this when you no longer have the token. The `jti` is the UUID v4 you generated when you signed the `patToken` — see [Set Up Your Server](/developers/setting-up-your-server).

    It is also handed back to your callback URL as the `fluz_jti` query parameter, so you can terminate a session from a callback without having stored the token.

    Because there is no token to read an `exp` from, a `jti`-only termination is remembered for a fixed period rather than for exactly as long as the session could have been used.
  </Tab>
</Tabs>

Supplying both is allowed as long as they describe the same session. The token wins, and the `jti` is treated as an assertion about it — a `jti` that disagrees with the token's own is rejected rather than silently ignored, so a mix-up cannot terminate the wrong session.

## Arguments

* **`input`** (`TerminateWidgetSessionInput!`): identifies the session to terminate.

### TerminateWidgetSessionInput fields

| Field   | Type     | Description                                                                             | Required                         |
| :------ | :------- | :-------------------------------------------------------------------------------------- | :------------------------------- |
| `token` | `String` | The operator token (`patToken`) you handed to the user to open the widget.              | At least one of `token` or `jti` |
| `jti`   | `String` | The `jti` claim of that token. Same value delivered to your callback URL as `fluz_jti`. | At least one of `token` or `jti` |

## Sample mutation

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

## cURL example

```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 } }"
  }'
```

## Sample response

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

## Response fields

| Field          | Type        | Description                                                                                                                                                                                                                      |
| :------------- | :---------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `jti`          | `String!`   | The session identifier that was terminated.                                                                                                                                                                                      |
| `wasActive`    | `Boolean!`  | `true` when the session had a live reservation that this call revoked — the user was in the widget, or could have been. `false` when there was nothing live to revoke. Informational only; the session is terminated either way. |
| `terminatedAt` | `DateTime!` | When the termination was recorded.                                                                                                                                                                                               |

<Note>
  **`wasActive: false` is a success, not a failure.** It is the normal answer when the user never opened the widget — which is also the safest moment to cancel. Terminating a session that was never opened is fully supported and is the recommended way to call off a payment you have already handed over.
</Note>

## When termination is refused

Termination is idempotent — terminating an already-terminated session succeeds. It is refused in exactly two cases, each meaning the money question is already settled:

| Error                           | Code         | Status | What it means                                                                                                                                        |
| :------------------------------ | :----------- | :----- | :--------------------------------------------------------------------------------------------------------------------------------------------------- |
| `WidgetSessionInProgress`       | `WIDGET-006` | `409`  | The session's payout is currently executing. Wait for the outcome — do not retry blindly. You will receive a completion or failure event either way. |
| `WidgetSessionAlreadyCompleted` | `WIDGET-007` | `409`  | The payment already went through. There is nothing left to terminate.                                                                                |

Other errors you may see:

| Error                      | Code         | Status | Cause                                                                                                                                                   |
| :------------------------- | :----------- | :----- | :------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `MissingParameter`         | `WIDGET-001` | `400`  | Neither `token` nor `jti` supplied, or the token has no `jti` claim.                                                                                    |
| `InvalidParameter`         | `WIDGET-002` | `400`  | The token does not verify against your application's secret, was not issued for this application, or the supplied `jti` disagrees with the token's own. |
| `MisconfiguredApplication` | `WIDGET-003` | `400`  | The application is not configured to open widget sessions.                                                                                              |

## What the user sees

Termination takes effect on the user's **next navigation or refresh** inside the widget. It does not close a screen that is already rendered.

When they next move, they are shown a "Session ended" message naming your application and telling them to close the window and start again from your product. If they get as far as confirming a payment, that confirmation is refused with the same message, and the payout is rejected server-side with `WidgetSessionTerminated` (`WIDGET-005`, `410`).

<Warning>
  Terminating does **not** by itself stop a payout that has already started executing — that case returns `409` instead, and you should wait for the completion or failure event rather than assuming the money is stopped.
</Warning>

## How long a termination is remembered

A terminated session is refused for as long as it could otherwise have been used:

* **Terminated by token** — until the token's own `exp`, and never less than one hour.
* **Terminated by `jti` alone** — for 30 days. Nothing bounds how long you may sign an operator token for, so without an `exp` to read the termination is kept well past any plausible session lifetime.

After that window the record is discarded. In practice the operator token has long since expired, so the session cannot be used regardless.

## Next steps

<CardGroup cols={2}>
  <Card title="Set up your server" icon="server" href="/developers/setting-up-your-server">
    Generate the `patToken` and the `jti` this mutation takes.
  </Card>

  <Card title="Embed the widget" icon="code" href="/developers/adding-the-js-widget-to-your-page">
    Script tag, init call, button binding.
  </Card>

  <Card title="Embedded Widgets overview" icon="book-copy" href="/developers/widgets">
    How widget sessions, OAuth grants, and pre-approved transaction tokens fit together.
  </Card>

  <Card title="Idempotency" icon="repeat" href="/docs/idempotency-requests">
    Why every money-moving call needs a unique `jti`.
  </Card>
</CardGroup>
