FindableClient

The main entry point for the SDK. Create an instance and call methods to interact with the Partner API.

Constructor

// Server-side: use API key directly
const client = new FindableClient({
  apiKey: 'YOUR_API_KEY', // pragma: allowlist secret
  buildingOwnerId: 'cust-456',
});

// Client-side: use a session token (see createSession below)
const client = new FindableClient({
  token: 'ft_...',
  buildingOwnerId: 'cust-456',
});
PropTypeDefaultDescription
apiKeystringYour Findable API key. Provide either apiKey or token.
tokenstringA short-lived session token from createSession(). Provide either apiKey or token.
buildingOwnerId*stringThe building owner (customer) ID
baseUrlstring'https://api.findable.ai'API base URL override

listBuildings()

Returns all buildings for the building owner.

const buildings = await client.listBuildings();
// Building[] — { id, name, numberOfFiles, createdAt, updatedAt }

getBuilding(buildingId)

Get a single building by ID.

const building = await client.getBuilding('bld-789');

Search documents. Omit buildingId to search across all buildings.

const result = await client.search({
  query: 'fire safety',
  buildingId: 'bld-789',   // optional
  maxResults: 10,           // optional
  startIndex: 0,            // optional, for pagination
});
// { hits: SearchHit[], numberOfHits: number }

ask(options)

Ask a question and receive a complete response (non-streaming).

const response = await client.ask({
  buildingId: 'bld-789',
  query: 'What fire safety documents exist?',
  language: 'en',                // optional: 'en' | 'no' | 'nb' | 'nn'
  threadId: 'prev-thread-id',    // optional: continue a conversation
  attachedDocumentIds: ['doc1'], // optional: focus on specific documents
  reasoningEffort: 'medium',     // optional: 'low' | 'medium' | 'high'
});
// { answer, threadId, citations, citedDocuments, followUpSuggestions }

askStream(options)

Same options as ask(), but returns an async iterable of streaming events. See the Streaming guide.

const stream = client.askStream({ buildingId: 'bld-789', query: '...' });

for await (const event of stream) {
  switch (event.event) {
    case 'start':    // { threadId }
    case 'text':     // { text }
    case 'thinking': // { text }
    case 'finish':   // { threadId, answer, citations, citedDocuments, followUpSuggestions }
    case 'error':    // { message }
  }
}

// Cancel early:
stream.abort();

createSession(options?)

Exchange an API key for a short-lived session token suitable for browser use. Only works when the client was created with an apiKey.

// On your server
const server = new FindableClient({ apiKey: 'fk_live_...', buildingOwnerId: 'cust-456' }); // pragma: allowlist secret
const session = await server.createSession({ expiresIn: 3600 }); // optional, default 1h
// => { token: 'ft_...', expiresAt: '2026-03-20T13:00:00.000Z' }

// Pass session.token to the browser and use it there:
const browser = new FindableClient({ token: session.token, buildingOwnerId: 'cust-456' });
PropTypeDefaultDescription
expiresInnumberToken lifetime in seconds (60–86400). Default 3600.

Error Handling

All methods throw typed errors:

import { FindableError, AuthError } from '@findable-ai/sdk';

try {
  await client.ask({ ... });
} catch (err) {
  if (err instanceof AuthError) {
    // 401 — invalid API key
  } else if (err instanceof FindableError) {
    console.error(err.status, err.message);
  }
}