ebchat library

Embeddable ebchat chat SDK for Flutter, on the first-party livechat protocol.

See ebchat-sdk-protocol-v1.md. Re-exports ebchat_core, so a host imports only package:ebchat/ebchat.dart.

Classes

Attachment
A message attachment. Covers raw media (image/video/file/voicenote), the botflow choices type (carrying actions), catalogue (carrying products) and botflow content variants. Backed by the raw map so unknown/forward-compat fields survive. §4.
BootstrapConfig
Public branding + config for a company widget. Mirrors protocol §2.1.
BootstrapFeatures
BootstrapLimits
CartLine
One product line in the local cart.
CatalogPage
One page of the guest catalog (GET /livechat/v1/catalog).
CatalogProduct
A sellable product as the guest sees it — in a catalogue attachment, the catalog browser (GET /catalog), or a cart line. Wire shape is snake_case (product_retailer_id, image_url); botflow-node copies may carry camelCase (imageUrl) — both parse.
ChoiceAction
A botflow choice/form action. Kept deliberately map-backed and opaque: the id payload (a WhatsappButtonId) encodes team / dispatch / branch routing that the client must echo VERBATIM, never reconstruct. Mirrors protocol §4.1.
ChoiceReply
ConversationClosedEvent
EbChat
Entry point for embedding ebchat in a Flutter app. One instance per company.
EbchatAssets
Assets shipped inside this package.
EbchatAttachmentTray
Horizontal strip of pending attachments above the composer, each removable.
EbChatBackground
Protocol §6: background push handling without a live EbChat instance.
EbChatBackgroundResult
What EbChatBackground.handleMessage resolved for a background push: everything the host needs to render a local notification and route a tap.
EbchatCart
WhatsApp-style local cart: products accumulate client-side and get submitted as ONE order message at checkout (controller.sendOrder). Keyed by retailer id; adding an existing product bumps its quantity.
EbchatCatalogueCard
WhatsApp-style product-list card for a catalogue attachment: a header with the menu name, up to three product rows (thumbnail, name, price, add button), and a "view all" action that opens the full list.
EbchatChatView
The complete guest chat surface for one conversation: scrolling transcript (bubbles, botflow choices, product/catalogue cards, order receipts), date separators, typing indicator, closed-state banner, and the composer over a WhatsApp-style wallpaper. Renders an EbchatConversationController; the host owns the controller's lifecycle (start/dispose).
EbchatChoices
Renders the button/form actions of a botflow choices message. Buttons echo the tapped ChoiceAction verbatim via onChoice; a ;cancel action gets secondary styling. Form actions (type == 'form') are labeled by what they ask for (type an answer / share location / upload a photo / attach a file) and surfaced via onForm so the host opens the matching native input.
EbchatComposer
Message input row: text field + send button, with optional attach/voice hooks the host wires up. Emits typing start/stop as the field gains/loses content so the controller can broadcast it. Pass a focusNode to focus the field programmatically (e.g. a "type your answer" form button).
EbchatConversationController
EbChatFormRequest
A botflow form question handed to a host picker.
EbchatMessageBubble
Renders a single message as a chat bubble. Guest messages align to the trailing edge with the primary colour; bot/operator to the leading edge. Text, image, video, voice-note and location attachments render inline; choices attachments are handled separately by EbchatChoices, product / catalogue / order messages by their dedicated cards. A quoted reply shows the quoted snippet block above the content.
EbchatOrderBubble
Receipt-style bubble for a submitted order (message.order) — the guest's cart rendered like WhatsApp renders an order message.
EbchatPendingAttachment
Something the guest has picked or recorded but not sent yet.
EbChatPickedFile
A file chosen by the host's picker, ready to upload.
EbchatProductCard
WhatsApp-style single-product card: image, name, price pill, short description, and an Add-to-Cart action inside the card. Rendered for botflow product messages (message.isProductCard).
EbChatPush
A parsed ebchat push (the FCM data-message payload, protocol §6). The host app owns Firebase — "notification outsourcing" — and passes the raw data map to EbChatPush.parse; ebchat never depends on firebase_messaging itself.
EbchatQuoteBlock
The WhatsApp-style quote block: accent bar + author + snippet. Rendered inside a bubble (above the content) and in the composer reply bar.
EbChatScreen
Drop-in chat screen. Opens (or resumes) the guest conversation for chat, renders it with the company's theme + language, and transparently opens a fresh conversation when the current one is closed by an operator.
EbChatScreenState
Public à la ScaffoldState: hosts that draw their own chrome reach the commerce surface through a GlobalKey.
EbchatStrings
Minimal en/ar string set for the guest chat surface. A small, complete bundle — enough to run the widget; a host can supply overrides.
EbchatTheme
Visual configuration for the chat widgets, derived from the backend BootstrapConfig (primary color, mascotte, powered-by) with sensible defaults. Host apps may override any field.
EbchatThemeScope
Inherited access to the active EbchatTheme.
EbChatUser
The end user of the host app as seen by ebchat.
GeoLocation
A geographic location as exchanged over the livechat protocol (flat lat/long/label). The backend keys it as pin_lat/pin_long internally; the wire shape the client sees and sends is this. Mirrors §2.6 / §3.2.
GeoLocationRef
Small concrete GeoLocation used by sendLocation without importing the model into call sites.
Guest
Identity of an authenticated guest.
GuestIdentity
Optional host-supplied identity for the mobile SDK (verified via HMAC when the company enables it). Mirrors the identity field of §2.2.
InlineAudioPlayer
Inline voice-note player: play/pause, a seekable waveform, and elapsed time.
InMemorySessionStore
Non-persistent default. A real host supplies a durable implementation.
LivechatApiClient
Thin, stateless transport over the /livechat/v1 REST API (protocol §2). Holds no session — callers pass the embed key (bootstrap/session) or a guest token (everything else). Higher-level session/token lifecycle lives in EbchatCoreClient.
LivechatConversation
A guest conversation. Mirrors protocol §3.1.
LivechatMessage
A single message. Mirrors protocol §3.2 and is the shape delivered by both the REST transcript and the realtime message.created event, so one parser serves both.
LivechatOrder
A submitted order carried on a message (message.order) — rendered as an order-summary bubble on the guest side.
LivechatRealtime
Transport for the per-conversation realtime channel. The default is polling (EbchatConversationController handles that internally when no transport is supplied); a Pusher/Soketi implementation of this interface can be dropped in without touching the controller.
LivechatSession
Result of POST /session. Mirrors protocol §2.2.
Mascotte
MessageCreatedEvent
MessageSender
MessageUpdatedEvent
A message changed — e.g. an answered choices menu had its buttons cleared. Carries the message id + the fields that changed (may be partial).
OrderItem
A line in a guest cart submission. Mirrors the WhatsApp order.product_items wire shape so the backend order engine consumes it unchanged.
OrderReply
PusherConfig
Pure helpers for the Pusher wire protocol — no I/O, so they are unit-tested directly. The backend triggers events as trigger(channel, eventName, { eventName, eventId, data }), which arrives at the client as a frame { event, channel, data: "<json>" } where the stringified data is that body. The guest payload we care about is its inner .data. Config for connecting to a Pusher-compatible server (hosted Pusher or self-hosted Soketi). For Soketi supply host/port; for hosted Pusher use the cluster host and 443. authUrl is the gateway's /pusher/auth.
PusherLivechatRealtime
A LivechatRealtime over the Pusher WebSocket protocol (hosted Pusher or self-hosted Soketi). Connects, authorizes the private private-livechat-<conversationId> channel against the gateway's /pusher/auth with the guest JWT, subscribes, and maps events. On any error the stream simply ends — EbchatConversationController should be configured to fall back to polling, or the host can reconnect.
RealtimeConfig
Pusher/Soketi connection params advertised by bootstrap (§2.1).
RealtimeEvent
A guest-facing realtime event on a conversation channel (protocol §5).
SendMessageRequest
A guest outbound message. Exactly one of text / attachments / location / choice / order is populated (protocol §2.6). Use the named constructors. quotedMessageId turns the send into a quoted reply (WhatsApp-style).
SessionStore
Persists the guest session so a returning visitor resumes and a background isolate (mobile push) can reconnect. Implementations back this with localStorage (web), secure storage (mobile), or memory (tests).
TypingEvent

Enums

ConversationStatus
EbChatFormKind
What a botflow form question is asking the guest for.
EbchatPendingStatus
Where a queued attachment is in its life.
LivechatConnectionState
Drives a single guest conversation: message state, optimistic send with idempotent de-dupe, pagination, read/typing, and live updates via either an injected LivechatRealtime transport or built-in polling.
LivechatDeliveryStatus
Sender-side progress of one message, newest state last.
SenderType
Who authored a message. Mirrors protocol §3.2 sender.

Functions

detectTextDirection(String text) TextDirection?
Best-effort base direction for USER CONTENT: the first strong character wins (how WhatsApp lays out mixed-language bubbles). Null → no strong character (digits/emoji only) → inherit the ambient direction.
formatDateLabel(DateTime date, {required DateTime now, required String today, required String yesterday, bool arabic = false}) String
Date-separator label: Today / Yesterday / "9 Jul 2026".
formatMoney(num value, String? currency) String
"12 QAR" (or just the number when no currency is known).
formatPrice(num value) String
12 -> "12", 6.5 -> "6.5", 6.50 -> "6.5" — price without trailing zeros.
formatShortDate(DateTime date, {bool arabic = false}) String
Day + month, for timestamps older than a week ("9 Jul").
formatTime(DateTime time) String
hh:mm in the local timezone for in-bubble timestamps.
formatWeekday(DateTime date, {bool arabic = false}) String
Short weekday for timestamps inside the past week.
productFromAddToCart(ChoiceAction action, {String? name, String? imageUrl, String? description}) CatalogProduct
Build the product a botflow Add-to-Cart action refers to, joining the action's routing payload (retailer id, price, currency) with the visuals of the message that carried it (name from the card text, image attachment).
quoteAuthor(LivechatMessage m, EbchatStrings strings) String
Display name for a quoted message's author ("You" for the guest's own).
quoteSnippet(LivechatMessage m, EbchatStrings strings) String
One-line preview of a message for quote blocks and the composer reply bar: text (truncated) or a typed placeholder ("📷 Photo", "📍 Location", …).
showEbchatCartSheet({required BuildContext context, required EbchatCart cart, required EbchatTheme theme, required EbchatStrings strings, required Future<void> onSubmit()}) Future<void>
Bottom-sheet cart: lines with quantity steppers, total, and a Send-order button. Returns via onSubmit; the host sends the order message and clears the cart on success.
showEbchatCatalogBrowser({required BuildContext context, required EbchatTheme theme, required EbchatStrings strings, required EbchatCatalogLoader loader, required void onAddToCart(CatalogProduct product, int quantity), List<CatalogProduct>? seed, String? title, EbchatCart? cart, VoidCallback? onOpenCart}) Future<void>
Full-height catalog browser (the WhatsApp storefront view): searchable, paginated product grid; tapping a product opens a detail pane with a quantity stepper and Add to cart.
showEbchatFullscreenImage({required BuildContext context, required String url, String? title}) Future<void>
Full-screen image viewer: pinch/double-tap to zoom, drag to pan, tap or swipe down to dismiss.
stripHtml(String input) String
Strip HTML tags/entities from backend-sourced rich text (product descriptions arrive as <p>…</p> fragments).

Typedefs

EbChatAttachmentPicker = Future<EbChatPickedFile?> Function()
Opens the native picker for the composer's attach button. Unlike EbChatFilePicker this answers no particular question — the guest just wants to send something — so it takes no request. Return null when they cancel. EbChatScreen uploads and sends whatever comes back.
EbChatAttachmentsPicker = Future<List<EbChatPickedFile>> Function()
Multi-select variant: return every file the guest picked (empty = cancel). Preferred over EbChatAttachmentPicker — five photos of a broken product should be one gallery visit, not five.
EbchatCatalogLoader = Future<CatalogPage> Function({int offset, String? query})
Loads one page of the company catalog. Wired to LivechatApiClient.getCatalog by the host.
EbChatFilePicker = Future<EbChatPickedFile?> Function(EbChatFormRequest request)
Opens the native picker for a media form question. Return null when the guest cancels — nothing is sent and the question stays pending.
EbChatLocationResolver = Future<GeoLocation?> Function()
Resolves the device's position for a location form question. Return null when permission is denied or no fix is available; the guest is then invited to type their address instead.
EbChatRecordCancel = Future<void> Function()
Aborts recording and throws the audio away — the guest cancelled.
EbChatRecordPause = Future<void> Function()
Holds a recording without ending it. Pair with EbChatRecordResume; supply both and the recording bar gains a pause button.
EbChatRecordResume = Future<void> Function()
Continues a held recording, appending to the same clip.
EbChatRecordStart = Future<bool> Function()
Starts recording a voice note. Return false when the microphone is refused or unavailable; the composer then stays in its normal text state.
EbChatRecordStop = Future<EbChatPickedFile?> Function(Duration elapsed)
Stops recording and returns the captured audio, or null to discard it (a recording too short to be worth sending, say). EbChatScreen uploads it as a voicenote and sends it.
EbchatVoiceAmplitude = Stream<double> Function()
Live input level, 0..1. Drives the recording waveform; without it the bar falls back to a static pattern, since a flat line looks like a dead mic.
EbchatVoiceCancel = Future<void> Function()
Discard the capture.
EbchatVoicePause = Future<void> Function()
Hold capture, keeping what has been recorded so far.
EbchatVoiceResume = Future<void> Function()
Continue a paused capture, appending to the same recording.
EbchatVoiceStart = Future<bool> Function()
Starts audio capture; false → permission denied / unavailable (stay idle).
EbchatVoiceStop = Future<void> Function(Duration elapsed)
Finalize the capture and deliver it (upload + send) — elapsed stamps the voice note's duration.

Exceptions / Errors

LivechatApiException
Thrown on a non-2xx livechat API response. code is the stable machine code from the error envelope (protocol §7), e.g. conversation_closed, invalid_or_expired_token.