> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://docs.runpayments.io/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs.runpayments.io/_mcp/server.

# Interactions & Status

`read-card` and `charge-card` are **queue-based**: they return `202 Accepted` immediately with an `interaction_id`, and the outcome is retrieved later.

## Retrieving the result

* **Polling:** [`GET /api/terminal/{device_id}/read-card/{interaction_id}`](/reference/terminal-api/card-read/get-read-card-status) or [`GET /api/terminal/{device_id}/charge-card/{interaction_id}`](/reference/terminal-api/charge-card/get-charge-card-status)
* **WebSocket:** subscribe to `terminal_job:{interaction_id}` for push updates (see [Real-time updates](#real-time-updates-websocket)).

## Interaction status values

| Status      | Meaning                                                                                                                                                                        |
| ----------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `pending`   | In progress. `result` is `null`. Only pending interactions can be cancelled.                                                                                                   |
| `succeeded` | The workflow completed. **For `charge-card`, this includes declines** — see [Handling declines](/docs/guides/payments/card-present/unified-charge-workflow#handling-declines). |
| `failed`    | The workflow could not complete (e.g., the terminal was unavailable).                                                                                                          |
| `cancelled` | Cancelled via the cancel endpoint or at the device.                                                                                                                            |

> **Interactions expire after 3 minutes**
>
> After the TTL, the status endpoint returns `404` — the same response as an interaction that never existed or a wrong `device_id`. Retrieve results promptly and persist anything you need.

## Cancelling

[`DELETE /api/terminal/{device_id}/cancel/{interaction_id}`](/reference/terminal-api/card-read/cancel-read-card) cancels a pending `read-card` interaction on the terminal. It returns `200` with no body on success, or `422` if the interaction is no longer pending.

> **charge-card interactions can't be cancelled through the API**
>
> Charging is a processing flow whose outcome depends on timing at the terminal and processor. Once a `charge-card` interaction starts, wait for its final status and check `result`.

## Sessions

`ping`, `read-card`, `charge-card`, and `print-receipt` **auto-connect** a terminal session if none is active, so calling `connect` first is optional. Use `connect` to pre-warm a terminal or force a reconnect (`force: true`); use `disconnect` to release the device.

## Real-time updates (WebSocket)

By default, interaction status is retrieved by polling the status endpoint. For applications that want instant updates without polling, the Terminal API also supports an optional WebSocket connection that pushes status changes as they happen. This works for both `read-card` and `charge-card` interactions.

### Why a separate token?

This flow uses its own token rather than your access token. Browser and native WebSocket clients can only pass credentials via the connection URL (query string), not request headers, and putting a long-lived access token into a URL risks it being captured in server logs, proxy logs, or browser history.

To avoid that risk, the WebSocket flow uses a **short-lived, single-use token** that is only valid for establishing one socket connection. It expires after 60 seconds or on first use, whichever comes first, and cannot be reused for a second connection or for REST calls.

### How it works

#### Request a WebSocket token

[`POST /api/ws-token`](/reference/terminal-api/authentication-web-socket/generate-ws-token). Returns a single-use `token` valid for 60 seconds.

#### Open the WebSocket connection

Connect to `wss://javelin.runpayments.io/cable?token={token}`. Once used, the token is invalidated; if the connection drops, request a new token before reconnecting.

#### Start the interaction

`POST /api/terminal/{device_id}/read-card` or `/charge-card`. Returns an `interaction_id`.

#### Subscribe to the channel

`terminal_job:{interaction_id}`. The channel is scoped to that single interaction.

#### Receive status updates

Events are pushed as the interaction moves through `pending` → `succeeded` / `failed` / `cancelled`. The pushed payload matches the polling response (`interaction_id`, `status`, `result`, `updated_at`).

### Example

```
POST /api/ws-token
→ { "token": "a1b2c3d4-e5f6-7890-abcd-ef1234567890" }

POST /api/terminal/{device_id}/charge-card
→ { "interaction_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6" }

Connect:   wss://javelin.runpayments.io/cable?token=a1b2c3d4-e5f6-7890-abcd-ef1234567890
Subscribe: terminal_job:3fa85f64-5717-4562-b3fc-2c963f66afa6

← { "status": "pending", ... }
← { "status": "succeeded", "result": { ... } }
```

### Other things to keep in mind

* **Tokens are single-use.** Request a new token for every new WebSocket connection, including reconnects.
* **Tokens expire in 60 seconds.** Request the token immediately before connecting, not in advance.
* **Channels are per-interaction.** You need the `interaction_id` before subscribing, so queue the interaction first.
* **WebSocket connections are multi-interaction.** Once open, a connection isn't single-use — you don't need a new connection or a new token to handle another interaction.
* **This does not start an interaction.** The WebSocket only delivers updates for an interaction already in progress.
* **Status alone doesn't mean approved.** A declined `charge-card` still arrives as `succeeded` — see [Handling declines](/docs/guides/payments/card-present/unified-charge-workflow#handling-declines).