Skip to main content

Webchat Sessions API

Overview

The Webchat Sessions API allows your server to create customer webchat sessions and refresh session tokens on behalf of your users. This is a server-to-server API designed for backend integrations where your application manages webchat sessions programmatically — typically when you don't want the standard browser-side flow (which stores session data in localStorage) and instead want your own backend to act as the system of record.

Read this before integrating

The identity anchor for a returning user's conversation history is user.id. Sessions expire after 1 hour and the underlying session record is then deleted; what survives across sessions is the conversation, which is keyed on user.id.

To get the "reload the page, see prior chat history" behavior, you must pass a stable user.id on every call to POST /external/sessions — ideally your own internal user ID. See Preserving conversation history across sessions below.

Prerequisites

To use the APIs, you need to have a token. Tokens can be generated by an admin at the setting section in Filum CX platform. Ensure you have the necessary permissions to access the admin settings for token generation.

APIs

Access the APIs via the endpoint: https://webchat-v2.filum.ai/

POST /external/sessions

Summary

Create a webchat session for a customer.

Resolution order on every call:

  1. Active session match — if the user has a session that hasn't expired yet, it's reused. Match is by user.id, user.phone, or user.email.
  2. Existing conversation match — if no active session exists, the server looks up a prior conversation by user.id only (phone/email are not used here). If found, a new session is created and attached to that conversation, so message history is preserved.
  3. New conversation — if no prior conversation is found for that user.id, a brand-new conversation is created (the user will see an empty chat).

This is why a stable, consistent user.id is the only reliable way to preserve conversation history across page reloads, browser changes, and the 1-hour session TTL.

Header Parameters

NameDescriptionRequiredSchema
authorizationThe authorization token to validate the request. The value should be in the format Bearer <your_api_token>Yesstring
organization-idThe unique identifier of your organizationYesstring
auth-typeThe type of authorization used for the request. Must be tokenYesstring
content-typeMust be application/jsonYesstring

Request Body

FieldType/FormatRequiredDescription
organizationIdstringYesThe unique identifier of the organization
installedSourceIdintegerYesThe ID of the installed source (webchat channel)
userobjectNoInformation about the customer
user.idstringNo*The unique identifier of the customer in your system. Strongly recommended. If omitted, the server generates a random Webchat-<uuid> and returns it as userId in the response — you then become responsible for storing it and echoing it back as user.id on subsequent calls, otherwise the user will get a fresh empty conversation on every reload. See Preserving conversation history across sessions.
user.namestringNoThe name of the customer
user.emailstringNoThe email of the customer
user.phonestringNoThe phone number of the customer

Request samples

{
"organizationId": "org_12345",
"installedSourceId": 1,
"user": {
"id": "customer_abc123",
"name": "John Doe",
"email": "john.doe@example.com",
"phone": "+84901234567"
}
}

Responses

CodeDescriptionContent type
201Successful Responseapplication/json
401Unauthorizedapplication/json
422Validation Errorapplication/json
429Too Many Requestsapplication/json

201 Successful Response

FieldType/FormatRequiredDescription
userIdstringYesThe user ID for the session (provided or auto-generated)
sessionIdstringYesThe unique identifier of the session
sessionTokenstringYesA JWT token for the session (expires in 1 hour)
sessionTokenExpirationintegerYesThe expiration timestamp of the session token (Unix epoch in seconds)
websocketUrlstringYesThe WebSocket URL for real-time messaging
conversationIdstringYesThe unique identifier of the conversation

Response samples

{
"userId": "customer_abc123",
"sessionId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"sessionToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"sessionTokenExpiration": 1705315800,
"websocketUrl": "wss://webchat-ws.filum.ai/a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"conversationId": "507f1f77bcf86cd799439011"
}

POST /external/sessions/refresh

Summary

Refresh an existing session token. This extends the session expiration by 1 hour and returns a new JWT token. Use this to keep a session alive without creating a new one.

Refresh works only while the session is still alive

Sessions expire 1 hour after they were last created or refreshed, and the session record is deleted shortly after. Once that happens, this endpoint returns 404 Session not found and cannot be used to recover the user's chat. To restore the user's prior conversation after that point, you must call POST /external/sessions again with the same user.id you originally used — that is what re-attaches the new session to the existing conversation. Storing only sessionId in your middleware is not enough.

Header Parameters

NameDescriptionRequiredSchema
authorizationThe authorization token to validate the request. The value should be in the format Bearer <your_api_token>Yesstring
organization-idThe unique identifier of your organizationYesstring
auth-typeThe type of authorization used for the request. Must be tokenYesstring
content-typeMust be application/jsonYesstring

Request Body

FieldType/FormatRequiredDescription
sessionIdstringYesThe unique identifier of the session to refresh
Don't store only sessionId in your backend

Although this endpoint accepts only sessionId, that is not enough state to keep around for a returning user. The moment this endpoint returns 404 Session not found (which it will, 1 hour after the last refresh), your only way back to the user's chat history is to call POST /external/sessions with the same user.id you used originally.

For every webchat user, your middleware should persist at minimum:

  • userId (from the create-session response) — or your own internal user ID if you passed it as user.id. This is the identity anchor; losing it loses the conversation.
  • sessionId — only useful while the session is still alive.

Do not treat sessionId as a long-lived handle. Treat user.id as the long-lived handle and sessionId as a short-lived (≤1 hour) token derived from it.

Request samples

What your backend must have persisted for the user (carried over from the create-session response):

{
// Long-lived identity handle. Required to ever recover this user's
// conversation history after the session expires. NEVER drop this.
"userId": "customer_abc123",

// Short-lived (≤1 hour). Only valid until the next failed refresh.
"sessionId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890"
}

The actual POST /external/sessions/refresh request body — note that userId is not sent on the wire, but you still must have it stored, because when this call eventually returns 404 you will need it to call POST /external/sessions and reattach to the existing conversation:

{
"sessionId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890"
}

Responses

CodeDescriptionContent type
200Successful Responseapplication/json
401Unauthorizedapplication/json
404Session Not Foundapplication/json
422Validation Errorapplication/json
429Too Many Requestsapplication/json

200 Successful Response

FieldType/FormatRequiredDescription
sessionTokenstringYesA new JWT token for the session (expires in 1 hour)
sessionTokenExpirationintegerYesThe expiration timestamp of the new session token (Unix epoch in seconds)

Response samples

{
"sessionToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"sessionTokenExpiration": 1705319400
}

Usage Examples

Example 1: Create a session for a known customer

curl -X POST "https://webchat-v2.filum.ai/external/sessions" \
-H "authorization: Bearer your_api_token_here" \
-H "organization-id: your_organization_id_here" \
-H "auth-type: token" \
-H "Content-Type: application/json" \
-d '{
"organizationId": "org_12345",
"installedSourceId": 1,
"user": {
"id": "customer_abc123",
"name": "John Doe",
"email": "john.doe@example.com",
"phone": "+84901234567"
}
}'

Example 2: Create a session for an anonymous visitor

No conversation persistence

Omitting user.id is only appropriate for truly one-off, throwaway sessions. The server will generate a random userId and return it in the response — if you don't store that value and pass it back as user.id on the user's next visit, they will see a fresh empty chat every time. For authenticated users on your side, always send your own stable user ID as user.id instead.

curl -X POST "https://webchat-v2.filum.ai/external/sessions" \
-H "authorization: Bearer your_api_token_here" \
-H "organization-id: your_organization_id_here" \
-H "auth-type: token" \
-H "Content-Type: application/json" \
-d '{
"organizationId": "org_12345",
"installedSourceId": 1
}'

Example 3: Refresh a session token

curl -X POST "https://webchat-v2.filum.ai/external/sessions/refresh" \
-H "authorization: Bearer your_api_token_here" \
-H "organization-id: your_organization_id_here" \
-H "auth-type: token" \
-H "Content-Type: application/json" \
-d '{
"sessionId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890"
}'

Preserving conversation history across sessions

If you're integrating /external/* because you don't want the webchat to use browser localStorage — i.e. your own backend is the system of record for the user's webchat identity — this section is the contract you need to follow.

The model

  • A conversation is the durable thing — it holds the entire message history.
  • A session is a 1-hour bearer credential over a conversation. It expires and is deleted automatically.
  • The server links a new session back to the prior conversation by matching user.id in POST /external/sessions. Nothing else (not email, not phone, not sessionId after expiry) is used as a fallback.

So: across reloads, browsers, devices, and after session expiry, the conversation persists only if user.id is the same.

This is the path that "just works" — no extra storage required on your side.

  1. On every page load where the user is authenticated, call POST /external/sessions with user.id set to your own internal user ID (the same ID you use everywhere else in your system).
  2. Use the returned sessionToken to drive the webchat for the next hour.
  3. If you want to keep the session alive past 1 hour without forcing the user to reload, call POST /external/sessions/refresh with the sessionId before the token expires.
  4. When the user logs out of your app, simply stop using the session — there's nothing to clean up.

With this pattern you do not need to persist sessionId, sessionToken, or userId in your backend. You can re-derive everything from your own user ID at any time.

Alternative integration (you must use the server-generated ID)

If you can't pass your own ID for some reason and let the server generate Webchat-<uuid> on the first call:

  1. First call: omit user.id. The response contains userId (e.g. Webchat-abc123…).
  2. Persist that userId in your backend, keyed to the user. This is now your only handle on their conversation history.
  3. On every subsequent call to POST /external/sessions for the same user, set user.id to that stored value.
  4. If you lose that value, you lose access to the prior conversation — there is no recovery path.

Common mistakes that produce "blank chat on reload"

  • Calling POST /external/sessions with only email/phone/name and no user.id. The server generates a new random userId on every such call → a new conversation each time.
  • Storing only sessionId in your middleware and relying on /external/sessions/refresh. Works for 1 hour, then 404s, and your fallback POST /external/sessions has no user.id to recover from.
  • Sending different user.id shapes between calls (e.g. omitted the first time, then your own ID later). The server can't link them.
  • Assuming email or phone will be used to recover history. They won't — they only match against currently active (unexpired) sessions, not historical conversations.

Quick decision table

What you store / sendHistory survives reload within 1 hourHistory survives reload after 1 hour
Your own user ID as user.id every callYesYes
Server-generated userId, echoed as user.id every callYesYes
Only sessionId, refreshed periodicallyYes (via refresh)No
Only email / phone, no user.idYes (same active session matched)No
Nothing — recreate fresh each visitNoNo

Rate Limiting

The API endpoints have generous rate limits designed for server-to-server usage:

  • Per second: 20 requests (configurable via EXTERNAL_WEBCHAT_PER_SEC_LIMIT)
  • Per minute: 1,200 requests (configurable via EXTERNAL_WEBCHAT_PER_MIN_LIMIT)

If you exceed these limits, you will receive a 429 Too Many Requests response. Please implement appropriate retry logic with exponential backoff in your integration.

Error Responses

401 Unauthorized

Returned when the authorization token is missing, invalid, or the token does not have the required permissions.

{
"message": "Unauthorized",
"statusCode": 401
}

404 Not Found

Returned when the session ID does not exist (refresh endpoint only).

{
"message": "Session not found",
"statusCode": 404
}

422 Validation Error

Returned when the request body is missing required fields or contains invalid data.

{
"message": ["organizationId should not be empty", "organizationId must be a string"],
"error": "Bad Request",
"statusCode": 400
}

429 Too Many Requests

{
"statusCode": 429,
"message": "ThrottlerException: Too Many Requests"
}