Skip to content

Flutter SDK ​

Headless client for your own UI. Prefer widgets? Use the Flutter UI Kit.

Before code: mint a session token on your server. Never ship sk_* in the app.
Guided path: Quick start → Flutter SDK.

Fast path ​

Do this in order — most integrations are these five steps.

1. Install ​

bash
flutter pub add sendsar_chat

2. Connect ​

dart
import 'dart:convert';
import 'package:http/http.dart' as http;
import 'package:sendsar_chat/sendsar_chat.dart';

Future<SessionResponse> fetchChatSession() async {
  final res = await http.post(
    Uri.parse('https://your-app.com/api/chat/session'),
    headers: {'Cookie': '…'},
  );
  if (res.statusCode < 200 || res.statusCode >= 300) {
    throw Exception(res.body);
  }
  return SessionResponse.fromJson(jsonDecode(res.body) as Map<String, dynamic>);
}

final session = await fetchChatSession();
final client = Sendsar.init(SendsarInitOptions(apiUrl: session.apiUrl));
await client.connect(ConnectOptions(
  userId: session.chatUserId,
  token: session.token,
));

3. Conversation list (inbox) ​

dart
final rooms = await client.listRooms();
setConversations(rooms); // ConversationListPage

client.on<Message>(SocketEvent.newMessage, (msg) {
  bumpConversation(msg); // preview, time, sort, unread
});

4. Message thread (open room) ​

Create in ChatPage; destroy in dispose.

dart
final sub = createRoomSubscription(
  client,
  RoomSubscriptionOptions(
    roomId: openRoomId,
    userId: session.chatUserId,
    onInitialMessages: (messages, peerLastReadAt, [nextCursor]) {
      setMessages(messages);
    },
    onMessage: (msg) {
      appendById(msg);
      bumpConversation(msg);
    },
    onMessageUpdated: (msg) => replaceById(msg),
  ),
);

// dispose:
sub.destroy();

5. Send ​

dart
final sent = await client.sendMessage(openRoomId, SendMessageParams(
  parts: [MessagePart(type: 'text', text: 'Hello')],
));
appendById(sent);
bumpConversation(sent);

Screens (what to update) ​

ScreenShowsYour widget
Conversation listRooms, last message, unreadConversationListPage
Message threadBubbles + composer for one roomIdChatPage / MessageList

Also common: Room info, Call UI.

HappensConversation listMessage thread
createRoomAdd rowOptional: open it
New messageBump preview / unreadAppend if that room is open
Edit / delete / reaction / pinPreview if latestReplace by id
forwardMessageBump targetsAppend in open target
deleteConversationRemove rowPop if open
clearHistoryClear previewEmpty list
Members changeOptional subtitleRoom info
Incoming callOptional badgeCall UI

WARNING

messageUpdated → replace by id. Never append a second bubble.


Messaging APIs ​

Create room & send text ​

dart
final room = await client.createRoom(CreateRoomParams(
  externalId: 'dm:${session.chatUserId}:user_bob',
  participants: [
    CreateRoomParticipant(id: session.chatUserId),
    CreateRoomParticipant(id: 'user_bob'),
  ],
));
// → Conversation list: add row

final sent = await client.sendMessage(room.id, SendMessageParams(
  parts: [MessagePart(type: 'text', text: 'Hello')],
));
// → Thread: append · List: bump · Event: newMessage

Edit, delete, reply ​

dart
await client.updateMessage(roomId, messageId, UpdateMessageParams(
  parts: [MessagePart(type: 'text', text: 'Updated')],
)); // → replace · messageUpdated

await client.deleteMessage(roomId, messageId);
// → replace (deletedAt)

await client.sendMessage(roomId, SendMessageParams(
  parts: [MessagePart(type: 'text', text: 'Replying!')],
  parentMessageId: messageId,
)); // → append · newMessage

Reactions ​

dart
await client.toggleReaction(
  roomId,
  messageId,
  ToggleReactionParams(emoji: '👍'),
); // → replace (reactions) · messageUpdated

Pin & forward ​

dart
await client.pinMessage(roomId, messageId);
await client.unpinMessage(roomId, messageId);

await client.forwardMessage(roomId, messageId, ForwardMessageParams(
  targetRoomIds: [otherRoomId],
)); // → target rooms: newMessage + bump list

Send files ​

dart
final message = await client.sendFileMessage(
  roomId,
  bytes: fileBytes,
  filename: 'photo.jpg',
  mediaType: 'image/jpeg',
); // → append · hydrate URLs for previews

Members & conversation ​

dart
await client.addParticipant(roomId, AddParticipantParams(userId: otherUserId));
await client.removeParticipant(roomId, otherUserId);
client.on(SocketEvent.roomParticipantsChanged, (ev) {
  if (ev.roomId == roomId) refreshMembers();
});

await client.deleteConversation(roomId);
await client.clearHistory(roomId);

Voice & video (optional) ​

Enable in the dashboard, then flutter pub add sendsar_call (+ mic/camera permissions).

dart
import 'package:sendsar_call/sendsar_call.dart';

final calls = CallClient(CallClientOptions(chat: client));
calls.on('incoming', (invite) => showIncomingCall(invite));
calls.on('localTrack', (e) { /* bind */ });
calls.on('remoteTrack', (e) { /* bind */ });
await calls.start(room.id, const CallStartOptions(type: 'video'));

Checklist ​

  • [ ] Session from your BFF — no sk_* in the app
  • [ ] Conversation list: listRooms + newMessage bumps
  • [ ] Message thread: createRoomSubscription (destroy on leave)
  • [ ] messageUpdated → replace by id
  • [ ] Files: hydrate access URLs for previews
  • [ ] Calls (if needed): sendsar_call + dashboard flag

Next ​