Overview
The High IQ API uses Server-Sent Events (SSE) for real-time streaming of AI-generated report sections. Reports are generated section-by-section, with each section streamed as a series of events: start, partial, complete, or error. This allows the client to render content progressively as it is generated.
The streaming service is built on Hono SSE with AI SDK 6 streamText() and Output.object() for structured output with partial updates.
Endpoints
| Endpoint | Method | Description |
|---|
/api/v1/reports/stream/health | GET | Health check for streaming service |
/api/v1/reports/stream/sections | GET | List available section keys |
/api/v1/reports/stream/:sectionKey | POST | Stream a single report section |
/api/v1/reports/stream/batch | POST | Stream multiple sections in sequence |
Single Section Streaming
Stream a single report section by its key. Returns an SSE stream with progressive updates.
Request
curl -X POST "https://tiwih-api.vercel.app/api/v1/reports/stream/terpene_analysis" \
-H "Content-Type: application/json" \
-H "Accept: text/event-stream" \
-d '{
"orderItems": [
{
"strainName": "Blue Dream",
"grams": 3.5,
"type": "hybrid",
"thcPct": 21,
"terpenes": [
{ "name": "Myrcene", "percentage": 0.45 },
{ "name": "Caryophyllene", "percentage": 0.32 }
]
}
],
"orderMetadata": {
"dispensaryName": "Green Leaf",
"orderDate": "2026-02-15",
"totalSpent": 45.00
}
}'
Request Body Schema
{
orderItems?: {
strainName: string;
grams: number;
price?: number;
thcPct?: number;
cbdPct?: number;
type?: 'sativa' | 'indica' | 'hybrid';
terpenes?: { name: string; percentage: number }[];
effects?: string[];
aromas?: string[];
}[];
orderMetadata?: {
dispensaryName?: string;
orderDate?: string;
totalSpent?: number;
};
previousSections?: Record<string, unknown>;
}
SSE Event Stream
The server sends events in the standard SSE format. Each event has a type, sectionKey, and optional data:
event: start
id: a1b2c3d4-uuid
data: {"type":"start","sectionKey":"terpene_analysis","estimatedTokens":500}
event: partial
id: a1b2c3d4-uuid
data: {"type":"partial","sectionKey":"terpene_analysis","data":{"title":"Terpene Profile"},"progress":25}
event: partial
id: a1b2c3d4-uuid
data: {"type":"partial","sectionKey":"terpene_analysis","data":{"title":"Terpene Profile","summary":"Your order features..."},"progress":60}
event: complete
id: a1b2c3d4-uuid
data: {"type":"complete","sectionKey":"terpene_analysis","data":{"title":"Terpene Profile","summary":"Your order features a myrcene-dominant profile...","insights":["..."]},"progress":100}
Batch Section Streaming
Stream multiple sections in sequence. Each section is generated one after another, with overall progress tracking. Previously generated sections are passed as context to dependent sections.
Request
curl -X POST "https://tiwih-api.vercel.app/api/v1/reports/stream/batch" \
-H "Content-Type: application/json" \
-H "Accept: text/event-stream" \
-d '{
"sectionKeys": ["overview", "terpene_analysis", "effects_breakdown"],
"orderItems": [
{
"strainName": "OG Kush",
"grams": 7,
"type": "indica",
"thcPct": 24
}
]
}'
Batch Request Schema
{
sectionKeys: string[]; // At least one section key required
orderItems?: OrderItem[];
orderMetadata?: OrderMetadata;
}
Batch Event Stream
Batch streaming adds batch_start and batch_complete events, plus overall progress tracking on each section event:
event: batch_start
id: req-uuid
data: {"type":"batch_start","totalSections":3,"sectionKeys":["overview","terpene_analysis","effects_breakdown"]}
event: start
id: req-uuid-overview
data: {"type":"start","sectionKey":"overview","overallProgress":0,"completedSections":0,"totalSections":3}
event: partial
id: req-uuid-overview
data: {"type":"partial","sectionKey":"overview","progress":50,"overallProgress":16,"completedSections":0,"totalSections":3}
event: complete
id: req-uuid-overview
data: {"type":"complete","sectionKey":"overview","data":{...},"progress":100,"overallProgress":33,"completedSections":1,"totalSections":3}
event: start
id: req-uuid-terpene_analysis
data: {"type":"start","sectionKey":"terpene_analysis","overallProgress":33,"completedSections":1,"totalSections":3}
...
event: batch_complete
id: req-uuid
data: {"type":"batch_complete","totalSections":3,"completedSections":3,"results":{"overview":{...},"terpene_analysis":{...},"effects_breakdown":{...}}}
Event Types
| Event | Description | Fields |
|---|
batch_start | Batch streaming has begun | totalSections, sectionKeys |
start | Individual section generation started | sectionKey, estimatedTokens |
partial | Partial structured data available | sectionKey, data (partial), progress (0-100) |
complete | Section fully generated | sectionKey, data (complete), progress (100) |
error | Section generation failed | sectionKey, error (message) |
batch_complete | All sections finished | totalSections, completedSections, results |
Batch-Enriched Fields
In batch mode, every section event includes additional fields for overall progress:
| Field | Type | Description |
|---|
overallProgress | number | 0-100 percentage across all sections |
completedSections | number | Count of finished sections |
totalSections | number | Total sections in the batch |
StreamEvent Interface
interface StreamEvent {
type: 'start' | 'partial' | 'complete' | 'error';
sectionKey: string;
data?: unknown; // Partial or complete structured data
progress?: number; // 0-100 section progress
text?: string; // Raw text output
error?: string; // Error message (type: 'error' only)
estimatedTokens?: number; // Estimated token count (type: 'start' only)
}
Available Sections
Fetch the list of available section keys and their metadata:
curl "https://tiwih-api.vercel.app/api/v1/reports/stream/sections"
{
"sections": [
{
"key": "overview",
"label": "Overview",
"tab": "summary",
"order": 1,
"strategy": "ai",
"estimatedTokens": 500
},
{
"key": "terpene_analysis",
"label": "Terpene Analysis",
"tab": "science",
"order": 2,
"strategy": "ai",
"estimatedTokens": 800
}
],
"totalSections": 12
}
Sections with strategy: "computed" are handled client-side and cannot be streamed. The API returns a message indicating the section should be computed locally.
Client Integration
JavaScript / TypeScript (EventSource)
const response = await fetch(
'https://tiwih-api.vercel.app/api/v1/reports/stream/batch',
{
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Accept': 'text/event-stream',
},
body: JSON.stringify({
sectionKeys: ['overview', 'terpene_analysis'],
orderItems: [{ strainName: 'Blue Dream', grams: 3.5 }],
}),
}
);
const reader = response.body!.getReader();
const decoder = new TextDecoder();
let buffer = '';
while (true) {
const { done, value } = await reader.read();
if (done) break;
buffer += decoder.decode(value, { stream: true });
const lines = buffer.split('\n');
buffer = lines.pop() || '';
for (const line of lines) {
if (line.startsWith('data: ')) {
const event = JSON.parse(line.slice(6));
switch (event.type) {
case 'start':
console.log(`Starting ${event.sectionKey}...`);
break;
case 'partial':
// Update UI with partial data
updateSection(event.sectionKey, event.data, event.progress);
break;
case 'complete':
// Section finished
finalizeSection(event.sectionKey, event.data);
break;
case 'error':
console.error(`Error in ${event.sectionKey}: ${event.error}`);
break;
}
}
}
}
React Native (High IQ Mobile)
The mobile app uses custom hooks for SSE consumption:
import { useStreamingReportGeneration } from '@/_hooks/useStreamingReportGeneration';
function ReportScreen({ orderItems }) {
const {
sections,
overallProgress,
isStreaming,
error,
startGeneration,
} = useStreamingReportGeneration();
const handleGenerate = () => {
startGeneration({
sectionKeys: ['overview', 'terpene_analysis', 'effects_breakdown'],
orderItems,
});
};
return (
<View>
<ProgressBar progress={overallProgress} />
{Object.entries(sections).map(([key, section]) => (
<StreamingSectionCard
key={key}
sectionKey={key}
data={section.data}
progress={section.progress}
status={section.status}
/>
))}
</View>
);
}
Error Handling
If a section fails during streaming, an error event is sent for that section and the batch continues to the next section. The batch_complete event includes the count of successfully completed sections.
event: error
id: req-uuid-failing_section
data: {"type":"error","sectionKey":"failing_section","error":"AI model timeout","overallProgress":66,"completedSections":2,"totalSections":3}
If the streaming service itself is unavailable, the API returns a 503 response before streaming begins:
{
"error": "Streaming service is not available",
"code": "SERVICE_UNAVAILABLE"
}
Health Check
Verify the streaming service is available before initiating a stream:
curl "https://tiwih-api.vercel.app/api/v1/reports/stream/health"
{
"available": true,
"service": "section-streaming",
"timestamp": "2026-02-16T12:00:00.000Z",
"aiSectionsCount": 12
}
Check available: true before starting a report generation flow. If false, AI models may not be configured or the service is temporarily unavailable.