Skip to Content
API ReferenceSDK Client

SDK Client

@pandorakit/sdk/client provides a typed HTTP client for Pandora. It wraps every REST endpoint with type-safe methods, handles authentication headers, and supports automatic token refresh.

Installation

npm install @pandorakit/sdk

Creating a Client

import { createClient } from '@pandorakit/sdk/client' const client = createClient({ baseUrl: 'http://localhost:4111', getToken: () => localStorage.getItem('pandora_token'), })

createClient is synchronous — safe to call at module scope.

ClientOptions

OptionTypeDefaultDescription
baseUrlstring"http://localhost:4111"Pandora server URL
getToken() => string | null | Promise<string | null>Called before every request to get the access token
refreshToken{ get, onRefresh }Opt-in automatic token refresh (see below)
fetch(url, init?) => Promise<Response>globalThis.fetchCustom fetch implementation (for testing, proxies, or non-standard runtimes)

Authentication

Pass getToken to attach a bearer token to every request. For automatic token refresh on 401 responses, configure refreshToken:

const client = createClient({ baseUrl: 'http://localhost:4111', getToken: () => localStorage.getItem('pandora_token'), refreshToken: { get: () => localStorage.getItem('pandora_refresh_token'), onRefresh: (tokens) => { localStorage.setItem('pandora_token', tokens.token) localStorage.setItem('pandora_refresh_token', tokens.refreshToken) }, }, })

When a request gets a 401, the client automatically exchanges the refresh token for a new pair, calls onRefresh to persist the rotated tokens, and retries the original request. Concurrent 401s are deduplicated into a single refresh call.

Client Namespaces

The client is organized into namespace objects that group related operations:

NamespaceMethodsAPI Reference
client.health()Server health check (no auth required)
client.authsetup, login, logout, refresh, changePassword, sessions, revokeSession, revokeAllSessionsAuthentication
client.chatsend, approve, resumeChat
client.threadslist, get, fork, deleteThreads
client.configget, updateConfiguration
client.pluginslistPlugins
client.mcpServerslist, addMCP Servers
client.modelslistPlugins
client.scheduledestinations, list, get, create, update, delete, heartbeat, updateHeartbeatSchedule
client.inboxlist, get, update, deleteInbox
client.memorygetWorkingMemory, updateWorkingMemory, getObservations, getRecordMemory

Error Handling

Non-2xx responses throw a PandoraApiError with status and body properties:

import { createClient, PandoraApiError } from '@pandorakit/sdk/client' const client = createClient({ /* ... */ }) try { await client.threads.get('nonexistent') } catch (err) { if (err instanceof PandoraApiError && err.status === 404) { console.log('Thread not found') } }

The chat namespace methods (send, approve, resume) return a raw Response with an SSE stream body instead of parsed JSON. These do not throw on non-2xx — check response.ok yourself.

API Types

All request and response types are also available from @pandorakit/sdk/api as a types-only entrypoint (zero runtime code):

import type { Config, Thread, ThreadListResponse, ThreadDetailResponse, UnifiedPluginInfo, ScheduleTask, InboxMessage, } from '@pandorakit/sdk/api'

See each API Reference page for the types relevant to that endpoint.

Examples

Listing threads

const { threads } = await client.threads.list() for (const thread of threads) { console.log(thread.id, thread.title) }

Updating configuration

const config = await client.config.update({ identity: { name: 'My Agent' }, models: { operator: { provider: 'anthropic', model: 'claude-sonnet-4-20250514' } }, })

Pass null for an optional field to delete it:

await client.config.update({ models: { operator: { temperature: null } }, })

Sending a chat message

The chat.send method returns a raw Response with an SSE stream. The thread ID is in the X-Thread-Id header:

const response = await client.chat.send({ parts: [{ type: 'text', text: 'Hello!' }], }) const threadId = response.headers.get('X-Thread-Id') // Read the stream const reader = response.body.getReader() const decoder = new TextDecoder() while (true) { const { done, value } = await reader.read() if (done) break console.log(decoder.decode(value, { stream: true })) }
Last updated on