Skip to content

Open a terminal session

POST
/v1/terminal_sessions
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.

Media typeapplication/json
object
client_session_token
required

The terminal’s token for this session, new for each session. Not blank.

string
>= 1 characters <= 64 characters /\S/

The session, open, and what the terminal needs to work. Sent with Cache-Control: no-store.

Media typeapplication/json

The session, as opening it answers, with what the terminal needs to start work.

object
id
required

The session’s id, used in the path of its heartbeat, resume and close.

string
object
required
string
Allowed value: terminal_session
livemode
required

Always true. A terminal is a live device; there are no test terminals.

boolean
terminal_id
required

The terminal that opened it, the only one that can use it.

string
status
required

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.

string
Allowed values: active recoverable_interrupted expired closed
opened_at
required

When it was opened, as a Unix timestamp.

integer
last_heartbeat_at
required

The last time the terminal showed it was alive on it, by opening, a heartbeat or a resume, as a Unix timestamp.

integer
interrupted_at
required

When it was interrupted for missing its heartbeats, while it is recoverable_interrupted.

integer | null
recovery_deadline
required

The last moment it can be resumed, while it is recoverable_interrupted.

integer | null
expires_at
required

When it ends, however well it heartbeats, as a Unix timestamp.

integer
expired_at
required

When it expired, once it is expired.

integer | null
closed_at
required

When it was closed, once it is closed.

integer | null
heartbeat_interval_seconds
required

How often to send a heartbeat, in seconds. The platform sets it.

integer
tids
required

The terminal IDs bound to the terminal now, one for each card route it has one for.

Array<object>
object
route
required
string
tid
required
string
store_label
required

The store the terminal is assigned to, as the operations team labelled it. Empty when none was given.

string
parameter_profile
required

The newest parameter profile a rollout completed for this terminal, or null until one has.

object
name
required
string
version
required
integer
parameters
required

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.

Media typeapplication/json
object
error
required
object
type
required
string
Allowed values: validation_failure authentication_failure authorization_failure not_found conflict timeout_or_in_progress policy_rejection invariant_violation rate_limited dependency_failure
code
required

A stable name for this refusal. Branch on this, never on message.

string
message
required

For the developer reading a log. May be reworded.

string
param
required

The field or parameter at fault, when there is one.

string | null
request_id
required
string | null
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.

Media typeapplication/json
object
error
required
object
type
required
string
Allowed values: validation_failure authentication_failure authorization_failure not_found conflict timeout_or_in_progress policy_rejection invariant_violation rate_limited dependency_failure
code
required

A stable name for this refusal. Branch on this, never on message.

string
message
required

For the developer reading a log. May be reworded.

string
param
required

The field or parameter at fault, when there is one.

string | null
request_id
required
string | null
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.

Media typeapplication/json
object
error
required
object
type
required
string
Allowed values: validation_failure authentication_failure authorization_failure not_found conflict timeout_or_in_progress policy_rejection invariant_violation rate_limited dependency_failure
code
required

A stable name for this refusal. Branch on this, never on message.

string
message
required

For the developer reading a log. May be reworded.

string
param
required

The field or parameter at fault, when there is one.

string | null
request_id
required
string | null
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.
Media typeapplication/json
object
error
required
object
type
required
string
Allowed values: validation_failure authentication_failure authorization_failure not_found conflict timeout_or_in_progress policy_rejection invariant_violation rate_limited dependency_failure
code
required

A stable name for this refusal. Branch on this, never on message.

string
message
required

For the developer reading a log. May be reworded.

string
param
required

The field or parameter at fault, when there is one.

string | null
request_id
required
string | null
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.

Media typeapplication/json
object
error
required
object
type
required
string
Allowed values: validation_failure authentication_failure authorization_failure not_found conflict timeout_or_in_progress policy_rejection invariant_violation rate_limited dependency_failure
code
required

A stable name for this refusal. Branch on this, never on message.

string
message
required

For the developer reading a log. May be reworded.

string
param
required

The field or parameter at fault, when there is one.

string | null
request_id
required
string | null
Example
{
"error": {
"type": "validation_failure"
}
}