NewInstance Documentation
View as Markdown

Session tokens (REST API)

The REST API your backend calls to create, inspect and invalidate chat sessions.

1. Your backend  -> POST /api/v1/chat/sessions        (identity + lifetime)
2. Your backend  <- signed JWT + session record
3. Your backend  -> return the token with your own session
4. Your frontend -> hand the token to the chat SDK
5. Chat SDK      -> the customer chats, already identified
6. Before expiry -> DELETE the session, POST a new one, pass it to setUserToken
7. On sign-out   -> DELETE /api/v1/chat/sessions?customerId=...

Endpointslink

MethodPathPurpose
POST/api/v1/chat/sessionsCreate a session and get its token
GET/api/v1/chat/sessions?customerId=The customer's live session, if any
GET/api/v1/chat/sessions/{sessionId}Has this session been invalidated?
DELETE/api/v1/chat/sessions/{sessionId}?customerId=Invalidate that session
DELETE/api/v1/chat/sessions?customerId=Invalidate whatever session the customer holds

Every endpoint requires a secret-bearing API key (x-api-key: keyId:secret) and is server-to-server only. A bare key ID is refused.

Lifetime is yours to chooselink

expiresInSeconds accepts 60 to 86400 (24 hours), defaulting to 3600. Want six-hour sessions? Send 21600. Values above the maximum are refused rather than silently clamped, so you always know what you got.

One live session per customerlink

A customer holds at most one session. POST returns 409 with the offending session while one is still valid; mint again once it expires or after you revoke it. This is deliberate: it keeps one identity from accumulating parallel credentials, and it means "the customer's session" is always a single, knowable thing.

How little is storedlink

The token is a JWT, and it is the session: the customer id, name, email, phone and metadata are all signed into it. Verifying the signature yields the whole identity, so the platform keeps no copy of any of it. Duplicating it server side would only create state that could drift from the claims.

Redis holds two things, and nothing else:

KeyWritten whenLives for
chat:revoked:{org}:{jti}only when you invalidate a session earlythe token's remaining lifetime
chat:live:{org}:{customerId}on every mint, to enforce the one-session rulethe token's lifetime

A session that lives out its natural life is never written to the denylist at all. Both keys carry the token's own TTL, so the store empties itself and nothing has to be swept.

A denylist rather than an allowlist is deliberate: if Redis is briefly unreachable, an allowlist would reject every token and take chat down, while a denylist degrades to "an early revocation may be missed until Redis returns", bounded by the lifetime you chose. Short lifetimes make that window small, which is another reason to prefer them.

The token itself is never stored either. If you lose it, revoke the session and mint another.

Get a customer's live session

GET/api/v1/chat/sessions

Returns the customer's live session, if they hold one.

Call it before minting to decide whether to reuse the token you have, wait, or revoke and re-mint. A customer can hold at most one session, so sessions is a list of zero or one.

Expired and revoked sessions are simply absent: the record exists only while the session is usable.

Authorization

x-api-keyAPI key · headerrequired

Parameters

customerIdquery · stringdefault:

Required. Your id for the customer to look up, the same customerId you minted the session with.

Responses

200Live session found
401Invalid or missing API key
curl -X GET 'https://api.newinstance.cloud/api/v1/chat/sessions?customerId=usr_123' \
  -H 'x-api-key: YOUR_API_KEY'
Response
{
  "sessions": [
    {
      "sessionId": "b3f1c2d4e5a67890b1c2d3e4f5a6b7c8",
      "customerId": "usr_123",
      "status": "active",
      "expiresAt": "2026-08-26T16:00:00.000Z",
      "expiresInSeconds": 21600
    }
  ]
}

Create a chat session

POST/api/v1/chat/sessions

Mints a chat session for one of your customers, from YOUR backend.

Call this wherever your app establishes a session (typically right after sign-in) and return the token to your frontend alongside your own session token. The frontend hands that one string to the chat SDK and passes nothing else.

Bodylink

FieldTypeRequiredNotes
customerIdstringYesYour stable id for this customer. Becomes the verified customer id. Max 200 characters.
customerNamestringYesName on the conversation and on every message they send. Max 200.
customerEmailstringNoAlso satisfies the merchant Require customer email setting, so the visitor is never asked. Max 320.
customerPhonestringNoShown to agents. Max 40.
metadataobjectNoExtra agent-visible context. At most 20 keys, 64-character keys, 500-character values, 4096 bytes total. Nested objects and arrays are rejected rather than flattened.
expiresInSecondsintegerNoYou choose the lifetime: 60 to 86400 seconds (24 hours max). Defaults to 3600. The example asks for 6 hours.

One live session per customerlink

A customer may hold one session at a time. While theirs is still valid this returns 409 with the session that is in the way. Once it expires, or you revoke it, a new one can be minted. That keeps a single identity from accumulating parallel credentials.

The 409 body carries the existing session, so you can decide whether to keep using the token you already have or revoke and re-mint.

What comes backlink

A signed JWT, and a session summary that is only an id, its owner and its expiry.

Everything about the customer is inside the token, signed. The platform keeps no copy: it would be duplicated state that could drift from the claims, and the JWT already answers the question. If you need the name, email, phone or metadata back, decode the token.

The token is never stored either. If you lose it, revoke the session and mint another.

Authorization

x-api-keyAPI key · headerrequired

Request body

application/json
{
  "customerId": "usr_123",
  "customerName": "Ada Lovelace",
  "customerEmail": "ada@example.com",
  "customerPhone": "+44 20 7946 0958",
  "metadata": {
    "plan": "enterprise",
    "accountNumber": "AC-4471"
  },
  "expiresInSeconds": 21600
}

Responses

201Session created
400Validation error
401Invalid or missing API key
409Customer already has a live session
curl -X POST 'https://api.newinstance.cloud/api/v1/chat/sessions' \
  -H 'x-api-key: YOUR_API_KEY' \
  -H 'Content-Type: application/json' \
  --data-raw '{
  "customerId": "usr_123",
  "customerName": "Ada Lovelace",
  "customerEmail": "ada@example.com",
  "customerPhone": "+44 20 7946 0958",
  "metadata": {
    "plan": "enterprise",
    "accountNumber": "AC-4471"
  },
  "expiresInSeconds": 21600
}'
Response
{
  "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJqdGkiOiJiM2YxYzJkNGU1YTY3ODkwIiwic3ViIjoidXNyXzEyMyJ9.7mK2_x1s0KQ",
  "expiresAt": "2026-08-26T16:00:00.000Z",
  "expiresInSeconds": 21600,
  "session": {
    "sessionId": "b3f1c2d4e5a67890b1c2d3e4f5a6b7c8",
    "customerId": "usr_123",
    "status": "active",
    "expiresAt": "2026-08-26T16:00:00.000Z",
    "expiresInSeconds": 21600
  }
}

Invalidate a customer's session

DELETE/api/v1/chat/sessions

Invalidates whatever session a customer holds, for sign-out when you did not keep the session id.

Idempotent: when the customer holds no session it still returns 200 with revoked: false, because "this customer has no live chat session" is the desired end state either way. Wire it into your own sign-out and you never have to track session ids.

Authorization

x-api-keyAPI key · headerrequired

Parameters

customerIdquery · stringdefault:

Required. Your id for the customer to sign out of chat.

Responses

200Session invalidated
401Invalid or missing API key
curl -X DELETE 'https://api.newinstance.cloud/api/v1/chat/sessions?customerId=usr_123' \
  -H 'x-api-key: YOUR_API_KEY'
Response
{
  "session": {
    "sessionId": "b3f1c2d4e5a67890b1c2d3e4f5a6b7c8",
    "customerId": "usr_123",
    "status": "active",
    "expiresAt": "2026-08-26T16:00:00.000Z",
    "expiresInSeconds": 21600
  },
  "revoked": true
}

Get one session

GET/api/v1/chat/sessions/{chatSessionId}

Reports whether this session has been invalidated.

chatSessionId in the path is the session.sessionId returned by Create a chat session; Postman stores it after that request runs.

Invalidation is the only thing a session id can answer, and the only thing worth asking. The token is a JWT: it carries its own exp and the customer's identity, so decode it for those. What the token cannot tell you is whether someone revoked it early, which is exactly what this reports.

revoked: false means no early invalidation was recorded. It does not mean the token is unexpired, because expiry is the token's business, not the platform's.

Authorization

x-api-keyAPI key · headerrequired

Parameters

chatSessionIdpath · stringrequireddefault:

Responses

200Not revoked
401Invalid or missing API key
curl -X GET 'https://api.newinstance.cloud/api/v1/chat/sessions/{chatSessionId}' \
  -H 'x-api-key: YOUR_API_KEY'
Response
{
  "sessionId": "b3f1c2d4e5a67890b1c2d3e4f5a6b7c8",
  "revoked": false
}

Invalidate a session

DELETE/api/v1/chat/sessions/{chatSessionId}

Invalidates a session before it expires.

chatSessionId in the path is the session.sessionId returned by Create a chat session.

The token stops being accepted on the next request: its signature is still valid and it has not expired, but the session is on the denylist. There is no propagation delay and no cache to wait out.

customerId is required so the customer's slot is freed as well as the token denied. Without it the token would die but the customer would stay blocked from a new session until natural expiry. You always have it: it is what you minted the session for.

Idempotent, so a retried sign-out is safe.

Authorization

x-api-keyAPI key · headerrequired

Parameters

customerIdquery · stringdefault:

Required. The customer this session belongs to, so their one-session slot is freed too.

chatSessionIdpath · stringrequireddefault:

Responses

200Session invalidated
401Invalid or missing API key
curl -X DELETE 'https://api.newinstance.cloud/api/v1/chat/sessions/{chatSessionId}?customerId=usr_123' \
  -H 'x-api-key: YOUR_API_KEY'
Response
{
  "sessionId": "b3f1c2d4e5a67890b1c2d3e4f5a6b7c8",
  "session": {
    "sessionId": "b3f1c2d4e5a67890b1c2d3e4f5a6b7c8",
    "customerId": "usr_123",
    "status": "active",
    "expiresAt": "2026-08-26T16:00:00.000Z",
    "expiresInSeconds": 21600
  },
  "revoked": true
}