fluxchat/sdk

SDK · Stable

React Native SDK

v0.3.0 · Stable

Official FluxChat SDK for React Native and Expo. A drop-in FluxChatWidget component, a useFluxChat hook for your own UI, and the full typed client.

SourceContributed by @benjaminmugangu — React Native SDK

Installation

terminal
npm install @fluxchat/react-native

Create a client

The base URL defaults to https://api.fluxchat-corp.com/api/v2 — production. Pass it explicitly to target dev.

App.tsx
import { FluxChatWidget, FluxChatClient } from '@fluxchat/react-native';

// Drop-in floating bubble + chat modal
export default function App() {
  return (
    <View style={{ flex: 1 }}>
      {/* your app */}
      <FluxChatWidget apiKey={process.env.EXPO_PUBLIC_FLUXCHAT_KEY!} />
    </View>
  );
}

// …or drive it yourself
const client = new FluxChatClient({ apiKey: process.env.EXPO_PUBLIC_FLUXCHAT_KEY! });

ask()

Send a message and get the assistant's reply. Pass context to inject real-time data the bot treats as a priority source of truth, above the knowledge base. A sessionId keeps multi-turn history without persisting a conversation.

ask.ts
const { reply, conversationId } = await client.ask('Quels sont vos horaires ?', {
  context: 'Utilisateur : Alice, Plan : Pro',
  sessionId: mySessionId,
});

Human handoff (support thread)

When the bot can't help, hand the visitor to a human. This creates a real support ticket in the organization's dashboard — and unlike a contact form, the conversation stays open in the same thread: the visitor polls it, the agent answers into it.

handoff.ts
const support = client.support();

// 1. Hand off — with the same sessionId you pass to ask, the bot's side of
//    the conversation is copied into the ticket.
const { ticketId } = await support.escalate({
  name: 'Jordan Mbeki',
  email: 'jordan@example.com',
  message: 'Mon virement est bloqué depuis hier.',
  sessionId: mySessionId,
});

// 2. Follow the thread: the e-mail proves the ticket is theirs. Store
//    { ticketId, email } in AsyncStorage so it survives an app restart.
const thread = await support.thread(ticketId, 'jordan@example.com');
thread.messages.forEach((m) => console.log(m.role, m.content)); // bot | visitor | agent

// 3. Let them reply into it.
await support.reply(ticketId, 'jordan@example.com', 'La référence est 4821.');
  • Ownership is the e-mail. A wrong e-mail and a non-existent ticket both return 404, deliberately — a guessed ticket id reveals nothing. The lookup is also scoped to the organization behind your API key.
  • Polled, not pushed. There is no socket on the public surface. 5s is the cadence the official widget uses and what the route's limits are sized for: 60 reads/min, 30 replies/min, 5 escalations/min.
  • Statuses: open → in_progress → resolved → closed. A reply to a resolved ticket reopens it; a closed one refuses the write (403) rather than swallowing a message nobody will read.
  • Requires the organization's plan to include supportTickets (403 otherwise).

Knowledge base

Create, update and delete articles. Write operations need a key with the bot:write scope, or an admin JWT.

knowledge.ts
const kb = client.knowledge(jwtToken);

const article = await kb.create('Délais de livraison', 'Livraison sous 48 h en RDC.');
await kb.delete(article.id);

Errors

Every failure is typed: an API error carries the HTTP status and the server's message, a network error wraps the transport failure, and a config error is raised before any request leaves.

errors.ts
import { FluxChatError, FluxChatNetworkError } from '@fluxchat/react-native';

try {
  await support.thread(ticketId, 'someone@else.com');
} catch (err) {
  if (err instanceof FluxChatError) {
    // 404 both when the ticket does not exist and when the e-mail does not
    // own it — deliberately indistinguishable.
    console.log(err.message);
  } else if (err instanceof FluxChatNetworkError) {
    console.log('transport failure', err);
  }
}