Skip to main content

Examples

platform v0.9.11verified 2026-05-14

Concrete recipes that pull together the rest of this section. Each one is short, copy-pasteable, and links back to the conceptual pages where the fields are explained.

Pseudo-shapes

Until the generated reference lands, the exact path and field names below are written as placeholders (/v1/call-tokens, data: {...}). Replace them with the values from your platform's Swagger UI at /documentation (TelAPI ships it) once you confirm the version.

1. Mint a call token from a Node.js backend

import {fetch} from 'undici';

const API_BASE = process.env.TELAPI_BASE_URL!; // https://api.your-delphi.example
const API_KEY = process.env.TELAPI_KEY!;

async function mintCallToken(endpointId: string) {
const res = await fetch(`${API_BASE}/v1/call-tokens`, {
method: 'POST',
headers: {
Authorization: `Bearer ${API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({endpointId}),
});

if (!res.ok) {
const body = await res.text();
throw new Error(`Token mint failed: ${res.status} ${body}`);
}

return res.json() as Promise<{token: string; endpointId: string; expiresAt: string}>;
}

Then expose it to your client behind your own auth:

// Express-style handler
app.post('/api/browser-sdk/call-tokens', requireUser, async (req, res) => {
const {endpointId} = req.body;
const token = await mintCallToken(endpointId);
res.json(token);
});

See Call tokens for the lifecycle.

2. Use the minted token from the client SDK

import {DelphiClient} from '@ki-kombinat/delphi-client-js-sdk';

const client = new DelphiClient({baseUrl: 'https://api.your-delphi.example'});

async function startCall() {
const {token, endpointId} = await fetch('/api/browser-sdk/call-tokens', {
method: 'POST',
body: JSON.stringify({endpointId: 'ep_abc123'}),
headers: {'Content-Type': 'application/json'},
}).then((r) => r.json());

const session = await client.openVoiceCall({endpointId, token});
session.on('transcript', (t) => console.log('they said:', t.text));
session.on('end', () => console.log('call ended'));
}

The SDK handles the WebSocket channel on your behalf. See SDK quick start → Voice call for the full version.

3. Discover the team's apps before minting

When your backend picks the right app/endpoint dynamically rather than hard-coding an endpoint ID, give the key the READ_TEAM_APPS scope:

async function pickEndpoint(appName: string) {
const res = await fetch(`${API_BASE}/v1/apps`, {
headers: {Authorization: `Bearer ${API_KEY}`},
});
if (!res.ok) throw new Error(`list apps failed: ${res.status}`);
const apps = (await res.json()) as Array<{id: string; name: string; endpoints: {id: string}[]}>;
const app = apps.find((a) => a.name === appName);
return app?.endpoints[0]?.id;
}

Cache the result for the lifetime of your process; app metadata changes rarely.

4. Respond to an async LLM/tool request

This is the inbound /api/v1/webhooks/* endpoint. When Delphi calls your async LLM/tool, the original request gives you a callback URL and a one-shot callback token. Use both verbatim — do not invent your own.

import {fetch} from 'undici';

// Inside your async worker, after producing the answer
async function deliverAsyncResult(callback: {url: string; token: string}, result: unknown) {
const res = await fetch(callback.url, {
method: 'POST',
headers: {
'X-Delphi-Callback-Token': callback.token, // exact header name comes from the original request
'Content-Type': 'application/json',
},
body: JSON.stringify(result),
});

if (res.status === 410) {
// Conversation already ended — drop the result.
return;
}
if (!res.ok) {
// Retry with backoff (token is still valid within its TTL).
throw new Error(`callback failed: ${res.status}`);
}
}

The callback token is one-shot per work item and tied to the conversation that is waiting. Don't log it, don't reuse it. See Webhooks for the full model.

5. Retry with backoff and idempotency

async function callWithRetry<T>(fn: () => Promise<T>, max = 5): Promise<T> {
let attempt = 0;
let lastError: unknown;
while (attempt < max) {
try {
return await fn();
} catch (err: any) {
lastError = err;
const status = err?.status ?? 0;
const retryable = status === 429 || (status >= 500 && status < 600);
if (!retryable) throw err;
const delay = Math.min(8_000, 250 * 2 ** attempt) + Math.random() * 250;
await new Promise((r) => setTimeout(r, delay));
attempt++;
}
}
throw lastError;
}

See Errors for which codes are retryable.

6. Look up a request when something goes wrong

When you get a 5xx or unexpected 4xx from TelAPI:

  1. Capture the requestId from the response body.
  2. File a ticket per Getting help with the requestId, the time window, and a redacted sample of the request.
  3. Your platform operator can find the request directly in SigNoz — much faster than reconstructing from logs.

See also