SDK Reference
Tannur provides type-safe SDKs for every major platform — TypeScript, React, React Native, Python, Go, PHP, and SvelteKit. Each SDK wraps the REST API with ergonomic helpers, smart retries, and automatic tenant resolution.
TypeScript
npm install tannurReact
npm install @tannur/reactPython
pip install tannur-sdkGo
go get github.com/tannur/go-sdkPHP
composer require tannur/php-sdkSvelteKit
npm install @tannur/sveltekitReact Native
npm install @tannur/react-nativeCLI
npm install -g @tannur/cliUniversal TypeScript SDK
TypeScriptThe core JavaScript/TypeScript package. Works in Node.js, edge workers (Cloudflare, Deno), and browsers alike.
npm install tannurimport { createClient } from 'tannur';
const tannur = createClient({
apiKey: process.env.TANNUR_API_KEY,
});
// Emit an event into a named stream
const res = await tannur.emit('user.signup', {
userId: 'usr_9kx2m',
email: 'alice@example.com',
plan: 'pro',
});
console.log(res.eventId); // evt_7xk29m// Fetch the current materialised state of a stream
const state = await tannur.getState('user_stream_usr_9kx2m');
console.log(state);
// {
// totalEvents: 12,
// lastEvent: 'user.profile_updated',
// updatedAt: '2026-06-30T12:00:00Z'
// }// List raw events (with pagination)
const { events, total } = await tannur.listEvents('orders', {
limit: 50,
offset: 0,
});
events.forEach(e => console.log(e.type, e.data));// Built-in retry + custom timeout
const tannur = createClient({
apiKey: process.env.TANNUR_API_KEY,
retry: { maxAttempts: 3, backoffMs: 500 },
timeoutMs: 10_000,
});React SDK
ReactPurpose-built for React. Provides useStream() and useEmit() hooks that re-render your components automatically when stream state changes.
npm install @tannur/react// Wrap your app with TannurProvider
import { TannurProvider } from '@tannur/react';
export default function App({ children }) {
return (
<TannurProvider apiKey={process.env.NEXT_PUBLIC_TANNUR_KEY}>
{children}
</TannurProvider>
);
}'use client';
import { useStream, useEmit } from '@tannur/react';
export function OrderDashboard() {
// Reactive — re-renders when the stream updates
const { state, loading, error } = useStream('orders');
const { emit, pending } = useEmit();
const placeOrder = async () => {
await emit('order.created', {
items: ['SKU-001'],
amount: 49.99,
currency: 'NGN',
});
};
if (loading) return <p>Loading stream…</p>;
if (error) return <p>Error: {error.message}</p>;
return (
<div>
<h2>Total Orders: {state?.totalOrders}</h2>
<button onClick={placeOrder} disabled={pending}>
{pending ? 'Placing…' : 'Place Order'}
</button>
</div>
);
}React Native SDK
React NativeThe same hook API as @tannur/react, but optimised for iOS and Android. Works with Expo and bare React Native projects.
npm install @tannur/react-nativeimport { useStream, useEmit } from '@tannur/react-native';
import { View, Text, TouchableOpacity } from 'react-native';
export function ActivityFeed() {
const { state, loading } = useStream('user_activity');
const { emit } = useEmit();
const trackTap = () =>
emit('ui.button_tapped', { screen: 'Home', button: 'CTA' });
return (
<View>
<Text>Events: {state?.totalEvents ?? 0}</Text>
<TouchableOpacity onPress={trackTap}>
<Text>Track Tap</Text>
</TouchableOpacity>
</View>
);
}Python SDK
PythonFull-featured sync and async clients for Python 3.9+. Great for Django, Flask, FastAPI, and data-science pipelines.
pip install tannur-sdkimport tannur
client = tannur.Client(api_key="tnr_live_xxxx")
# Emit an event
result = client.emit(
stream="payments",
event_type="payment.completed",
data={"amount": 9999, "currency": "NGN", "user_id": "u_abc"},
)
print(result["eventId"])
# Fetch stream state
state = client.get_state("payments")
print(state["totalRevenue"])import asyncio
import tannur
async def main():
async with tannur.AsyncClient(api_key="tnr_live_xxxx") as client:
# Batch emit
events = [
{"type": "page.viewed", "data": {"page": "/home"}},
{"type": "page.viewed", "data": {"page": "/pricing"}},
]
await asyncio.gather(*[
client.emit("analytics", e["type"], e["data"])
for e in events
])
asyncio.run(main())Go SDK
GoA high-performance, idiomatic Go SDK for fast backend services and edge-native connectors. Fully context-aware.
go get github.com/tannur/go-sdk@latestpackage main
import (
"context"
"fmt"
"log"
tannur "github.com/tannur/go-sdk"
)
func main() {
client, err := tannur.NewClient(tannur.Options{
APIKey: "tnr_live_xxxx",
})
if err != nil {
log.Fatal(err)
}
ctx := context.Background()
// Emit an event
event, err := client.Emit(ctx, tannur.EmitInput{
Stream: "inventory",
Type: "stock.updated",
Data: map[string]any{
"sku": "PROD-001",
"quantity": 250,
},
})
if err != nil {
log.Fatal(err)
}
fmt.Println("Event ID:", event.ID)
// Fetch state
state, err := client.GetState(ctx, "inventory")
if err != nil {
log.Fatal(err)
}
fmt.Printf("State: %+v\n", state)
}PHP SDK
PHPA PSR-compatible PHP SDK that works with Laravel, WordPress, Symfony, and raw PHP. Install via Composer.
composer require tannur/php-sdk<?php
require 'vendor/autoload.php';
use Tannur\Client;
$client = new Client(['api_key' => 'tnr_live_xxxx']);
// Emit an event
$result = $client->emit('subscriptions', 'subscription.renewed', [
'user_id' => 'u_9xk2',
'plan' => 'pro',
'amount' => 2999,
]);
echo $result['eventId'] . PHP_EOL;
// Get stream state
$state = $client->getState('subscriptions');
echo "Active subs: " . $state['activeCount'] . PHP_EOL;<?php
// Laravel service provider — bind once, use anywhere
use Tannur\Client;
use Illuminate\Support\ServiceProvider;
class TannurServiceProvider extends ServiceProvider
{
public function register(): void
{
$this->app->singleton(Client::class, fn () =>
new Client(['api_key' => config('services.tannur.key')])
);
}
}
// In a controller:
class OrderController extends Controller
{
public function store(Request $request, Client $tannur)
{
$tannur->emit('orders', 'order.placed', $request->validated());
return response()->json(['ok' => true], 201);
}
}SvelteKit SDK
SvelteKitA first-class SvelteKit integration with server-side load helpers and reactive Svelte stores for real-time stream subscriptions.
npm install @tannur/sveltekit// +page.server.ts — server-side load
import { createServerClient } from '@tannur/sveltekit/server';
import type { PageServerLoad } from './$types';
export const load: PageServerLoad = async ({ locals }) => {
const tannur = createServerClient(process.env.TANNUR_API_KEY!);
const state = await tannur.getState('dashboard_metrics');
return { metrics: state };
};<!-- +page.svelte — reactive client store -->
<script lang="ts">
import { useStream } from '@tannur/sveltekit';
export let data; // from load()
// Subscribe to live updates
const stream = useStream('dashboard_metrics');
</script>
<h1>Total Revenue</h1>
{#if $stream.loading}
<p>Loading…</p>
{:else}
<!-- Use server-loaded value, updated by live store -->
<p class="text-4xl font-bold">
₦{($stream.state?.totalRevenue ?? data.metrics.totalRevenue).toLocaleString()}
</p>
{/if}