@l7mp/tivadar-ai-api-sdk
v0.1.7
Published
TypeScript/JavaScript SDK for Tivadar AI Backend API
Readme
@l7mp/tivadar-ai-api-sdk
TypeScript/JavaScript SDK for the Tivadar AI Backend API. Provides a fully-typed, tree-shakeable client for managing Voice Agents, Chat Agents, RAG knowledge bases, SIP telephony, subscriptions, and more.
- Package:
@l7mp/tivadar-ai-api-sdk - Version:
0.1.4 - Requires: Node.js ≥ 20, or any modern browser / edge runtime with native
fetch - Formats: CommonJS (
dist/index.js) + ESM (dist/esm/index.js), with TypeScript declarations
Table of Contents
- Installation
- Quick Start
- Authentication
- Client Configuration
- API Reference
- Type Reference
- Error Handling
- Advanced Usage
- Low-Level API Classes
Installation
npm install @l7mp/tivadar-ai-api-sdk
# or
yarn add @l7mp/tivadar-ai-api-sdk
# or
pnpm add @l7mp/tivadar-ai-api-sdkQuick Start
import { Api } from '@l7mp/tivadar-ai-api-sdk';
const client = new Api({
baseUrl: 'https://api.tivadar.ai/api/v1',
options: {
token: 'your-jwt-token',
},
});
const ORG_ID = 'org_abc123';
// List all voice agents
const agents = await client.voiceAgents.list(ORG_ID);
// agents: VoiceAgentWithSipTrunks[]
for (const agent of agents) {
console.log(agent.id, agent.name);
}
// Create a voice agent
const newAgent = await client.voiceAgents.create(ORG_ID, {
name: 'Support Agent',
organization_id: ORG_ID,
instructions: 'You are a helpful customer support agent.',
greeting: 'Hello! How can I help you today?',
language: 'en-US',
stt_provider: 'deepgram',
stt_model: 'nova-2',
tts_provider: 'elevenlabs',
tts_voice: 'Rachel',
llm_agent: {
llmProviderName: 'openai/gpt-4o',
temperature: 0.7,
maxTokens: 1024,
},
});
console.log('Created:', newAgent.id);Base URL
All API endpoints are versioned under /api/v1. Set the baseUrl accordingly:
| Environment | Base URL |
|---|---|
| Local development | http://localhost:3000/api/v1 |
| Production | https://your-api-domain.com/api/v1 |
Authentication
All organization-scoped endpoints require a JWT Bearer token. Pass it at construction time or update it dynamically.
At construction time
const client = new Api({
baseUrl: 'https://api.tivadar.ai/api/v1',
options: { token: 'eyJhbGci...' },
});Dynamically (e.g. after login or token refresh)
const client = new Api({ baseUrl: 'https://api.tivadar.ai/api/v1' });
// Set / update the Bearer token
client.setAccessToken('eyJhbGci...');
// Or set the full Authorization header value for non-Bearer schemes
client.setAuthorizationHeader('Basic dXNlcjpwYXNz');
// Inspect the current token
const token = client.getAccessToken(); // string | undefined
// Remove authorization entirely (e.g. on logout)
client.clearAuthorization();The auth state is shared by reference across all internal API instances. Calling setAccessToken() once immediately affects every subsequent request — no need to recreate the client.
Client Configuration
export interface ApiClientConfig {
/** Base URL of the Tivadar AI backend including /api/v1 path. */
baseUrl: string;
options?: {
/** JWT Bearer token (without the "Bearer " prefix). */
token?: string;
};
}Abort / timeout
Every method accepts an optional RequestInit object as the last parameter. Use it to pass an AbortSignal for cancellation or timeouts:
// Abort on demand
const controller = new AbortController();
const agents = await client.voiceAgents.list(ORG_ID, {
signal: controller.signal,
});
controller.abort();
// Timeout after 10 seconds (Node.js 18+)
const agents = await client.voiceAgents.list(ORG_ID, {
signal: AbortSignal.timeout(10_000),
});API Reference
Every method returns a Promise that resolves to the parsed response body. Methods return values directly — they are not wrapped in an envelope object.
Voice Agents
Voice agents handle telephony and LiveKit-based real-time voice conversations.
voiceAgents.list(organizationId, options?)
Returns all voice agents for an organization, including any linked SIP trunk info.
const agents: VoiceAgentWithSipTrunks[] = await client.voiceAgents.list('org_abc123');voiceAgents.listBasic(organizationId, options?)
Returns a lightweight list (id + name only) — useful for dropdowns and selectors.
const basic = await client.voiceAgents.listBasic('org_abc123');
// OrganizationsOrganizationIdVoiceAgentsBasicGet200ResponseInner[]
for (const item of basic) {
console.log(item.id, item.name);
}voiceAgents.get(organizationId, voiceAgentId, options?)
Fetches a single voice agent by ID, including its linked llm_agent config.
const agent: VoiceAgent = await client.voiceAgents.get('org_abc123', 'va_xyz');
console.log(agent.llm_agent?.llmProviderName); // e.g. "openai/gpt-4o"
console.log(agent.language); // e.g. "en-US"voiceAgents.create(organizationId, data, options?)
Creates a new voice agent. Automatically provisions a linked LLM agent in the LangChain service.
const agent: VoiceAgent = await client.voiceAgents.create('org_abc123', {
name: 'Sales Bot',
organization_id: 'org_abc123',
instructions: 'You are a sales assistant for Acme Corp.',
greeting: 'Hi! Welcome to Acme. How can I assist you?',
language: 'en-US',
stt_provider: 'deepgram',
stt_model: 'nova-2',
tts_provider: 'elevenlabs',
tts_model: 'eleven_turbo_v2',
tts_voice: 'Rachel',
enable_recording: true,
llm_agent: {
llmProviderName: 'openai/gpt-4o-mini',
temperature: 0.5,
maxTokens: 512,
maxConversationTurns: 20,
ragConfigName: 'my-knowledge-base', // optional RAG integration
ragTopK: 5,
ragScoreThreshold: 0.7,
toolsConfig: [
{ name: 'calendar', enabled: true },
],
},
});
console.log('Created agent:', agent.id);voiceAgents.update(organizationId, voiceAgentId, data, options?)
Partially updates a voice agent. Only provide fields you want to change.
const updated: VoiceAgent = await client.voiceAgents.update(
'org_abc123',
'va_xyz',
{
name: 'Sales Bot v2',
instructions: 'Updated instructions...',
llm_agent: {
llmProviderName: 'openai/gpt-4o',
temperature: 0.3,
},
}
);voiceAgents.delete(organizationId, voiceAgentId, options?)
Deletes a voice agent and its linked LLM agent.
await client.voiceAgents.delete('org_abc123', 'va_xyz');Chat Agents
Chat agents power chat widget integrations for web applications.
chatAgents.list(organizationId, options?)
const agents: ChatAgent[] = await client.chatAgents.list('org_abc123');chatAgents.get(organizationId, chatAgentId, options?)
const agent: ChatAgent = await client.chatAgents.get('org_abc123', 'ca_xyz');
console.log(agent.chat_api_key); // embed this key in your frontend widget
console.log(agent.allowed_domains); // domain allow-listchatAgents.create(organizationId, data, options?)
const agent: ChatAgent = await client.chatAgents.create('org_abc123', {
name: 'Website Assistant',
system_prompt: 'You are a helpful assistant for our website visitors.',
allowed_domains: ['example.com', 'www.example.com'],
rate_limit: 60, // requests per minute per session
widget_config: {
title: 'Chat with us',
placeholder: 'Type your message...',
welcome_message: 'Welcome! How can I help?',
theme: 'light', // 'light' | 'dark'
position: { side: 'right', alignment: 'bottom' },
},
llm_agent: {
llmProviderName: 'openai/gpt-4o-mini',
temperature: 0.7,
maxTokens: 1024,
ragConfigName: 'product-docs',
},
});chatAgents.update(organizationId, chatAgentId, data, options?)
await client.chatAgents.update('org_abc123', 'ca_xyz', {
system_prompt: 'Updated system prompt.',
rate_limit: 120,
});chatAgents.delete(organizationId, chatAgentId, options?)
await client.chatAgents.delete('org_abc123', 'ca_xyz');RAG (Retrieval-Augmented Generation)
Manage knowledge bases (RAG configs) that can be attached to any agent via llm_agent.ragConfigName.
rag.list(organizationId, options?)
const configs: RagConfig[] = await client.rag.list('org_abc123');
for (const cfg of configs) {
console.log(cfg.name, cfg.vectorStoreType, cfg.embeddingProviderName);
}rag.create(organizationId, data, options?)
const config: RagConfig = await client.rag.create('org_abc123', {
name: 'product-docs',
embedding_provider_name: 'openai/text-embedding-3-small',
});rag.delete(organizationId, ragConfigName, options?)
await client.rag.delete('org_abc123', 'product-docs');rag.documents.upload(organizationId, ragConfigName, file, sourceUrl?, metadata?, options?)
Upload a document for indexing. Accepts a File (browser) or Blob (Node.js).
// Browser
const file = document.querySelector<HTMLInputElement>('#upload')!.files![0];
const doc: RagDocument = await client.rag.documents.upload(
'org_abc123',
'product-docs',
file
);
// With optional metadata
const doc = await client.rag.documents.upload(
'org_abc123',
'product-docs',
file,
undefined, // sourceUrl (optional external link)
JSON.stringify({ category: 'faq' }) // metadata (optional JSON string)
);
// Node.js
import { readFileSync } from 'fs';
const buffer = readFileSync('./manual.pdf');
const blob = new Blob([buffer], { type: 'application/pdf' });
const doc = await client.rag.documents.upload(
'org_abc123',
'product-docs',
blob as unknown as File
);rag.documents.list(organizationId, ragConfigName, status?, options?)
import {
OrganizationsOrganizationIdRagRagConfigNameDocumentsGetStatusEnum as DocStatus,
} from '@l7mp/tivadar-ai-api-sdk';
// All documents
const docs: RagDocumentList = await client.rag.documents.list(
'org_abc123',
'product-docs'
);
// Filter by processing status
const ready = await client.rag.documents.list(
'org_abc123',
'product-docs',
DocStatus.Completed
);rag.documents.get(organizationId, ragConfigName, documentId, options?)
const doc: RagDocument = await client.rag.documents.get(
'org_abc123',
'product-docs',
'doc_abc'
);
console.log(doc.status); // 'pending' | 'processing' | 'completed' | 'failed'rag.documents.replace(organizationId, ragConfigName, documentId, file, sourceUrl?, options?)
Replace the contents of an existing document (re-processes and re-indexes).
await client.rag.documents.replace('org_abc123', 'product-docs', 'doc_abc', newFile);rag.documents.delete(organizationId, ragConfigName, documentId, options?)
await client.rag.documents.delete('org_abc123', 'product-docs', 'doc_abc');Calendar
Manage calendars and events (used by voice agents for scheduling features).
calendar.listCalendars(organizationId, options?)
const response: CalendarListResponse = await client.calendar.listCalendars('org_abc123');
for (const cal of response.data ?? []) {
console.log(cal.id, cal.name);
}calendar.listEvents(organizationId, start, end, calendarIds?, options?)
const events = await client.calendar.listEvents(
'org_abc123',
new Date('2025-01-01T00:00:00Z'),
new Date('2025-01-31T23:59:59Z'),
'cal_1,cal_2' // optional: comma-separated calendar IDs to filter
);calendar.getEvent(organizationId, eventId, options?)
const event: CalendarEventResponse = await client.calendar.getEvent(
'org_abc123',
'evt_xyz'
);
console.log(event.name, event.start_time, event.end_time);calendar.createEvent(organizationId, data, options?)
const event = await client.calendar.createEvent('org_abc123', {
name: 'Team Standup',
description: 'Daily standup meeting',
start_time: new Date('2025-06-01T09:00:00Z'),
end_time: new Date('2025-06-01T09:30:00Z'),
calendar_id: 'cal_abc',
});calendar.updateEvent(organizationId, eventId, data, options?)
await client.calendar.updateEvent('org_abc123', 'evt_xyz', {
name: 'Updated Meeting Name',
end_time: new Date('2025-06-01T10:00:00Z'),
});calendar.deleteEvent(organizationId, eventId, options?)
await client.calendar.deleteEvent('org_abc123', 'evt_xyz');Conversation History
Access conversation history stored by the LangChain service. History is read-only — no local DB.
history.list(organizationId, options?)
const result = await client.history.list('org_abc123');
// OrganizationsOrganizationIdConversationsGet200Response
for (const summary of result.conversations ?? []) {
console.log(summary.id, summary.createdAt);
}history.get(organizationId, conversationId, options?)
Returns the full conversation including all messages.
const convo: HistoryConversation = await client.history.get(
'org_abc123',
'session_xyz'
);
for (const msg of convo.messages ?? []) {
console.log(`[${msg.role}] ${msg.content}`);
}history.delete(organizationId, conversationId, options?)
await client.history.delete('org_abc123', 'session_xyz');Recordings
Fetch presigned S3 URLs for call recordings. Requires the voice agent to have enable_recording: true.
recordings.get(organizationId, conversationId, options?)
const result: RecordingSignedUrl = await client.recordings.get(
'org_abc123',
'session_xyz'
);
console.log(result.url); // Presigned S3 URL — valid for a limited timeSIP / Telephony
Manage SIP trunks, dispatch rules, and phone numbers for inbound telephony routing.
sip.listTrunks(organizationId, options?)
const trunks: SipTrunkWithAgent[] = await client.sip.listTrunks('org_abc123');
for (const trunk of trunks) {
console.log(trunk.number, trunk.dispatch_id);
}sip.createTrunk(organizationId, data, options?)
const trunk: SipTrunk = await client.sip.createTrunk('org_abc123', {
number: '+15551234567',
});sip.deleteTrunk(organizationId, trunkId, options?)
await client.sip.deleteTrunk('org_abc123', 'trunk_xyz');sip.createDispatchRule(organizationId, data, options?)
Create a SIP dispatch rule that routes inbound calls from a trunk to a voice agent.
const result = await client.sip.createDispatchRule('org_abc123', {
trunk_id: 'trunk_xyz',
agent_id: 'va_xyz',
});sip.deleteDispatchRule(organizationId, dispatchId, options?)
await client.sip.deleteDispatchRule('org_abc123', 'dispatch_xyz');sip.listPhoneNumbers(options?)
List all available phone numbers (global, not organization-scoped).
const numbers: PhoneNumber[] = await client.sip.listPhoneNumbers();Organizations
organizations.list(options?)
List all organizations the authenticated user belongs to.
const orgs: Organization[] = await client.organizations.list();
for (const org of orgs) {
console.log(org.id, org.name);
}organizations.create(data, options?)
const org: Organization = await client.organizations.create({
name: 'My Company',
});Members
members.list(organizationId, options?)
const members: Member[] = await client.members.list('org_abc123');
for (const m of members) {
console.log(m.user_id, m.is_admin ? '[admin]' : '');
}Invitations
invitations.list(organizationId, options?)
const invites: InvitationResponse[] = await client.invitations.list('org_abc123');invitations.create(organizationId, data, options?)
const invite: InvitationResponse = await client.invitations.create('org_abc123', {
email: '[email protected]',
is_admin: false,
});
// Send invite.token to the user via emailinvitations.accept(data, options?)
Accept an invitation token. This endpoint does not require authentication.
await client.invitations.accept({
token: 'invitation-token-from-email',
user_id: 'user_xyz',
});Playground
Generate a short-lived LiveKit sandbox token to test a voice agent interactively, without a real phone call.
playground.sandboxToken(organizationId, voiceAgentId, options?)
const result: SandboxToken = await client.playground.sandboxToken(
'org_abc123',
'va_xyz'
);
console.log(result.token); // LiveKit access token
console.log(result.serverUrl); // LiveKit server URL
// Use these to connect directly from the LiveKit SDK or Agents PlaygroundProviders
Discover which LLM, STT, TTS, and embedding providers are enabled for your organization.
llmProviders.list(organizationId, options?)
const providers = await client.llmProviders.list('org_abc123');
// OrganizationsOrganizationIdLlmProvidersGet200ResponseInner[]
// e.g. [{ name: 'openai/gpt-4o' }, { name: 'anthropic/claude-3-5-sonnet' }]
for (const p of providers) {
console.log(p.name);
}sttProviders.list(organizationId, options?)
const providers = await client.sttProviders.list('org_abc123');
// OrganizationsOrganizationIdSttProvidersGet200ResponseInner[]
for (const p of providers) {
console.log(p.name); // e.g. 'deepgram'
for (const model of p.models ?? []) {
console.log(' -', model.id); // e.g. 'nova-2'
}
}ttsProviders.list(organizationId, options?)
const providers = await client.ttsProviders.list('org_abc123');
// OrganizationsOrganizationIdTtsProvidersGet200ResponseInner[]
for (const p of providers) {
console.log(p.name); // e.g. 'elevenlabs'
for (const model of p.models ?? []) {
console.log(' model:', model.id);
for (const voice of model.voices ?? []) {
console.log(' voice:', voice.id, voice.name);
}
}
}embeddingProviders.list(organizationId, options?)
const providers = await client.embeddingProviders.list('org_abc123');
// e.g. [{ name: 'openai/text-embedding-3-small' }]Subscription
Manage billing subscriptions via Stripe integration.
subscription.getStatus(organizationId, options?)
const status: SubscriptionStatus = await client.subscription.getStatus('org_abc123');
if (status.isActive) {
console.log('Plan:', status.plan?.name);
console.log('Status:', status.subscription?.status);
// 'active' | 'trialing' | 'past_due' | 'canceled' | 'paused'
}subscription.getDetails(organizationId, options?)
Returns full subscription details including plan features and limits.
const details: SubscriptionDetails = await client.subscription.getDetails('org_abc123');subscription.createCheckout(organizationId, data, options?)
Create a Stripe Checkout session to start or upgrade a subscription.
const session: CheckoutSessionResponse = await client.subscription.createCheckout(
'org_abc123',
{
plan_slug: 'pro',
success_url: 'https://myapp.com/billing/success',
cancel_url: 'https://myapp.com/billing/cancel',
}
);
window.location.href = session.url; // redirect to Stripe Checkoutsubscription.cancel(organizationId, data?, options?)
// Cancel at the end of the current billing period (recommended)
await client.subscription.cancel('org_abc123', {
cancel_at_period_end: true,
});
// Cancel immediately
await client.subscription.cancel('org_abc123', {
cancel_at_period_end: false,
});subscription.resume(organizationId, options?)
Undo a scheduled cancellation (must call before the period ends).
await client.subscription.resume('org_abc123');subscription.updatePlan(organizationId, data, options?)
Upgrade or downgrade the subscription plan.
const result: UpdatePlanResponse = await client.subscription.updatePlan(
'org_abc123',
{ plan_slug: 'enterprise' }
);subscription.pause(organizationId, data?, options?)
await client.subscription.pause('org_abc123', {
resumes_at: '2025-09-01', // optional ISO date to auto-resume
});subscription.unpause(organizationId, options?)
await client.subscription.unpause('org_abc123');subscription.billingPortal(organizationId, data, options?)
Generate a Stripe Customer Portal session URL for self-service billing management.
const portal: BillingPortalResponse = await client.subscription.billingPortal(
'org_abc123',
{ return_url: 'https://myapp.com/settings' }
);
window.location.href = portal.url;subscription.getCredits(organizationId, options?)
const balance: CreditBalance = await client.subscription.getCredits('org_abc123');
console.log(balance.balance, balance.currency);subscription.getTransactions(organizationId, creditType?, limit?, offset?, options?)
const txns: CreditTransactionsResponse = await client.subscription.getTransactions(
'org_abc123',
'voice_minutes', // optional: filter by credit type
20, // limit (default: 20)
0 // offset for pagination
);
for (const tx of txns.data ?? []) {
console.log(tx.amount, tx.description, tx.createdAt);
}Type Reference
All types are exported from the package root.
import type {
// Agents
VoiceAgent,
VoiceAgentCreate,
VoiceAgentUpdate,
VoiceAgentMetadata,
VoiceAgentWithSipTrunks,
ChatAgent,
ChatAgentCreate,
ChatAgentUpdate,
// LLM
LlmAgent,
LlmAgentInput,
LlmAgentUpdateInput,
ToolConfig,
// RAG
RagConfig,
RagConfigCreate,
RagDocument,
RagDocumentChunk,
RagDocumentList,
RagDocumentChunkList,
// Calendar
Calendar,
CalendarEvent,
CalendarEventCreate,
CalendarEventUpdate,
CalendarEventResponse,
CalendarListResponse,
CalendarWithAgent,
// History
HistoryConversation,
HistoryMessage,
HistorySummary,
// Recordings
RecordingSignedUrl,
// Organizations & Members
Organization,
OrganizationCreate,
OrganizationUpdate,
Member,
// Invitations
InvitationCreate,
InvitationAccept,
InvitationResponse,
// SIP / Telephony
SipTrunk,
SipTrunkCreate,
SipTrunkWithAgent,
DispatchRuleCreate,
PhoneNumber,
// Playground
SandboxToken,
// Widget (Chat)
WidgetConfig,
WidgetPosition,
// Subscription
SubscriptionStatus,
SubscriptionDetails,
CreateCheckoutSessionRequest,
CheckoutSessionResponse,
CancelSubscriptionRequest,
UpdatePlanRequest,
UpdatePlanResponse,
PauseSubscriptionRequest,
PauseSubscriptionResponse,
BillingPortalRequest,
BillingPortalResponse,
CreditBalance,
CreditTransaction,
CreditTransactionsResponse,
} from '@l7mp/tivadar-ai-api-sdk';Key type shapes
VoiceAgentCreate
interface VoiceAgentCreate {
name: string; // required
organization_id: string; // required
instructions?: string; // system prompt / persona instructions
greeting?: string; // first spoken utterance when a call connects
stt_provider?: string; // e.g. 'deepgram'
stt_model?: string; // e.g. 'nova-2'
tts_provider?: string; // e.g. 'elevenlabs'
tts_model?: string; // e.g. 'eleven_turbo_v2'
tts_voice?: string; // e.g. 'Rachel'
language?: string; // BCP-47 code for STT + TTS, e.g. 'en-US', 'hu-HU'
enable_recording?: boolean;
metadata?: VoiceAgentMetadata;
llm_agent?: LlmAgentInput;
}VoiceAgentMetadata
interface VoiceAgentMetadata {
allowedFunctions?: string[]; // names of callable functions / tools
rag_index?: string; // legacy: RAG index name
}LlmAgentInput
interface LlmAgentInput {
llmProviderName: string; // required — e.g. 'openai/gpt-4o'
temperature?: number; // 0.0–2.0, controls randomness
maxTokens?: number; // maximum tokens per response
maxConversationTurns?: number; // max back-and-forth turns before ending
ragConfigName?: string; // name of a RagConfig to attach
ragTopK?: number; // top-K documents to retrieve from the RAG
ragScoreThreshold?: number; // minimum similarity score (0.0–1.0)
toolsConfig?: ToolConfig[]; // tool/function configurations
rateLimit?: number; // max requests per minute
allowedOrigins?: string[]; // CORS origins for the chat endpoint
}ToolConfig
interface ToolConfig {
name: string; // tool identifier, e.g. 'calendar', 'weather'
enabled: boolean;
config?: Record<string, any>; // tool-specific configuration object
}ChatAgentCreate
interface ChatAgentCreate {
name: string; // required
system_prompt?: string; // persona / instructions for the chat agent
allowed_domains?: string[]; // domains permitted to use the widget
rate_limit?: number; // requests per minute per session
widget_config?: WidgetConfig;
llm_agent?: LlmAgentInput;
}WidgetConfig
interface WidgetConfig {
position?: WidgetPosition; // { side: 'right'|'left', alignment: 'bottom'|'top' }
title?: string; // widget header title
placeholder?: string; // input field placeholder
theme?: 'light' | 'dark';
welcome_message?: string; // greeting shown before the first message
}RagConfig
interface RagConfig {
name: string; // unique name used as ragConfigName in agents
organization: string;
vectorStoreType: string; // 'memory' | 'qdrant' | 'weaviate'
vectorStoreUrl?: string; // required for qdrant/weaviate
embeddingProviderName: string; // e.g. 'openai/text-embedding-3-small'
chunkSize: number; // tokens per document chunk
chunkOverlap: number; // token overlap between chunks
maxFileSizeMb: number;
processingTimeoutS: number;
createdAt: Date;
updatedAt: Date;
}SubscriptionStatus
interface SubscriptionStatus {
isActive: boolean; // true when status is 'active' or 'trialing'
service?: SubscriptionStatusService;
subscription?: SubscriptionStatusSubscription | null;
plan?: SubscriptionStatusPlan | null;
}Error Handling
The SDK throws typed errors for HTTP and network failures.
import { ResponseError, FetchError } from '@l7mp/tivadar-ai-api-sdk';
async function safeGet(orgId: string, agentId: string) {
try {
return await client.voiceAgents.get(orgId, agentId);
} catch (err) {
if (err instanceof ResponseError) {
// HTTP error (4xx / 5xx)
console.error('HTTP', err.response.status);
const body = await err.response.json().catch(() => ({}));
console.error('Message:', body.error || body.message);
switch (err.response.status) {
case 401:
// Token expired — refresh and retry
client.setAccessToken(await refreshToken());
return client.voiceAgents.get(orgId, agentId);
case 403:
throw new Error('Not authorized for this organization');
case 404:
return null; // resource not found
default:
throw err;
}
}
if (err instanceof FetchError) {
// Network-level error (DNS, timeout, CORS, offline)
console.error('Network error:', err.cause.message);
throw err;
}
throw err; // unexpected
}
}Advanced Usage
Middleware
The underlying BaseAPI supports pre/post/onError middleware for logging, retry logic, and header injection.
import {
Configuration,
VoiceAgentsApi,
type Middleware,
} from '@l7mp/tivadar-ai-api-sdk';
const loggingMiddleware: Middleware = {
pre: async (ctx) => {
console.log(`→ ${ctx.init.method} ${ctx.url}`);
return ctx; // must return { url, init }
},
post: async (ctx) => {
console.log(`← ${ctx.response.status} ${ctx.url}`);
return ctx.response;
},
onError: async (ctx) => {
console.error(`✗ ${ctx.url}`, ctx.error);
// return a fallback Response to recover, or undefined to propagate the error
},
};
const configuration = new Configuration({
basePath: 'https://api.tivadar.ai/api/v1',
accessToken: () => getTokenFromStore(), // called on every request
middleware: [loggingMiddleware],
});
const voiceAgentsApi = new VoiceAgentsApi(configuration);
const agents = await voiceAgentsApi.organizationsOrganizationIdVoiceAgentsGet({
organizationId: 'org_abc123',
});Retry middleware example
const retryMiddleware: Middleware = {
post: async (ctx) => {
if (ctx.response.status === 429) {
const retryAfter = parseInt(ctx.response.headers.get('Retry-After') ?? '1', 10);
await new Promise(r => setTimeout(r, retryAfter * 1000));
return fetch(ctx.url, ctx.init);
}
},
};Token refresh middleware example
const authMiddleware: Middleware = {
post: async (ctx) => {
if (ctx.response.status === 401) {
const newToken = await refreshAccessToken();
client.setAccessToken(newToken);
const retryInit = {
...ctx.init,
headers: {
...ctx.init.headers as Record<string, string>,
Authorization: `Bearer ${newToken}`,
},
};
return fetch(ctx.url, retryInit);
}
},
};Custom fetch (testing / polyfills)
import { Configuration, VoiceAgentsApi } from '@l7mp/tivadar-ai-api-sdk';
const config = new Configuration({
basePath: 'https://api.tivadar.ai/api/v1',
fetchApi: myCustomFetch, // any fetch-compatible implementation
});Low-Level API Classes
The Api convenience client wraps these generated classes. Use them directly if you need full control over request construction or want to add per-instance middleware.
| Class | Api namespace |
|---|---|
| VoiceAgentsApi | client.voiceAgents |
| ChatAgentsApi | client.chatAgents |
| CalendarApi | client.calendar |
| HistoryApi | client.history |
| RecordingsApi | client.recordings |
| RAGApi | client.rag |
| SIPApi | client.sip |
| OrganizationsApi | client.organizations |
| MembersApi | client.members |
| InvitationsApi | client.invitations |
| PlaygroundApi | client.playground |
| LLMProvidersApi | client.llmProviders |
| STTProvidersApi | client.sttProviders |
| TTSProvidersApi | client.ttsProviders |
| EmbeddingProvidersApi | client.embeddingProviders |
| SubscriptionApi | client.subscription |
All classes extend BaseAPI from ./runtime and accept a Configuration instance.
import { Configuration, VoiceAgentsApi } from '@l7mp/tivadar-ai-api-sdk';
const config = new Configuration({
basePath: 'https://api.tivadar.ai/api/v1',
accessToken: 'your-jwt-token',
});
const api = new VoiceAgentsApi(config);
// Low-level: returns ApiResponse<T> — call .value() to get the parsed body
const raw = await api.organizationsOrganizationIdVoiceAgentsGetRaw({
organizationId: 'org_abc123',
});
console.log(raw.raw.status); // HTTP status
const agents = await raw.value(); // VoiceAgentWithSipTrunks[]
// Convenience: resolves directly to the parsed body
const agents = await api.organizationsOrganizationIdVoiceAgentsGet({
organizationId: 'org_abc123',
});License
See LICENSE in this package.
