Sarufi - Dart & Flutter SDK
A modern, null-safe Dart SDK for the Sarufi Conversational AI platform. Build, train and chat with Swahili-first chatbots from any Dart or Flutter app: mobile, desktop, web, server or CLI.
final sarufi = Sarufi('YOUR_API_KEY');
final bot = await sarufi.getBot(42);
final reply = await bot.respond(message: 'Habari');
print(reply.messages); // ['Habari yako? Karibu Weledi']
Why this SDK
- API-key auth - one line to get started.
- Typed models -
Bot,ChatResponse,ChatState,IntentPrediction; no more digging through raw maps. - Typed errors - a
sealedSarufiExceptionhierarchy you can exhaustivelyswitchon. - Self-documenting -
print(SarufiDocs.chat)prints an endpoint's fields and an example, right in your terminal. - Testable - inject your own
http.Client; unit tests never touch the network. - Pure Dart - no Flutter dependency, so it runs everywhere Dart does.
Contents
- Install
- Quick start
- Authentication
- Creating bots
- Conversations
- The
Botobject - Self-documenting API
- Error handling
- Logging
- Testing
- API reference
- Examples
- Other Sarufi SDKs
Install
dart pub add sarufi # or: flutter pub add sarufi
dependencies:
sarufi: ^1.0.0
Then import it:
import 'package:sarufi/sarufi.dart';
Quick start
import 'package:sarufi/sarufi.dart';
Future<void> main() async {
final sarufi = Sarufi('YOUR_API_KEY');
// Create a bot with intents (example phrases) and a flow (state machine).
final bot = await sarufi.createBot(
name: 'Weledi Bot',
description: 'A friendly Swahili student assistant',
intents: {
'salamu': ['habari', 'mambo', 'hi'],
},
flow: {
'salamu': {
'message': ['Habari! Karibu Weledi'],
'next_state': 'end',
},
},
);
// Chat with it.
final reply = await bot.respond(message: 'Habari');
print(reply.messages); // ['Habari! Karibu Weledi']
print(reply.nextState); // 'end'
sarufi.close(); // release the HTTP client when you're done
}
Authentication
Grab an API key from the Sarufi dashboard and pass it to the
constructor. Every request is authenticated with a Bearer token automatically.
final sarufi = Sarufi(
'YOUR_API_KEY',
timeout: const Duration(seconds: 30), // optional (default: 120s)
);
Creating bots
Bots are defined by intents (a map of intent name to example phrases) and a flow (the conversation state machine).
final bot = await sarufi.createBot(
name: 'iBank',
industry: 'banking',
intents: {
'greeting': ['habari', 'mambo', 'hi'],
'balance': ['angalia salio', 'check my balance'],
},
flow: {
'greeting': {
'message': ['Karibu iBank! Naweza kukusaidiaje?'],
'next_state': 'end',
},
},
);
From JSON / YAML files
Keep your training data in files and load it with the IO helper (uses dart:io,
so it's available everywhere except Flutter web):
import 'package:sarufi/sarufi.dart';
import 'package:sarufi/sarufi_io.dart';
final bot = await sarufi.createFromFile(
intents: 'data/intents.yaml',
flow: 'data/flow.yaml',
metadata: 'data/metadata.json', // name, description, industry, ...
);
// Re-upload after editing the files:
await sarufi.updateFromFile(id: bot.id!, flow: 'data/flow.yaml');
Conversations
// Reuse a chat id to keep context across turns.
const chatId = 'user-123';
await sarufi.chat(botId: 42, chatId: chatId, message: 'Habari');
await sarufi.chat(botId: 42, chatId: chatId, message: 'Nataka kukopa');
// Where are we in the flow?
final state = await sarufi.chatStatus(botId: 42, chatId: chatId);
print('${state.currentState} -> ${state.nextState}');
// Classify a message without advancing the conversation.
final p = await sarufi.predictIntent(botId: 42, message: 'nataka salio langu');
print('${p.intent} (${p.confidence})');
// Send over WhatsApp instead of the default channel.
await sarufi.chat(botId: 42, message: 'Hi', channel: Channel.whatsapp);
The Bot object
getBot, bots, createBot and updateBot all return a Bot: a typed
wrapper you can act on directly. Mutating helpers call the API and return a
fresh Bot (no hidden network calls behind a plain setter).
final bot = await sarufi.getBot(42);
bot.name; // 'Weledi Bot'
bot.intents; // Map<String, dynamic>?
bot.flows; // Map<String, dynamic>?
await bot.respond(message: 'Habari'); // ChatResponse
await bot.predictIntent('nataka kozi'); // IntentPrediction
final trained = await bot.addIntent({'bye': ['kwaheri']}); // updated Bot
final renamed = await bot.rename('Weledi v2'); // updated Bot
await bot.delete();
Self-documenting API
Every operation ships with inline docs, no browser needed. Print one endpoint, or all of them:
print(SarufiDocs.chat);
┌─ chat
│ POST conversation
│ Send a message to a bot and get its reply.
│
│ Set channel to whatsapp to route through the conversation/whatsapp
│ endpoint. Reuse chat_id across turns to keep conversation context.
│
│ Request body:
│ bot_id number required
│ chat_id string optional Conversation session id (auto-generated if omitted).
│ message string required
│ message_type string optional [text, image, audio, video, file]
│
│ Response:
│ message array optional The bot's replies.
│ next_state string optional The state moved to.
│
│ Example:
│ final reply = await sarufi.chat(botId: 42, chatId: 'user-1', message: 'Habari');
│ print(reply.messages);
└─
print(Sarufi.docs); // every operation, in reading order
Error handling
Every call throws a typed SarufiException on failure. The base type is
sealed, so a switch is exhaustive and the analyzer keeps you honest:
try {
await sarufi.getBot(42);
} on SarufiException catch (e) {
final reason = switch (e) {
SarufiAuthException() => 'Check your API key',
SarufiNotFoundException() => 'That bot does not exist',
SarufiValidationException() => 'Bad request: ${e.message}',
SarufiNetworkException() => 'No connection',
SarufiServerException() => 'Sarufi is having a bad day',
SarufiApiException() => e.message,
};
print(reason);
}
Each exception carries message, statusCode and the decoded body.
Logging
Nothing is printed by default. Turn on diagnostics during development:
Sarufi.enableConsoleLogging(); // built on the `logging` package
Testing
Inject a mock http.Client and your integration never hits the network:
import 'package:http/testing.dart';
final sarufi = Sarufi(
'test-key',
httpClient: MockClient((req) async => http.Response('{"id":1}', 200)),
);
API reference
| Method | HTTP | Returns |
|---|---|---|
createBot(...) |
POST chatbot |
Bot |
updateBot(id, ...) |
PUT chatbot/{id} |
Bot |
getBot(id) |
GET chatbot/{id} |
Bot |
bots() |
GET chatbots |
List<Bot> |
deleteBot(id) |
DELETE chatbot/{id} |
Map |
chat(...) |
POST conversation |
ChatResponse |
chatStatus(...) |
POST conversation/status |
ChatState |
updateConversationState(...) |
POST conversation-state |
Map |
predictIntent(...) |
POST predict/intent |
IntentPrediction |
Base URL: https://developers.sarufi.io/.
Examples
Runnable examples live in example/:
| Example | What it shows |
|---|---|
example.dart |
End-to-end tour: create, chat, list, train, delete |
weledi/ |
Flagship - a bilingual student bot: browse courses, enroll, pay |
insurance/ |
Build an insurance bot from JSON files |
kubeti/ |
Swahili betting bot, created/updated from JSON |
dart run example/weledi/weledi.dart
Other Sarufi SDKs
Prefer another language? Sarufi has official and community SDKs:
- Dart & Flutter - this package
- Python - sarufi-python-sdk
Credits
Built and maintained by Brightius Kalokola at TRIXA. Thanks to the Sarufi and Neurotech Africa team for the platform.
Support
Please open an issue on GitHub, or contact the maintainer at brightius@trixa.net
Licensed under the MIT License.