Quickstart
Install the Polimorf SDK, authenticate with an API key, and run your first generation — streaming and non-streaming.
This guide takes you from nothing to a running generation. It uses the official
TypeScript SDK, @polimorfapp/sdk;
every call is also a plain HTTPS request you can make from any language (see the
API Reference).
Prerequisites
- Node.js 20 or newer — the SDK uses the built-in global
fetch. - An API key. Create one in your Polimorf dashboard. Keys look like
csk_live_…and carry theruntime:executescope by default. See Authentication for details. - A provider credential configured on your workspace (e.g. an OpenAI key), set in the dashboard — generations run against your own provider account.
1. Install the SDK
npm install @polimorfapp/sdk2. Configure credentials
The SDK reads your API key from the POLIMORF_API_KEY environment variable, so
you never hard-code it:
export POLIMORF_API_KEY="csk_live_your_key_here"By default the client talks to the managed API at https://api.polimorf.app. If
you self-host, set POLIMORF_BASE_URL (or pass baseUrl explicitly).
3. Run your first generation
There are two ways to run a generation. Start with whichever fits your setup.
Option A — Run a deployed assistant (recommended)
If your team has already published an assistant in the dashboard, call it by its slug. You send only the input; the provider, model, and prompt come from the published version — so your team can change them later without a code change.
import { createClient } from '@polimorfapp/sdk';
// apiKey and baseUrl are read from the environment when omitted.
const client = createClient();
const result = await client.assistant('support').run({
input: 'How do I cancel my subscription?',
});
console.log(result.message.content);
console.log('finish:', result.finishReason);
console.log('tokens:', result.usage.totalTokens);You can pass values for the version's declared prompt variables, and target a non-default environment:
const result = await client.assistant('support').run({
input: 'How do I cancel my subscription?',
variables: { plan: 'pro', locale: 'en-US' },
environment: 'production', // defaults to "production"
});Option B — Run an ad-hoc generation
If you want full control from the client, send the provider, model, and messages yourself:
import { createClient } from '@polimorfapp/sdk';
const client = createClient();
const result = await client.runtime.execute({
providerName: 'openai',
model: 'gpt-4o',
messages: [
{ role: 'system', content: 'You are a concise assistant.' },
{ role: 'user', content: 'Explain what an embedding is in one sentence.' },
],
config: { temperature: 0.2, maxOutputTokens: 200 },
});
console.log(result.message.content);4. Stream the response
For a typing-indicator experience, stream tokens as they are produced. Both
runtime.stream(...) and assistant(slug).stream(...) return an async iterable
of typed events — consume it with for await:
import { createClient } from '@polimorfapp/sdk';
const client = createClient();
for await (const event of client.assistant('support').stream({
input: 'Give me three tips for onboarding.',
})) {
switch (event.type) {
case 'delta':
process.stdout.write(event.content);
break;
case 'usage':
console.log('\ntokens:', event.usage.totalTokens);
break;
case 'done':
console.log('\nfinished:', event.finishReason);
break;
case 'error':
console.error('\nprovider error:', event.error.message);
break;
}
}A provider failure arrives as a terminal error event, not a thrown
exception — only a transport failure (network, timeout, abort) throws. See
Streaming for the full event contract.
5. Handle errors
Any non-2xx response is thrown as a typed PolimorfApiError subclass you can
branch on:
import {
createClient,
AuthenticationError,
RateLimitError,
} from '@polimorfapp/sdk';
const client = createClient();
try {
const result = await client.runtime.execute({
providerName: 'openai',
model: 'gpt-4o',
messages: [{ role: 'user', content: 'Hello' }],
});
console.log(result.message.content);
} catch (err) {
if (err instanceof AuthenticationError) {
// 401 — bad or missing API key
} else if (err instanceof RateLimitError) {
// 429 — back off and retry
} else {
throw err;
}
}The full catalog of error codes and status mappings is in Errors.