WebChat

General description

Webchat is a small application allowing communication between users of the website and our bots

Similar to Intercom, webchat will be added to the client page, and be displayed in the right bottom corner, ready to use.

There Is a separate section about the usage of WebChat, starting from What is webchat?

Mobile SDK backend

Besides serving the browser widget, this service is also the gRPC backend for the SentiOne Automate Mobile SDK (iOS and Android). Native mobile applications do not go through the Gateway API or a webhook — they connect to this service directly over gRPC, and it reuses the same session, conversation, hooks and handover machinery as the browser widget.

That makes web-chat the runtime for two channel families:

Channel typeClientTransport
WebChatBrowser widgetHTTP + WebSocket
Mobile - iOS / Mobile - AndroidNative app embedding the Mobile SDKgRPC (HTTP/2)

Channel setup for the mobile variants is described in Adding the Mobile SDK Channel (iOS & Android).

Mobile channels are registered by the channels-connector through the internal /api/mobileChat/* endpoints and stored in this service's own mobile_chat_subscription table, which holds the App Key, the registered application identity, the authentication method, and the optional voice and handover configuration.

API

Default port: 5760

The application exposes two APIs on this port, with different security models:

  • the public HTTP API, used by the browser widget, which is not secured;
  • the gRPC API, used by the Mobile SDK, which is authenticated on every call.

No gRPC call is served anonymously. Handshake is admitted only when the App Key resolves to an active mobile channel and the application identity the SDK reports matches the one registered on that channel; every later RPC must carry the session token issued by that handshake. On channels that enforce external JWT, each call additionally carries a client access token that is validated against the configured JWKS, audience and user identifier claim — and on the long-lived Subscribe stream that token is re-checked as it expires, so the stream cannot outlive the credential behind it. Transport is TLS, terminated at the ingress; the SDK requires it and pins certificates for the SentiOne-hosted environments.

There are default endpoints for monitoring purposes. They are described in Components monitoring section.

gRPC API (Mobile SDK)

The gRPC service is exposed on the same port as the HTTP API — there is no separate gRPC listener. Requests whose Content-Type starts with application/grpc are dispatched to the gRPC handler; everything else is routed normally by Play.

Two consequences worth noting when deploying or debugging:

  • HTTP/2 must be enabled (pekko.http.server.preview.enable-http2 = on). Any proxy or ingress in front of the service has to pass HTTP/2 through, and must not buffer responses — Subscribe, SpeechToText and TextToSpeech are long-lived streams.
  • Server reflection is enabled, so tools such as grpcurl can call the service without a local copy of the .proto files.

Service: sentione.automate.mobile.v1.MobileChatService. The SDK calls Handshake first, then keeps a Subscribe stream open for the lifetime of the session; the remaining RPCs cover conversations, messaging and voice.

Every RPC carries its credentials in gRPC metadata rather than in the message body:

Metadata headerPurpose
x-sentione-app-keyApp Key of the mobile channel; identifies the channel
x-sentione-platformandroid or ios; must agree with the platform identity sent in the handshake
x-sentione-sdk-versionSDK version, checked against the kill-switch below
x-sentione-session-tokenSession token issued by Handshake; sent on every later RPC
x-sentione-client-access-tokenPer-call user credential, for channels that enforce external JWT; absent for anonymous channels

The client's IP address is taken from the TCP connection and attached to the request by the gRPC handler, because gRPC calls carry no X-Forwarded-For.

Internal HTTP endpoints

EndpointCalled byAuth
POST /api/mobileChat/subscribechannels-connector, when a mobile channel is created or updatedOTP
POST /api/mobileChat/unsubscribe/:channelIdchannels-connector, when a mobile channel is removedOTP
GET /api/handoversadmin, to list the handover types enabled on this installationOTP

Communication

This service communicates with the following services:

ApplicationConfig to URLAuth
bot-integrationchatbots.senti-one-api.urlOTP
gateway-apichatbots.gateway-api.urlnone
hooks-serverchatbots.web-chat.hooks.hooks-receivers.urlOTP
thread-coordinatorchatbots.thread-coordinator-api.urlnone
voice-gateway (TTS)chatbots.voice-gateway-api.text-to-speech.base-urlAPI key
voice-gateway (ASR)chatbots.voice-gateway-api.speech-to-text.endpointnone
admin (projects)chatbots.projects-api.urlOTP
storagechatbots.storage-api.urlOTP

Not every target is contacted by every installation:

  • voice-gateway is used only by the Mobile SDK voice RPCs, and both entries are optional — each client is created only when its configuration block is present, so an installation that does not need speech in mobile apps can leave them out. TTS is called over HTTP (POST /v2/synthesize); ASR is a gRPC dictation stream. Both are single, provider-agnostic endpoints: the speech vendor chosen on a channel does not change them.
  • admin (projects) and storage are used only when the attachments feature is configured (chatbots.web-chat.attachments), to resolve the company owning a project and to store the uploaded files.

Config

Application's config:

chatbots.web-chat {  
  legacy-demo-enabled: true # enables or disables demo page for web chat.

  # SQL connection details  
  db {  
    url: "jdbc:postgresql://db:5432/chatbots-web-chat",  
    user: "postgres",  
    password: "root"  
    max-connections: 20  
  }    
  
  session {  
    # After this duration of user inactivity, the session will be marked as expired  
    max-inactivity: 1h  
    # After this duration of user inactivity, the session will be permanently removed from the database  
    delete-after: 24h  
  }  

  # Mobile SDK (gRPC) settings. Only the two nested keys below are required;
  # the rest have the defaults shown.
  mobile-chat {
    # Lifetime of the session token issued by the handshake. The SDK may reuse it
    # to resume a conversation after a dropped connection.
    session-token-ttl: 24h

    # SDK version gate ("kill-switch")
    sdk-version {
      # Handshake is refused below this version, and the app cannot start a conversation
      min-supported: "1.0.0"
      # At or above min-supported but below this: handshake succeeds and is reported
      # to the SDK as DEPRECATED, together with the hint below
      deprecated-below: "1.0.0"
      deprecation-hint: "A newer SDK version is available; please update."
    }

    # Tolerance applied when checking the expiry of an external JWT
    client-access-token-clock-skew: 5s
    # How often an open Subscribe stream re-checks its external JWT for expiry
    client-access-token-expiration-check-interval: 5s
    # Idle keep-alive on the Subscribe stream, so it never goes silent
    subscribe-heartbeat-interval: 30s
  }
  
  hooks {  
    hooks-request-timeout: 30s  
    hooks-messages-max-age: 24h  
    hooks-receivers: [  
      {  
        url: "https://REACT_HOOKS_SERVER_PUBLIC_URL/webchat"  
        otp-secret: "PUT_SECRET_HERE"  
      }  
    ]  
  }  

  # Public address this service is reachable at. Used to build the links handed
  # out for attachments, so it must be the externally visible URL, not an
  # internal service address.
  public-url: "https://WEB_CHAT_PUBLIC_URL"

  # OTP secret for the inbound thread webhook called by thread-coordinator
  thread-coordinator-otp-secret: "PUT_SECRET_HERE"

  # How long a resolved channel subscription is cached before it is re-read
  subscription-cache-duration: 5s

  # Allows sessions that are not tied to a configured channel
  non-channel-web-chat-support-enabled: true

  # Coordinates session processing across instances through Redis. Keep enabled
  # whenever more than one instance is running.
  distributed-locks-enabled: true

  # Which handover destinations this installation offers. Reported to admin
  # through GET /api/handovers and offered when configuring a channel.
  handover-types {
    react {
      enabled: true
    }
    genesys {
      enabled: true
    }
  }

  # Attachments — optional. When absent, users cannot send files, and this
  # service does not contact admin or storage at all.
  attachments {
    # Signs the generated attachment links
    signature-secret-key: "PUT_SECRET_HERE"
    # Virus scanning of uploaded files
    cloudmersive {
      api-key: "PUT_KEY_HERE"
      url: "https://api.cloudmersive.com"
    }
    # Validity of a generated attachment link
    link-expires-in: 1.day
  }
}

Other required configurations:

# Other APIs URLs  
chatbots.gateway-api.url: "http://host:port"

# Bot Integration configuration  
chatbots.senti-one-api {  
  url: "http://bot-integration:9010", # actual address for bot-integration service  
  secret: "KNSWG4TFORIGC43T" # same secret as defined in bot-integration service  
}      
  
# Redis configuration  
chatbots.concurrency {  
  redis {  
    host: "redis"  
    port: 6379  
  }  
} 

# Required to properly work with web-chat channel. If it's not set the web-chat won't be displayed as an available channel  
chatbots.admin.web-chat-demo-url: "http://host:port"

Voice Gateway configuration (Mobile SDK voice only)

Needed only when mobile applications should use speech. Both blocks are optional
and independent — configure just the one you need.

These are not arbitrary URLs. Each one addresses a component of the Automate
platform itself:

  • text-to-speechCrocotta, the platform's text-to-speech component
  • speech-to-textPytia, the platform's speech recognition component

In practice both run in the same Kubernetes cluster as this service, so the host
is simply the Kubernetes service name and the traffic never leaves the cluster —
no ingress, public DNS or externally resolvable address is involved:

chatbots.voice-gateway-api {
  # Text-to-speech synthesis — Crocotta, called over HTTP
  text-to-speech {
    base-url: "http://crocotta:PORT"
    api-key: "PUT_KEY_HERE"
  }

  # Speech-to-text (dictation) — Pytia, called over gRPC.
  # The port is Pytia's own `grpc-endpoint-port` (6885 as shipped).
  speech-to-text {
    endpoint {
      hostname: "pytia"
      port: 6885
    }
    # Upper bound on a single dictation stream
    max-dictation-duration: 2m
  }
}

Substitute the service names your deployment actually uses. Outside a cluster —
for local development against a shared environment, for instance — these become
ordinary reachable addresses, typically port-forwards, and then the host must be
an address the container can reach rather than localhost.

📘

These endpoints are provider-agnostic — they do not change per channel

Each block points at one endpoint — Crocotta for TTS, Pytia for ASR. Neither is tied to a speech vendor, so this configuration is set once per installation and does not change when someone picks a different provider on a channel.

That is because the provider selected on the channel is never sent here. A voice request carries the channel's configuration tag and its provider parameters, and Crocotta or Pytia resolves which engine to use from that tag, matching it against the service tags configured on its own side. The provider name itself never leaves the Channels module, where it only decides which form to show and which configuration tags to offer.

📘

Voice availability is reported to the SDK

A voice capability is usable only when it is configured both on the service, here, and on the channel itself. Configuring one without the other leaves it switched off — in particular, a channel with a TTS provider selected still has no speech if this block is missing. The handshake tells the SDK which of the two are available, so a mobile app can hide its microphone and playback controls when they are not. If the app calls a voice RPC anyway, it is refused with SPEECH_TO_TEXT_NOT_AVAILABLE or TEXT_TO_SPEECH_NOT_AVAILABLE.

Play Framework config

More information about Play Framework could be found in Play Framework configuration section

HTTP/2 has to stay enabled for the Mobile SDK gRPC API to work:

pekko.http.server.preview.enable-http2 = on
🚧

play.http.secret.key also signs mobile session tokens

The session token issued by the gRPC handshake is signed with the application secret. Rotating play.http.secret.key therefore invalidates every outstanding mobile session token, and all instances behind a load balancer must share the same secret or handshakes will not validate across them.

Job execution

This service registers three system cron jobs. They are scheduled and triggered by the cron-orchestrator, not by web-chat itself:

JobSchedulePurpose
FinishWebChatSessionsevery minuteMarks sessions as expired once they pass session.max-inactivity
CleanWebChatSessionsevery hourPermanently removes sessions older than session.delete-after
ClearWebChatBlockingOperationsevery minuteReleases stale blocking operations left behind by interrupted processing

Troubleshooting

Nothing yet.


Did this page help you?