TypeScript SDK
Call Lookio assistants from TypeScript or JavaScript, return answers and citations to your product, stream responses, and continue conversations.
@lookio/sdk is the official TypeScript client for the Lookio API. It has no runtime dependencies and runs on Node 18+, Cloudflare Workers, Deno and Bun, in ESM and CommonJS.
Install and connect
npm install @lookio/sdkimport { Lookio } from "@lookio/sdk";
const lookio = new Lookio({ apiKey: process.env.LOOKIO_API_KEY });Create an API key in Developer tools. For a product that only asks questions, choose Ask questions and limit the key to the assistants it needs. Keep the key on your server. A key in browser code lets visitors use your workspace and spend its credits.
Ask an assistant
const answer = await lookio.assistants.ask("ASSISTANT_ID", {
question: "How much does the pro plan cost?",
mode: "flash", // or "eco", "deep"
});
console.log(answer.answer); // Markdown, citations as [1], [2]
for (const c of answer.citations) console.log(c.n, c.title, c.url);
console.log(answer.credit_cost, answer.credits_remaining);Each answer returned by the model spends the selected mode’s fixed price, even when the resources do not contain an answer. An assistant with no resources is refused before a model call, at no cost. See Credits and plans.
Stream an answer
const stream = lookio.assistants.askStream("ASSISTANT_ID", { question: "Summarise our refund policy." });
for await (const text of stream.textStream()) process.stdout.write(text);
const final = await stream.finalAnswer(); // the same fields as `ask`The stream is also an async iterable of typed events (status, delta, done, error) and has abort(). Lookio does not automatically retry a stream. If the connection closes after the request reached Lookio, the answer may still finish and spend credits. Check the conversation or usage before asking again. See Streaming answers.
Import a file and wait until it is ready
import { openAsBlob } from "node:fs";
const file = await openAsBlob("./handbook.pdf");
const resource = await lookio.resources.uploadFile(file, "handbook.pdf", { title: "Employee handbook", tags: ["hr"] });
const ready = await lookio.resources.waitUntilReady(resource.id); // throws ResourceFailedError if reading failsuploadFile takes a Blob, File, ArrayBuffer, Uint8Array or web ReadableStream (with { contentLength }).
Walk every resource
for await (const resource of lookio.resources.iterate({ tags: ["hr"], status: "ready" })) {
console.log(resource.id, resource.title);
}Lists return { data, hasMore, nextCursor }; iterate() follows the cursors for you.
Schedule a site
resources.createSite and sites.updateRules accept manual, daily, weekly, monthly, or an interval such as every_3_days, every_2_weeks or every_1_month. Intervals range from 1 to 90 days, 1 to 52 weeks or 1 to 12 months. Recurring schedules require a paid plan.
When you omit schedule on creation, Lookio uses manual on Free and weekly on paid plans. When you omit it from sites.updateRules, Lookio keeps the current schedule.
Keep a conversation, name your users
const first = await lookio.assistants.ask("ASSISTANT_ID", {
question: "How much does the Pro plan cost?",
end_user: "user_42", // your own id for the person asking
});
const followUp = await lookio.assistants.ask("ASSISTANT_ID", {
question: "And for the annual plan?",
conversationId: first.conversation_id!, // the history is read server-side
end_user: "user_42",
});
// Forward your user's thumb, then read where the assistant fails.
await lookio.conversations.feedback(first.conversation_id!, first.message_id!, { rating: "down", comment: "Out of date" });
for await (const chat of lookio.logs.conversations.iterate({ rating: "down" })) console.log(chat.title);store: false keeps nothing. See Conversations and end users, Feedback on answers and Logs.
end_user is an identifier, not proof of identity. Set it on your server from the person who has already signed in to your product. Check that a conversation belongs to that person before continuing it. Do not trust an end_user or conversation_id from browser code without checking it.
Use an assistant in your product
Call the SDK from your backend, such as a Node.js API route or Cloudflare Worker. Return only the fields your interface needs to the browser:
const answer = await lookio.assistants.ask("ASSISTANT_ID", {
question,
end_user: authenticatedUser.id,
});
return Response.json({
answer: answer.answer,
citations: answer.citations,
conversation_id: answer.conversation_id,
});For a follow-up, pass the verified conversation id to assistants.ask. The SDK returns answers and data; it does not render a chat interface. Use the Widget if you want Lookio to provide the chat UI.
Put an assistant on a website
const widget = await lookio.widgets.create({
assistant_id: "ASSISTANT_ID",
allowed_domains: ["docs.acme.com"],
settings: { accent: "#0F766E", sources: "numbered_no_links" },
});
console.log(widget.snippets.bubble); // paste on your siteSee Widget.
What is built in
| Idempotency | Every POST except a stream carries an Idempotency-Key, the same on every retry: a retried question is never charged twice. Pass { idempotencyKey } to choose it. |
| Retries | Up to maxRetries (2) on 429, 408, 5xx and network errors, with backoff and Retry-After. Never on another 4xx; never a PATCH that may have landed. |
| Timeouts | timeoutMs per client or per call (60 seconds). Pass a signal to cancel. |
| Errors | Every failure is a LookioError with status, code, param, requestId, actionUrl. Subclasses: AuthenticationError, PermissionError, NotFoundError, ConflictError, RateLimitError, InsufficientCreditsError, ConnectionError. Branch on code, never on the message. |
| Types | Generated from the OpenAPI document, in the API’s own snake_case. |
Methods
| Namespace | Methods |
|---|---|
account, credits, usage | account.get(), credits.get(), usage.get() |
resources | list, iterate, get, createText, createUrl, createSite, uploadFile, update, delete, content, reindex, waitUntilReady, pages, iteratePages |
sites | preview, pages, iteratePages, updateRules, retryFailed |
tags | list, rename, delete |
assistants | list, get, create, update, delete, ask, askStream |
conversations | list, iterate, get, rename, delete, feedback: your own conversations (an API key’s, with end_user) |
logs | conversations.list, .iterate, .get, .stats; answers.list, .iterate, .stats; indexing.list, .iterate, .stats; activity.list, .iterate: the workspace’s four logs |
widgets | list, get, create, update, duplicate, setImage, clearImage, delete, conversations.list, conversations.iterate, conversations.get |
members | list, updatePermissions |
feedback | send to report a problem with Lookio |
lookio.request({ method, path, body }) reaches any endpoint with the same authentication, retries and idempotency.