Lookio Docs
Lookio websiteOpen Lookio
ToolsTypeScript SDK
Tools

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

Terminal
npm install @lookio/sdk
TypeScript
import { 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: in browser code, visitors could spend your credits.

Ask an assistant

TypeScript
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 costs the fixed price of its mode, also when the resources hold no answer. See Credits and plans.

Stream an answer

TypeScript
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), with abort(). The SDK never retries a stream. If the connection closes, the answer can still finish and cost credits. Check the conversation or usage before you ask again. See Streaming answers.

Import a file and wait until it is ready

TypeScript
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 fails

uploadFile takes a Blob, File, ArrayBuffer, Uint8Array or web ReadableStream (with { contentLength }).

Walk every resource

TypeScript
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: 1 to 90 days, 1 to 52 weeks or 1 to 12 months. Recurring schedules need a paid plan. See Websites for the defaults.

Keep a conversation, name your users

TypeScript
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 id, not a proof of identity. Set it on your server, from the person signed in to your product. Do not trust an end_user or a conversation_id that comes from browser code.

Use an assistant in your product

Call the SDK from your backend, such as a Node.js API route or a Cloudflare Worker. Send to the browser only the fields that your interface needs:

TypeScript
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 checked conversation id to assistants.ask. The SDK returns data, not a chat interface. For a ready chat interface, use the Widget.

Put an assistant on a website

TypeScript
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 site

See Widget.

What is built in

IdempotencyEvery POST except a stream sends an Idempotency-Key, the same on each retry. So a retried question is never charged twice. Pass { idempotencyKey } to set it.
RetriesUp 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 arrived.
TimeoutstimeoutMs per client or per call (default 60 seconds). Pass a signal to cancel.
ErrorsEvery 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.
TypesGenerated from the OpenAPI document, in the API’s own snake_case.

Methods

NamespaceMethods
account, credits, usageaccount.get(), credits.get(), usage.get()
resourceslist, iterate, get, createText, createUrl, createSite, uploadFile, update, delete, content, reindex, waitUntilReady, pages, iteratePages
sitespreview, pages, iteratePages, updateRules, retryFailed
tagslist, rename, delete
assistantslist, get, create, update, delete, ask, askStream
conversationslist, iterate, get, rename, delete, feedback: your own conversations (an API key’s, with end_user)
logsconversations.list, .iterate, .get, .stats; answers.list, .iterate, .stats; indexing.list, .iterate, .stats; activity.list, .iterate: the workspace’s four logs
widgetslist, get, create, update, duplicate, setImage, clearImage, delete, conversations.list, conversations.iterate, conversations.get
memberslist, updatePermissions
feedbacksend to report a problem with Lookio

lookio.request({ method, path, body }) reaches any endpoint with the same authentication, retries and idempotency.

Use these docs with your AI tools

An AI agent can read this documentation directly. You do not need an account or an API key. Everything here is public and read-only.

Query these docs via MCP

Recommended

Add this server to Claude, Claude Code, Cursor, Mistral, or any tool that supports MCP. Your agent can then search Lookio Docs documentation and read it in full, instead of answering from memory.

https://lookio.app/docs/mcp
  • searchFind the passages that answer a question.
  • fetchRead one page in full, as Markdown.
  • list_pagesSee every page in this documentation.

Query these docs over HTTP

The same tools also work as plain web requests. Use this for scripts, or for any tool that does not support MCP. There is one endpoint per tool. Arguments go in the query string, and the answer comes back as JSON.

https://lookio.app/docs/api/docs/search?query=custom+domain

Read the OpenAPI description. It is built from the same definitions as the tools, so it always matches what the endpoints do.

Read these docs as Markdown

Add .md to any page URL to get its Markdown source. You can also send the headerAccept: text/markdown to the page URL itself.

To read the whole documentation in one file, open llms-full.txt. For a short index of every page, open llms.txt.