@savantoai/ai-sdk
v3.1.0
Published
Official JavaScript/TypeScript SDK for Savanto AI — search, chat, recommendations, and knowledge base management
Maintainers
Readme
@savantoai/ai-sdk
Official JavaScript/TypeScript SDK for Savanto — AI-powered search, chat, recommendations, and knowledge base management.
Auto-generated from the Savanto OpenAPI spec. Every endpoint is fully typed with zero manual maintenance.
Installation
npm install @savantoai/ai-sdkRequires Node.js >= 18 (uses native fetch). Works in modern browsers with no polyfills.
Quick Start
import { createClient, searchProducts, chat } from '@savantoai/ai-sdk';
const client = createClient({
baseUrl: 'https://api.savanto.ai',
auth: 'if_sk_...',
});
// Search products
const { data } = await searchProducts({
client,
body: { query: 'blue running shoes', limit: 10 },
});
console.log(data);
// AI chat
const { data: chatResponse } = await chat({
client,
body: { message: 'What shoes do you recommend?', threadId: 'thread-1' },
});Authentication
Pass your API key via the auth option on the client:
const client = createClient({
baseUrl: 'https://api.savanto.ai',
auth: 'if_sk_...',
});The client automatically sends it as Authorization: Bearer <key> on every request.
| Key Type | Prefix | Use |
|----------|--------|-----|
| Secret | if_sk_ | Server-side only. Full access to all endpoints. |
| Publishable | if_pk_ | Safe for client-side. Limited to search, chat, feedback, and prompts. |
Examples
Products
import {
searchProducts,
upsertProduct,
getProduct,
deleteProduct,
bulkUpsertProducts,
bulkDeleteProducts,
listProductIds,
} from '@savantoai/ai-sdk';
// Search
const { data } = await searchProducts({
client,
body: { query: 'warm jacket', limit: 10 },
});
// Upsert
await upsertProduct({
client,
body: { id: 'prod-1', name: 'Running Shoe', price: 99.99 },
});
// Get / Delete
const { data: product } = await getProduct({ client, path: { id: 'prod-1' } });
await deleteProduct({ client, path: { id: 'prod-1' } });
// Bulk operations
await bulkUpsertProducts({
client,
body: { items: [{ id: 'p1', name: 'Shoe' }, { id: 'p2', name: 'Boot' }] },
});
await bulkDeleteProducts({ client, body: { ids: ['p1', 'p2'] } });
// List IDs
const { data: ids } = await listProductIds({ client });Chat
import { chat } from '@savantoai/ai-sdk';
// `throwOnError: true` makes `response` non-optional so `response.body` is
// safe to read directly. Without it (since 2.2.0) `response` is typed as
// `Response | undefined`. See CHANGELOG.md for details.
const { data, response } = await chat({
client,
body: {
message: 'What is your return policy?',
threadId: 'thread-1',
stream: true,
},
throwOnError: true,
});
// For streaming (NDJSON), read the response body directly. The protocol is
// block-based: text streams as `block_delta` chunks inside an active text
// block, structured items arrive as `block_data` keyed by item id, and
// per-field streaming (post summaries, product reasons, etc.) flows through
// `item_delta`. See https://savanto.ai/docs/developers/streaming for the
// full chunk-type reference.
const reader = response.body!.getReader();
const decoder = new TextDecoder();
while (true) {
const { done, value } = await reader.read();
if (done) break;
const lines = decoder.decode(value).split('\n').filter(Boolean);
for (const line of lines) {
const chunk = JSON.parse(line);
if (chunk.type === 'block_delta') process.stdout.write(chunk.data.content);
}
}Posts
Same pattern as products — upsertPost, searchPosts, getPost, deletePost, bulkUpsertPosts, bulkDeletePosts, listPostIds.
import { searchPosts, upsertPost } from '@savantoai/ai-sdk';
await upsertPost({
client,
body: { id: 'post-1', title: 'Return Policy', content: '...' },
});
const { data } = await searchPosts({
client,
body: { query: 'shipping policy' },
});Feedback
import { submitFeedback, listFeedback } from '@savantoai/ai-sdk';
// Submit (publishable key safe)
await submitFeedback({
client,
body: { threadId: 'thread-1', messageIndex: 0, rating: 5, comment: 'Helpful!' },
});
// List (secret key)
const { data } = await listFeedback({ client });Threads
import { searchThreads, getThreadMessages, deleteThread } from '@savantoai/ai-sdk';
const { data } = await searchThreads({
client,
body: { query: 'returns' },
});
const { data: messages } = await getThreadMessages({ client, path: { id: 'thread-1' } });
await deleteThread({ client, path: { id: 'thread-1' } });Webhooks
import { createWebhook, listWebhooks, testWebhook } from '@savantoai/ai-sdk';
await createWebhook({
client,
body: { name: 'Inventory sync', url: 'https://example.com/hook', events: ['product.upsert'] },
});
const { data } = await listWebhooks({ client });
const { data: result } = await testWebhook({ client, path: { id: 'webhook-1' } });Recommendations
import { getProductRecommendations } from '@savantoai/ai-sdk';
const { data } = await getProductRecommendations({
client,
body: { productId: 'prod-1', maxRecommendations: 5 },
});Crawl & Scrape
import { startCrawl, getCrawlStatus, scrapePage } from '@savantoai/ai-sdk';
await startCrawl({ client, body: { url: 'https://mystore.com' } });
const { data } = await getCrawlStatus({ client, path: { id: 'crawl-abc' } });
await scrapePage({ client, body: { url: 'https://mystore.com/about' } });Response Format
Every function returns { data, error, response }:
const result = await searchProducts({ client, body: { query: 'shoes' } });
if (result.error) {
// Typed error: { error: { message: string, code: string } }
console.error(result.error);
} else {
console.log(result.data);
}To throw on errors instead of returning them:
const { data } = await searchProducts({
client,
body: { query: 'shoes' },
throwOnError: true,
});TypeScript
All types are exported:
import type {
Product,
ProductInput,
ProductSearchRequest,
Post,
ChatRequest,
ChatStreamChunk,
Taxonomy,
Prompt,
FeedbackSubmission,
ErrorResponse,
} from '@savantoai/ai-sdk';Utilities
import { workspaceIdFromUrl } from '@savantoai/ai-sdk';
workspaceIdFromUrl('https://mystore.com'); // 'mystore-com'
workspaceIdFromUrl('my-store.myshopify.com'); // 'my-store-myshopify-com'API Reference
Full endpoint documentation with request/response schemas:
Versioning & changelog
See CHANGELOG.md for per-version migration notes,
including the TypeScript-level breaking changes in 2.2.0. Type
narrowings and generator-driven shape changes are treated as major.
Regeneration
The SDK is auto-generated from the OpenAPI spec. To regenerate after API changes:
cd cloud && npm run openapi # extract spec to cloud/openapi.json
cd sdks/javascript && npm run generate # regenerate src/generated/License
MIT
