Open a terminal session
const url = 'https://terminal.api.example.com/v1/terminal_sessions';const options = { method: 'POST', headers: {'Content-Type': 'application/json'}, body: '{"client_session_token":"shift-2026-10-08-0001"}'};
try { const response = await fetch(url, options); const data = await response.json(); console.log(data);} catch (error) { console.error(error);}curl --request POST \ --url https://terminal.api.example.com/v1/terminal_sessions \ --header 'Content-Type: application/json' \ --data '{ "client_session_token": "shift-2026-10-08-0001" }'Called by a paired terminal, over mutual TLS with its certificate, when a cashier starts work.
The merchant and store are the terminal’s assignment, never the body’s. A terminal has one
session at a time: while one is active or recoverable_interrupted, opening another is
refused.
The client_session_token makes a retry safe: the same token answers the same session, as it
stands now, with 201 again, without checking the clock: read its status and
recovery_deadline, and resume it or open a new session as the guide says. A token first sent
with an earlier certificate is refused with 409. Use a new token for each session. See
Terminal sessions.
Authorizations
Section titled “Authorizations”Request Bodyrequired
Section titled “Request Bodyrequired”object
The terminal’s token for this session, new for each session. Not blank.
Responses
Section titled “Responses”The session, open, and what the terminal needs to work. Sent with Cache-Control: no-store.
The session, as opening it answers, with what the terminal needs to start work.
object
The session’s id, used in the path of its heartbeat, resume and close.
Always true. A terminal is a live device; there are no test terminals.
The terminal that opened it, the only one that can use it.
active while it takes heartbeats; recoverable_interrupted once it missed them, until it is
resumed or its recovery_deadline passes; expired and closed are final.
When it was opened, as a Unix timestamp.
The last time the terminal showed it was alive on it, by opening, a heartbeat or a resume, as a Unix timestamp.
When it was interrupted for missing its heartbeats, while it is recoverable_interrupted.
The last moment it can be resumed, while it is recoverable_interrupted.
When it ends, however well it heartbeats, as a Unix timestamp.
When it expired, once it is expired.
When it was closed, once it is closed.
How often to send a heartbeat, in seconds. The platform sets it.
The terminal IDs bound to the terminal now, one for each card route it has one for.
object
The store the terminal is assigned to, as the operations team labelled it. Empty when none was given.
The newest parameter profile a rollout completed for this terminal, or null until one has.
object
The profile’s parameters, names and values, as the operations team saved them.
object
Example
{ "id": "6d0f3b8e-2c4a-4f7e-9b1d-8a5c3e7f2b10", "object": "terminal_session", "livemode": true, "terminal_id": "3f6c2a9e-8b41-4d7a-9e25-0c1b7d4f8a63", "status": "active", "opened_at": 1791000000, "last_heartbeat_at": 1791000000, "interrupted_at": null, "recovery_deadline": null, "expires_at": 1791043200, "expired_at": null, "closed_at": null, "heartbeat_interval_seconds": 30, "tids": [ { "route": "card_processor", "tid": "T0001" }, { "route": "domestic_debit", "tid": "T0002" } ], "store_label": "Front counter", "parameter_profile": null}validation_failure with invalid_parameter and param client_session_token: the token is missing, not a string, blank or longer than 64 characters. Also the codes any /v1 call can get for a body that is not JSON.
object
object
A stable name for this refusal. Branch on this, never on message.
For the developer reading a log. May be reworded.
The field or parameter at fault, when there is one.
Example
{ "error": { "type": "validation_failure" }}authentication_failure with terminal_credential_refused: the certificate does not count, or the terminal is suspended or retired. See Pairing a terminal.
object
object
A stable name for this refusal. Branch on this, never on message.
For the developer reading a log. May be reworded.
The field or parameter at fault, when there is one.
Example
{ "error": { "type": "validation_failure" }}conflict with session_already_open, for either of two reasons. This terminal already has a session that is active or recoverable_interrupted: resume or close it first (a session that time has already ended does not count). Or this client_session_token was first sent with an earlier certificate, before a renewal: it is refused even when that session is now closed or expired. Resume the session it opened if it is still live, or open with a new token.
object
object
A stable name for this refusal. Branch on this, never on message.
For the developer reading a log. May be reworded.
The field or parameter at fault, when there is one.
Example
{ "error": { "type": "conflict", "code": "session_already_open", "message": "This terminal already has a session open. Resume or close it first.", "param": null, "request_id": "req_9c1e5a7b3d2f" }}policy_rejection: no session can be opened now. code says why:
code |
Meaning |
|---|---|
merchant_not_active |
The terminal’s merchant is suspended or closed. |
tenant_not_active |
The merchant’s tenant is suspended or closed. |
terminal_not_assigned |
The terminal is not assigned to a store. |
terminal_credential_refused |
The terminal’s credential stopped counting while the session was being opened. Treat it as the 401. |
object
object
A stable name for this refusal. Branch on this, never on message.
For the developer reading a log. May be reworded.
The field or parameter at fault, when there is one.
Example
{ "error": { "type": "validation_failure" }}dependency_failure with service_unavailable: the platform did not answer, or failed part-way. Whether the session was opened is not known. Retry the same request with the same client_session_token: a session that was opened is answered, not opened twice. Never make a new token for the retry.
object
object
A stable name for this refusal. Branch on this, never on message.
For the developer reading a log. May be reworded.
The field or parameter at fault, when there is one.
Example
{ "error": { "type": "validation_failure" }}