Skip to main content
Version: Next — unreleased

Make and troubleshoot an HTTP API request

Use this journey to connect your backend to Delphi's HTTP API and verify a read-only request before adding session or usage operations. The API origin is the deployment's TelAPI address, which can differ from TelWeb and the documentation address. Ask the deployment operator for that origin.

Availability: from 0.9.18, the operator must enable Browser SDK with FEATURE_BROWSER_SDK=true. Without it, the API serves no endpoint discovery, session, runtime-capability or usage routes, and no API-key access. The team also needs Browser SDK entitlement and the operation's allowed scopes. Browser voice additionally requires FEATURE_WEBRTC=true. A product login, documentation login and team API key are separate credentials. Use Manage team API keys to create, store, rotate and revoke keys.

The HTTP reference snapshot describes the 0.9.17-patch1 schema. For 0.9.18, use the API description that your deployment serves, as described in API description by capability profile.

API description by capability profile​

The API builds its OpenAPI description from the capabilities your deployment enables, so two deployments of 0.9.18 can publish different descriptions. The interactive view is served at /documentation when the operator enables it; it is off by default in production.

Enabled capabilityWhat the description and API include
None of the threeHealth checks only
Browser SDKAPI-key and bearer authentication, endpoints, sessions, runtime capabilities, TTS usage and the session channel message schema
Browser SDK and WebRTCAlso the voice upgrade and downgrade operations and the gateway fields of voice sessions

Feature availability lists the flags behind each capability. Generate client code from your own deployment's description, not from another installation.

Runtime capabilities and voice​

GET /api/v1/runtime/capabilities requires a key with CREATE_CALL_TOKEN. It reports voice only when two conditions hold: the deployment enables WebRTC, and the calling key grants the WebRTC channel. A key without a channel restriction counts as granting it. When either condition is missing, the response omits web_voice entry points and reports voice_conversation and voiceInvocable as false.

When an application offers both browser chat and browser voice, runtime.migration lists text_to_voice, voice_to_text and api_to_media. From 0.9.18 the enum includes voice_to_text; update clients that validate this field against a fixed list.

1. Select the operation and credential​

For the first check, use GET /api/v1/endpoints with a key containing READ_TEAM_APPS. This operation lists browser endpoints in the key's team, not all applications, telephone endpoints or another team's resources. You do not supply a team identifier to broaden the result.

Send the long-lived key in the X-API-Key header from your backend. Do not put it in browser code or a URL. A bearer/session token is not interchangeable with this key. If your following task is browser voice or chat, continue with the browser integration journey for scoped session credentials and readiness; listing an endpoint does not create or start a session.

2. Send a bounded read-only request​

This Node.js backend example reads configuration from your server environment, applies a ten-second client timeout and logs only a count and pagination metadata. Set DELPHI_API_ORIGIN to the operator-supplied HTTPS origin and keep DELPHI_API_KEY in your secret storage. The timeout is this client's choice, not a server timeout guarantee.

const origin = process.env.DELPHI_API_ORIGIN;
const key = process.env.DELPHI_API_KEY;
if (!origin || !key) throw new Error('Configure the API origin and team API key');
const url = new URL('/api/v1/endpoints?page=1&limit=20', origin);
const response = await fetch(url, {
headers: {'X-API-Key': key},
signal: AbortSignal.timeout(10_000),
});
const contentType = response.headers.get('content-type') || '';
const body = contentType.includes('application/json') ? await response.json() : null;
if (!response.ok) {
// Keep full response bodies and credentials out of routine logs.
const code = body?.error?.code || 'HTTP_ERROR';
const requestId = body?.error?.requestId || 'unavailable';
throw new Error(
`Endpoint request failed: HTTP ${response.status}; ${code}; request ${requestId}`,
);
}
if (!Array.isArray(body?.endpoints) || !body?.pagination) {
throw new Error('Unexpected endpoint response; check the API origin and deployed contract');
}
console.log({endpointCount: body.endpoints.length, pagination: body.pagination});

A 200 response contains endpoints and pagination. Each endpoint has an id and name; the name comes from its application and is not a unique identifier. Use the endpoint ID when another operation requires it. An empty array can be a valid result for a team without browser endpoints. Confirm the selected team and application entry points before replacing the key.

A proxy or another server can return HTML or a different error body. Check the HTTP status and content type before assuming every response uses the TelAPI JSON envelope. A successful login page is not a successful API response.

3. Read further pages deliberately​

page is one-based and defaults to 1; limit defaults to 20 and must be between 1 and 100. Use positive integer query values. Invalid values, including zero or an excessive limit, are rejected rather than silently clamped.

The response's pagination contains total, page, limit and totalPages. When the total is zero, totalPages is zero. Continue only while the returned page is below totalPages; a page beyond the available results can return an empty array.

This is offset pagination, not a stable snapshot or cursor. The query does not declare a stable ordering, and the count and page reads are separate. If endpoints change while you read, do not assume a complete, duplicate-free export. For application selection, prefer storing the chosen endpoint ID and reconciling it when configuration changes rather than continually rebuilding identity from display names.

4. Interpret errors before retrying​

TelAPI's shared error handler returns an error object with code and message, and can include details and requestId. Details depend on the operation and error; do not require a fixed structure or display raw details to an end user. A request identifier helps an operator correlate logs; it is not a call ID or session credential.

HTTP resultMeaning and what to do
400 / VALIDATION_ERRORCorrect the query or body according to the operation. Retrying the same invalid input does not help.
401 / AUTHENTICATION_ERRORCheck missing, inactive, expired or invalid key, team state and entitlement. The team daily request allowance can also be rejected through authentication, so read the safe message before assuming the secret is wrong.
403 / AUTHORIZATION_ERRORCheck required scope and operation-specific authority. Repeated requests cannot add permission.
404 / NOT_FOUNDA shared-handler resource error can use NOT_FOUND. Check origin, path, route availability and resource identifier; routing and proxy 404 responses can have a different body.
409 / CONFLICTWhere the operation uses this error, reconcile its current state before attempting a conflicting change again.
429 / RATE_LIMIT_EXCEEDEDStop immediate retries. Honor Retry-After when supplied and inspect whether the cause is request rate or repeated credential failures.
500 / INTERNAL_ERROR, network error or client timeoutCapture safe context and investigate. A failed response does not establish whether a state-changing operation took effect.
503 / WEBRTC_DISABLED or TELPRO_UNCONFIGUREDA browser-voice operation can reject unavailable voice capability or gateway configuration. Ask the operator to correct availability; retrying cannot enable it. Other 503 responses can have different causes.

An IP-tier rate-limit response can include limiter-specific details, for example:

{
"error": {
"code": "RATE_LIMIT_EXCEEDED",
"message": "Too many requests",
"details": {"max": 600, "after": "1 minute", "ttlMs": 42000},
"requestId": "example-request"
}
}

The shared builder forwards the limiter's max and after values and includes ttlMs when a TTL was supplied. This is an illustrative shape, not your deployment's configured limit. Other errors or limiters need not provide these fields; use Retry-After when present and investigate the actual limit rather than parsing the human-readable message.

Per-IP request controls, the team's daily allowance and the credential-retry jail are separate limits. A credential jail can temporarily reject a valid replacement key from the same client IP; changing keys repeatedly is not a recovery strategy. Follow API rate-limit operations when multiple clients share an egress address or failures persist.

For an idempotent read, bounded retries with delay can be appropriate after a transient failure. Set your own retry cap and stop on validation, authentication or authorization failures. Do not automatically replay a session-creation or other state-changing request after a timeout. Check that operation's state and contract first; this guide does not promise a universal idempotency key or exactly-once execution.

Read team TTS usage​

Use GET /api/v1/usage/tts-characters with a backend API key containing READ_TEAM_USAGE to retrieve the calling team's recorded TTS character totals. The team comes from the key; a query parameter cannot select another team. Applications excluded from the dashboard are excluded from this aggregate too. These are character counts, not a currency invoice or proof that every provider has reported final usage.

Query fieldMeaning
fromOptional ISO 8601 date-time, inclusive start of the usage-event window. Defaults to the Unix epoch.
toOptional ISO 8601 date-time, inclusive end of the window. Defaults to the request's current time.
timeframeday, week, month or total; defaults to total. This is an echoed label and does not select or shorten the time window.

For a monthly report, send explicit from and to values; timeframe=month alone still uses the default all-time window. Either bound can be supplied alone. Invalid dates or labels and a start later than the end return validation errors. Both bounds are inclusive: avoid counting events on a shared boundary twice when combining adjacent windows.

GET /api/v1/usage/tts-characters?from=2026-06-01T00%3A00%3A00.000Z&to=2026-06-30T23%3A59%3A59.999Z&timeframe=month
X-API-Key: <server-side-team-key>
Response fieldMeaning
teamIdTeam associated with the calling key.
timeframeEffective label, independent of the date bounds.
from, toResolved report bounds as ISO date-times.
charactersTotalRecorded total TTS characters in the window.
charactersFromCacheRecorded characters served from the TTS cache.
charactersGeneratedRecorded characters generated by an upstream provider.
cacheHitRatioCached characters divided by total characters, rounded to four decimal places; zero when the total is zero.

An empty result returns zero totals. If figures differ from an expected dashboard view, check the team, explicit date window, application exclusions and when usage was recorded before changing credentials. Use API key administration to grant reporting scope and dashboard reporting to interpret the UI view.

5. Verify the intended integration, then hand over​

A successful endpoint list proves that this key, team, route and request worked at that time. It does not prove a browser session can start, a provider is configured, a SIP call can connect or a later write is permitted.

  • For browser sessions, use session readiness, events and recovery.
  • For key lifecycle and scope changes, return to API key administration.
  • For missing endpoints, verify the app's channel and binding.
  • For persistent failures, give the operator the deployment, operation, HTTP status/code, approximate time and safe request identifier. Do not include a key, authorization header, full response payload or customer conversation content. Use logs and traces to correlate the request without assuming its request ID is a call's correlation identifier.