@findable-ai/sdk
Zero-dependency TypeScript client for the Findable Partner API. Works in browsers, Node.js, and any runtime with native fetch.
Full documentation: docs.findable.ai
Installation
npm install @findable-ai/sdk
Quick start
import { FindableClient } from '@findable-ai/sdk';
const client = new FindableClient({
apiKey: 'YOUR_API_KEY',
buildingOwnerId: 'YOUR_BUILDING_OWNER_ID',
});
// Search documents
const results = await client.search({ query: 'fire safety', buildingId: 'bld-123' });
console.log(results.hits);
// Ask a question (non-streaming)
const answer = await client.assistant({
buildingId: 'bld-123',
query: 'What are the fire safety requirements?',
});
console.log(answer.answer);
Streaming
assistantStream() returns an async iterable with real-time server-sent events:
const stream = client.assistantStream({
buildingId: 'bld-123',
query: 'Summarise the ventilation specs',
});
for await (const event of stream) {
switch (event.event) {
case 'text':
process.stdout.write(event.text);
break;
case 'finish':
console.log('\n\nCitations:', event.citations);
break;
}
}
// Cancel at any time
stream.abort();
Stream events
| Event | Fields | Description |
|---|---|---|
start | threadId | Stream opened, thread created |
text | text | Incremental answer text chunk |
thinking | text | Model reasoning text (when using high reasoning effort) |
action | state, value, result | Agent progress/action update |
finish | answer, threadId, citations, citedDocuments, followUpSuggestions | Complete response with metadata |
error | message | Error occurred |
API reference
FindableClient
new FindableClient({ apiKey: string, buildingOwnerId: string, baseUrl?: string })
Methods
| Method | Returns | Description |
|---|---|---|
assistant(options) | Promise<AssistantResponse> | Ask a question, get a complete response |
assistantStream(options) | AsyncIterable<AssistantStreamEvent> & { abort() } | Ask with real-time streaming |
assistantAcrossBuildings(options) | Promise<AssistantResponse> | Ask across buildings, get a complete response |
assistantAcrossBuildingsStream(options) | AsyncIterable<AssistantStreamEvent> & { abort() } | Ask across buildings with real-time streaming |
search(options) | Promise<SearchResult> | Search documents |
listBuildings() | Promise<Building[]> | List all buildings |
getBuilding(id) | Promise<Building> | Get a single building |
The earlier names ask(), askStream(), askAcrossBuildings() and
askAcrossBuildingsStream(), and the Ask* types, are deprecated. They keep working and
have no removal date; replace ask with assistant in the name when you next touch the code.
Options
// Assistant
{ buildingId: string, query: string, language?: 'en' | 'no' | 'nb' | 'nn',
threadId?: string, attachedDocumentIds?: string[], mode?: 'fast' | 'balanced' | 'deep',
reasoningEffort?: 'low' | 'medium' | 'high' /* deprecated */, useAgenticRag?: boolean }
// Search
{ query: string, buildingId?: string, maxResults?: number, startIndex?: number }
Choosing how much work goes into an answer
mode is one setting with three positions:
mode | What you get |
|---|---|
'fast' | Cheapest and quickest: roughly 15x cheaper than 'balanced' and several times faster, with shallower synthesis across many documents. |
'balanced' | The default. What every request gets when mode is omitted. |
'deep' | Most thorough and most expensive. For questions that genuinely need extensive reasoning across many sources. |
Prefer 'fast' for lookups and single-document questions. If you run the Assistant in a
batch (for example a nightly job asking the same questions of the same
buildings), this is the setting that matters most for cost.
Omit mode and nothing changes: requests are answered exactly as they were
before the option existed.
reasoningEffort is deprecated in favour of mode. It was never a separate dial:
'high' behaves like mode: 'deep', and 'low' and 'medium' both behave like
mode: 'balanced'. It is still accepted with that behaviour, and ignored when
mode is set.
Error handling
import {
FindableClient,
AuthError,
NotFoundError,
FindableError,
} from '@findable-ai/sdk';
try {
await client.assistant({ buildingId: 'bld-123', query: 'Hello' });
} catch (err) {
if (err instanceof AuthError) {
// Invalid or missing API key (401/403)
} else if (err instanceof NotFoundError) {
// Building not found (404)
} else if (err instanceof FindableError) {
// Other API error — check err.status and err.message
}
}
React
For drop-in React components and hooks, see @findable-ai/react.
Documentation
Licence
MIT