Provider registry
6 endpoints. Every path below is relative to the API base URL and already includes the /api/v1 prefix — see conventions for authentication, pagination, errors and idempotency.
| Endpoint | ||
|---|---|---|
| GET | /registry | The whole registry in one call: providers, models, voices, telephony |
| GET | /registry/model-providers | LLM providers that CallAgent can actually talk to today |
| GET | /registry/models | List LLM models with capability, context window and pricing metadata, filterable by provider |
| GET | /registry/telephony | Telephony providers and what each one can do (§8) |
| GET | /registry/transcribers | Transcriber providers and their models (§27) |
| GET | /registry/voices | The voice catalogue plus this organization's cloned voices (§28) |
Endpoints
The whole registry in one call: providers, models, voices, telephony
GET/registry
- No scope is enforced in the handler — any valid key may call it.
bash
curl -X GET "$CALLAGENT_API_URL/registry" \
-H "Authorization: Bearer $CALLAGENT_API_KEY" \
-H "Accept: application/json"js
const response = await fetch(`${process.env.CALLAGENT_API_URL}/registry`, {
method: 'GET',
headers: {
Authorization: `Bearer ${process.env.CALLAGENT_API_KEY}`,
Accept: 'application/json',
},
});
if (!response.ok) {
const { error } = await response.json();
throw new Error(`${error.type}: ${error.message}`);
}
const { data } = await response.json();php
<?php
$handle = curl_init(getenv('CALLAGENT_API_URL') . '/registry');
curl_setopt_array($handle, [
CURLOPT_CUSTOMREQUEST => 'GET',
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . getenv('CALLAGENT_API_KEY'),
'Accept: application/json',
],
]);
$body = json_decode(curl_exec($handle), true);
$status = curl_getinfo($handle, CURLINFO_HTTP_CODE);
curl_close($handle);
if ($status >= 400) {
throw new RuntimeException("{$body['error']['type']}: {$body['error']['message']}");
}
$data = $body['data'];python
import os, requests
response = requests.get(
f"{os.environ['CALLAGENT_API_URL']}/registry",
headers={"Authorization": f"Bearer {os.environ['CALLAGENT_API_KEY']}"},
timeout=30,
)
response.raise_for_status()
data = response.json()["data"]Responses
| Status | Body |
|---|---|
200 | data-wrapped object |
Example response, generated from the schema:
json
{
"data": {
"model_providers": [
{}
],
"transcriber_providers": [
{}
],
"voice_providers": [
{}
],
"telephony_providers": [
{}
]
}
}LLM providers that CallAgent can actually talk to today
GET/registry/model-providers
- No scope is enforced in the handler — any valid key may call it.
bash
curl -X GET "$CALLAGENT_API_URL/registry/model-providers" \
-H "Authorization: Bearer $CALLAGENT_API_KEY" \
-H "Accept: application/json"js
const response = await fetch(`${process.env.CALLAGENT_API_URL}/registry/model-providers`, {
method: 'GET',
headers: {
Authorization: `Bearer ${process.env.CALLAGENT_API_KEY}`,
Accept: 'application/json',
},
});
if (!response.ok) {
const { error } = await response.json();
throw new Error(`${error.type}: ${error.message}`);
}
const { data } = await response.json();php
<?php
$handle = curl_init(getenv('CALLAGENT_API_URL') . '/registry/model-providers');
curl_setopt_array($handle, [
CURLOPT_CUSTOMREQUEST => 'GET',
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . getenv('CALLAGENT_API_KEY'),
'Accept: application/json',
],
]);
$body = json_decode(curl_exec($handle), true);
$status = curl_getinfo($handle, CURLINFO_HTTP_CODE);
curl_close($handle);
if ($status >= 400) {
throw new RuntimeException("{$body['error']['type']}: {$body['error']['message']}");
}
$data = $body['data'];python
import os, requests
response = requests.get(
f"{os.environ['CALLAGENT_API_URL']}/registry/model-providers",
headers={"Authorization": f"Bearer {os.environ['CALLAGENT_API_KEY']}"},
timeout=30,
)
response.raise_for_status()
data = response.json()["data"]Responses
| Status | Body |
|---|---|
200 | data-wrapped array |
Example response, generated from the schema:
json
{
"data": [
{
"slug": "string",
"name": "Support Line",
"api_style": "string",
"default_base_url": "https://example.com/hook",
"supports_byo_key": true,
"supports_custom_base_url": true,
"credential_fields": []
}
]
}List LLM models with capability, context window and pricing metadata, filterable by provider
GET/registry/models
- No scope is enforced in the handler — any valid key may call it.
- Query filters are
providerandvoice_only. pricing_verified:false means the price is unconfirmed and must be shown as an estimate.
Query parameters
| Name | Type | Required | Notes |
|---|---|---|---|
voice_only | boolean | — | default false |
bash
curl -X GET "$CALLAGENT_API_URL/registry/models?voice_only=false" \
-H "Authorization: Bearer $CALLAGENT_API_KEY" \
-H "Accept: application/json"js
const response = await fetch(`${process.env.CALLAGENT_API_URL}/registry/models?voice_only=false`, {
method: 'GET',
headers: {
Authorization: `Bearer ${process.env.CALLAGENT_API_KEY}`,
Accept: 'application/json',
},
});
if (!response.ok) {
const { error } = await response.json();
throw new Error(`${error.type}: ${error.message}`);
}
const { data } = await response.json();php
<?php
$handle = curl_init(getenv('CALLAGENT_API_URL') . '/registry/models?voice_only=false');
curl_setopt_array($handle, [
CURLOPT_CUSTOMREQUEST => 'GET',
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . getenv('CALLAGENT_API_KEY'),
'Accept: application/json',
],
]);
$body = json_decode(curl_exec($handle), true);
$status = curl_getinfo($handle, CURLINFO_HTTP_CODE);
curl_close($handle);
if ($status >= 400) {
throw new RuntimeException("{$body['error']['type']}: {$body['error']['message']}");
}
$data = $body['data'];python
import os, requests
response = requests.get(
f"{os.environ['CALLAGENT_API_URL']}/registry/models?voice_only=false",
headers={"Authorization": f"Bearer {os.environ['CALLAGENT_API_KEY']}"},
timeout=30,
)
response.raise_for_status()
data = response.json()["data"]Responses
| Status | Body |
|---|---|
200 | data-wrapped array |
Example response, generated from the schema:
json
{
"data": [
{
"provider": "string",
"slug": "string",
"name": "Support Line",
"family": "string",
"capabilities": [],
"context_window": 1,
"max_output": 1,
"input_price_per_million": "string",
"output_price_per_million": "string",
"currency": "string",
"pricing_verified": true,
"recommended_for_voice": true,
"deprecated": true
}
]
}Telephony providers and what each one can do (§8)
GET/registry/telephony
- No scope is enforced in the handler — any valid key may call it.
bash
curl -X GET "$CALLAGENT_API_URL/registry/telephony" \
-H "Authorization: Bearer $CALLAGENT_API_KEY" \
-H "Accept: application/json"js
const response = await fetch(`${process.env.CALLAGENT_API_URL}/registry/telephony`, {
method: 'GET',
headers: {
Authorization: `Bearer ${process.env.CALLAGENT_API_KEY}`,
Accept: 'application/json',
},
});
if (!response.ok) {
const { error } = await response.json();
throw new Error(`${error.type}: ${error.message}`);
}
const { data } = await response.json();php
<?php
$handle = curl_init(getenv('CALLAGENT_API_URL') . '/registry/telephony');
curl_setopt_array($handle, [
CURLOPT_CUSTOMREQUEST => 'GET',
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . getenv('CALLAGENT_API_KEY'),
'Accept: application/json',
],
]);
$body = json_decode(curl_exec($handle), true);
$status = curl_getinfo($handle, CURLINFO_HTTP_CODE);
curl_close($handle);
if ($status >= 400) {
throw new RuntimeException("{$body['error']['type']}: {$body['error']['message']}");
}
$data = $body['data'];python
import os, requests
response = requests.get(
f"{os.environ['CALLAGENT_API_URL']}/registry/telephony",
headers={"Authorization": f"Bearer {os.environ['CALLAGENT_API_KEY']}"},
timeout=30,
)
response.raise_for_status()
data = response.json()["data"]Responses
| Status | Body |
|---|---|
200 | data-wrapped array |
Example response, generated from the schema:
json
{
"data": [
{
"slug": "string",
"name": "Support Line",
"supports_inbound": true,
"supports_outbound": true,
"supports_number_purchase": true,
"supports_sms": true,
"supports_sip_trunk": true,
"supports_media_streams": true,
"credential_fields": []
}
]
}Transcriber providers and their models (§27)
GET/registry/transcribers
- No scope is enforced in the handler — any valid key may call it.
- data is an object with providers and models, not a flat list. The
providerfilter narrows only models. pricing_verified:false marks an unconfirmed price.
bash
curl -X GET "$CALLAGENT_API_URL/registry/transcribers" \
-H "Authorization: Bearer $CALLAGENT_API_KEY" \
-H "Accept: application/json"js
const response = await fetch(`${process.env.CALLAGENT_API_URL}/registry/transcribers`, {
method: 'GET',
headers: {
Authorization: `Bearer ${process.env.CALLAGENT_API_KEY}`,
Accept: 'application/json',
},
});
if (!response.ok) {
const { error } = await response.json();
throw new Error(`${error.type}: ${error.message}`);
}
const { data } = await response.json();php
<?php
$handle = curl_init(getenv('CALLAGENT_API_URL') . '/registry/transcribers');
curl_setopt_array($handle, [
CURLOPT_CUSTOMREQUEST => 'GET',
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . getenv('CALLAGENT_API_KEY'),
'Accept: application/json',
],
]);
$body = json_decode(curl_exec($handle), true);
$status = curl_getinfo($handle, CURLINFO_HTTP_CODE);
curl_close($handle);
if ($status >= 400) {
throw new RuntimeException("{$body['error']['type']}: {$body['error']['message']}");
}
$data = $body['data'];python
import os, requests
response = requests.get(
f"{os.environ['CALLAGENT_API_URL']}/registry/transcribers",
headers={"Authorization": f"Bearer {os.environ['CALLAGENT_API_KEY']}"},
timeout=30,
)
response.raise_for_status()
data = response.json()["data"]Responses
| Status | Body |
|---|---|
200 | data-wrapped object |
Example response, generated from the schema:
json
{
"data": {
"providers": [
{}
],
"models": [
{}
]
}
}The voice catalogue plus this organization's cloned voices (§28)
GET/registry/voices
- No scope is enforced in the handler — any valid key may call it.
- Filterable with
provider. Cloned voices belonging to this organization are mixed into the same list, flagged by is_cloned.
bash
curl -X GET "$CALLAGENT_API_URL/registry/voices" \
-H "Authorization: Bearer $CALLAGENT_API_KEY" \
-H "Accept: application/json"js
const response = await fetch(`${process.env.CALLAGENT_API_URL}/registry/voices`, {
method: 'GET',
headers: {
Authorization: `Bearer ${process.env.CALLAGENT_API_KEY}`,
Accept: 'application/json',
},
});
if (!response.ok) {
const { error } = await response.json();
throw new Error(`${error.type}: ${error.message}`);
}
const { data } = await response.json();php
<?php
$handle = curl_init(getenv('CALLAGENT_API_URL') . '/registry/voices');
curl_setopt_array($handle, [
CURLOPT_CUSTOMREQUEST => 'GET',
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . getenv('CALLAGENT_API_KEY'),
'Accept: application/json',
],
]);
$body = json_decode(curl_exec($handle), true);
$status = curl_getinfo($handle, CURLINFO_HTTP_CODE);
curl_close($handle);
if ($status >= 400) {
throw new RuntimeException("{$body['error']['type']}: {$body['error']['message']}");
}
$data = $body['data'];python
import os, requests
response = requests.get(
f"{os.environ['CALLAGENT_API_URL']}/registry/voices",
headers={"Authorization": f"Bearer {os.environ['CALLAGENT_API_KEY']}"},
timeout=30,
)
response.raise_for_status()
data = response.json()["data"]Responses
| Status | Body |
|---|---|
200 | data-wrapped array |
Example response, generated from the schema:
json
{
"data": [
{
"provider": "string",
"voice_id": "01JQ0000000000000000000000",
"name": "Support Line",
"model": "string",
"gender": "string",
"accent": "string",
"languages": {},
"preview_url": "https://example.com/hook",
"is_cloned": true
}
]
}