Complete API documentation for managing SIP trunks and phone numbers programmatically. Automate your voice infrastructure with VoxPria’s RESTful API.
Authentication #
All API requests require authentication using an API key in the Authorization header.
Getting Your API Key #
- Log into VoxPria dashboard
- Navigate to Settings → API Keys
- Click Generate New Key
- Copy and store securely
- Use in Authorization header
Authentication Format #
`bash
Authorization: Bearer YOUR_API_KEY
`
Example Request #
`bash
curl -X GET https://api.voxpria.com/v1/sip/trunks \
-H “Authorization: Bearer vox_sk_test_abc123xyz789”
`
Base URL #
`
https://api.voxpria.com/v1
`
All endpoints are relative to this base URL.
SIP Trunks #
List SIP Trunks #
Retrieve all SIP trunks in your account.
Endpoint: GET /sip/trunks
Response:
`json
{
“data”: [
{
“id”: “trunk_abc123”,
“name”: “My ElevenLabs Trunk”,
“provider”: “elevenlabs”,
“status”: “active”,
“created_at”: “2024-01-15T10:30:00Z”,
“phone_numbers_count”: 5
}
],
“pagination”: {
“page”: 1,
“per_page”: 20,
“total”: 3
}
}
`
Query Parameters:
page(integer) – Page number (default: 1)per_page(integer) – Results per page (default: 20, max: 100)provider(string) – Filter by provider type
Example:
`bash
curl -X GET “https://api.voxpria.com/v1/sip/trunks?provider=elevenlabs” \
-H “Authorization: Bearer YOUR_API_KEY”
`
Create SIP Trunk #
Create a new SIP trunk connection.
Endpoint: POST /sip/trunks
Request Body:
ElevenLabs Trunk:
`json
{
“name”: “Production ElevenLabs”,
“provider”: “elevenlabs”,
“credentials”: {
“username”: “your_elevenlabs_username”,
“password”: “your_elevenlabs_password”
},
“config”: {
“server”: “sip.rtc.elevenlabs.io”,
“port”: 5061,
“transport”: “tls”
}
}
`
OpenAI Trunk:
`json
{
“name”: “Production OpenAI”,
“provider”: “openai”,
“credentials”: {
“project_id”: “proj_abc123”,
“api_key”: “sk-proj-xyz789”,
“webhook_secret”: “whsec_def456”
}
}
`
Generic Trunk:
`json
{
“name”: “Custom SIP Provider”,
“provider”: “generic”,
“credentials”: {
“username”: “sip_username”,
“password”: “sip_password”
},
“config”: {
“server”: “sip.example.com”,
“port”: 5060,
“transport”: “tcp”
}
}
`
Response:
`json
{
“id”: “trunk_abc123”,
“name”: “Production ElevenLabs”,
“provider”: “elevenlabs”,
“status”: “active”,
“created_at”: “2024-01-15T10:30:00Z”
}
`
Status Codes:
201 Created– Trunk created successfully400 Bad Request– Invalid parameters401 Unauthorized– Invalid API key409 Conflict– Trunk name already exists
Get SIP Trunk #
Retrieve details for a specific trunk.
Endpoint: GET /sip/trunks/{trunk_id}
Response:
`json
{
“id”: “trunk_abc123”,
“name”: “Production ElevenLabs”,
“provider”: “elevenlabs”,
“status”: “active”,
“config”: {
“server”: “sip.rtc.elevenlabs.io”,
“port”: 5061,
“transport”: “tls”
},
“phone_numbers”: [
{
“id”: “phone_def456”,
“number”: “+12125551234”,
“status”: “active”
}
],
“created_at”: “2024-01-15T10:30:00Z”,
“updated_at”: “2024-01-20T14:20:00Z”
}
`
Note: Credentials are not returned for security.
Update SIP Trunk #
Update trunk configuration or credentials.
Endpoint: PATCH /sip/trunks/{trunk_id}
Request Body:
`json
{
“name”: “Updated Trunk Name”,
“credentials”: {
“password”: “new_password”
},
“config”: {
“transport”: “tls”
}
}
`
Response:
`json
{
“id”: “trunk_abc123”,
“name”: “Updated Trunk Name”,
“provider”: “elevenlabs”,
“status”: “active”,
“updated_at”: “2024-01-20T15:00:00Z”
}
`
Note: After updating credentials, re-provision affected phone numbers.
Delete SIP Trunk #
Delete a trunk and remove all associated phone numbers.
Endpoint: DELETE /sip/trunks/{trunk_id}
Response:
`json
{
“success”: true,
“message”: “Trunk deleted successfully”
}
`
Status Codes:
200 OK– Trunk deleted404 Not Found– Trunk doesn’t exist409 Conflict– Trunk has active phone numbers (remove first)
Provision Trunk (OpenAI) #
Provision an OpenAI trunk at project level.
Endpoint: POST /sip/trunks/{trunk_id}/provision
Response:
`json
{
“success”: true,
“status”: “provisioned”,
“provisioned_at”: “2024-01-20T16:00:00Z”
}
`
Note: Only required for OpenAI trunks. Provisions entire project.
Phone Numbers #
List Phone Numbers #
Retrieve all phone numbers in your account.
Endpoint: GET /phone-numbers
Response:
`json
{
“data”: [
{
“id”: “phone_abc123”,
“number”: “+12125551234”,
“trunk_id”: “trunk_def456”,
“engine”: “elevenlabs”,
“status”: “active”,
“agent_id”: “agent_ghi789”,
“capabilities”: {
“inbound”: true,
“outbound”: true,
“campaigns”: true
},
“created_at”: “2024-01-15T10:30:00Z”
}
],
“pagination”: {
“page”: 1,
“per_page”: 20,
“total”: 15
}
}
`
Query Parameters:
page(integer) – Page numberper_page(integer) – Results per pagetrunk_id(string) – Filter by trunkstatus(string) – Filter by status:active,inactive,provisioningengine(string) – Filter by engine:elevenlabs,openai
Import Phone Number #
Add a phone number to VoxPria.
Endpoint: POST /phone-numbers/import
Request Body:
`json
{
“phone_number”: “+12125551234”,
“trunk_id”: “trunk_abc123”,
“engine”: “elevenlabs”,
“agent_id”: “agent_def456”,
“config”: {
“first_message”: “Hello! How can I help you today?”,
“max_duration”: 3600,
“language”: “en-US”
}
}
`
Response:
`json
{
“id”: “phone_abc123”,
“number”: “+12125551234”,
“trunk_id”: “trunk_def456”,
“engine”: “elevenlabs”,
“status”: “provisioning”,
“agent_id”: “agent_ghi789”,
“created_at”: “2024-01-20T10:00:00Z”
}
`
Status Codes:
201 Created– Number imported successfully400 Bad Request– Invalid phone number format409 Conflict– Number already exists429 Too Many Requests– Rate limit exceeded (10/minute)
Rate Limiting:
- Maximum 10 imports per minute per user
- HTTP 429 returned when exceeded
- Wait 60 seconds before retrying
Get Phone Number #
Retrieve details for a specific phone number.
Endpoint: GET /phone-numbers/{phone_id}
Response:
`json
{
“id”: “phone_abc123”,
“number”: “+12125551234”,
“trunk_id”: “trunk_def456”,
“trunk_name”: “My ElevenLabs Trunk”,
“engine”: “elevenlabs”,
“status”: “active”,
“agent_id”: “agent_ghi789”,
“agent_name”: “Customer Support Agent”,
“config”: {
“first_message”: “Hello! How can I help you today?”,
“max_duration”: 3600,
“language”: “en-US”
},
“capabilities”: {
“inbound”: true,
“outbound”: true,
“campaigns”: true,
“recordings”: true
},
“stats”: {
“total_calls”: 127,
“total_minutes”: 423.5,
“last_call_at”: “2024-01-20T14:30:00Z”
},
“created_at”: “2024-01-15T10:30:00Z”,
“updated_at”: “2024-01-20T14:30:00Z”
}
`
Update Phone Number #
Update phone number configuration.
Endpoint: PATCH /phone-numbers/{phone_id}
Request Body:
`json
{
“agent_id”: “agent_new789”,
“config”: {
“first_message”: “Updated greeting message”,
“max_duration”: 1800
}
}
`
Response:
`json
{
“id”: “phone_abc123”,
“number”: “+12125551234”,
“status”: “active”,
“agent_id”: “agent_new789”,
“updated_at”: “2024-01-20T16:00:00Z”
}
`
Delete Phone Number #
Remove a phone number from VoxPria.
Endpoint: DELETE /phone-numbers/{phone_id}
Response:
`json
{
“success”: true,
“message”: “Phone number deleted successfully”
}
`
Note: This removes the number from VoxPria but doesn’t cancel with provider.
Provision Phone Number #
Provision a phone number (ElevenLabs only).
Endpoint: POST /phone-numbers/{phone_id}/provision
Response:
`json
{
“success”: true,
“status”: “active”,
“provisioned_at”: “2024-01-20T16:30:00Z”
}
`
Note: Required after importing ElevenLabs numbers. OpenAI uses project-level provisioning.
Bulk Operations #
Re-provision All Numbers (Trunk) #
Re-provision all numbers on a trunk after credential updates.
Endpoint: POST /sip/trunks/{trunk_id}/reprovision-all
Response:
`json
{
“success”: true,
“total_numbers”: 5,
“provisioned”: 5,
“failed”: 0
}
`
Bulk Import Numbers #
Import multiple numbers at once.
Endpoint: POST /phone-numbers/bulk-import
Request Body:
`json
{
“trunk_id”: “trunk_abc123”,
“engine”: “elevenlabs”,
“numbers”: [
{
“phone_number”: “+12125551234”,
“agent_id”: “agent_def456”
},
{
“phone_number”: “+12125555678”,
“agent_id”: “agent_def456”
}
]
}
`
Response:
`json
{
“success”: true,
“imported”: 2,
“failed”: 0,
“results”: [
{
“phone_number”: “+12125551234”,
“status”: “success”,
“id”: “phone_abc123”
},
{
“phone_number”: “+12125555678”,
“status”: “success”,
“id”: “phone_abc124”
}
]
}
`
Rate Limiting:
- Subject to standard import rate limits
- Failed imports don’t count toward limit
- Respects 10 imports per minute
Call Logs #
List Call Logs #
Retrieve call history for your phone numbers.
Endpoint: GET /calls
Response:
`json
{
“data”: [
{
“id”: “call_abc123”,
“phone_number”: “+12125551234”,
“direction”: “inbound”,
“from”: “+13035559876”,
“to”: “+12125551234”,
“agent_id”: “agent_def456”,
“status”: “completed”,
“duration”: 127,
“started_at”: “2024-01-20T14:00:00Z”,
“ended_at”: “2024-01-20T14:02:07Z”,
“recording_url”: “https://recordings.voxpria.com/abc123.mp3”,
“transcript_available”: true
}
],
“pagination”: {
“page”: 1,
“per_page”: 20,
“total”: 342
}
}
`
Query Parameters:
page(integer) – Page numberper_page(integer) – Results per pagephone_number(string) – Filter by phone numberdirection(string) – Filter:inbound,outboundstatus(string) – Filter:completed,failed,no-answerstart_date(string) – ISO 8601 date (e.g.,2024-01-15)end_date(string) – ISO 8601 date
Example:
`bash
curl -X GET “https://api.voxpria.com/v1/calls?phone_number=%2B12125551234&start_date=2024-01-15” \
-H “Authorization: Bearer YOUR_API_KEY”
`
Get Call Details #
Retrieve detailed information about a specific call.
Endpoint: GET /calls/{call_id}
Response:
`json
{
“id”: “call_abc123”,
“phone_number”: “+12125551234”,
“direction”: “inbound”,
“from”: “+13035559876”,
“to”: “+12125551234”,
“agent_id”: “agent_def456”,
“agent_name”: “Customer Support Agent”,
“status”: “completed”,
“duration”: 127,
“started_at”: “2024-01-20T14:00:00Z”,
“ended_at”: “2024-01-20T14:02:07Z”,
“recording_url”: “https://recordings.voxpria.com/abc123.mp3”,
“transcript”: {
“segments”: [
{
“speaker”: “agent”,
“text”: “Hello! How can I help you today?”,
“timestamp”: “2024-01-20T14:00:02Z”
},
{
“speaker”: “caller”,
“text”: “I need help with my account.”,
“timestamp”: “2024-01-20T14:00:05Z”
}
]
},
“metadata”: {
“caller_location”: “Denver, CO”,
“call_quality”: “excellent”
}
}
`
Webhooks #
Configure webhooks to receive real-time notifications.
Webhook Events #
Available event types:
call.started– Call initiatedcall.ended– Call completedcall.failed– Call failed to connectnumber.provisioned– Number successfully provisionedtrunk.updated– Trunk configuration changed
Webhook Payload #
Example call.ended webhook:
`json
{
“event”: “call.ended”,
“timestamp”: “2024-01-20T14:02:07Z”,
“data”: {
“call_id”: “call_abc123”,
“phone_number”: “+12125551234”,
“direction”: “inbound”,
“status”: “completed”,
“duration”: 127,
“recording_url”: “https://recordings.voxpria.com/abc123.mp3”
}
}
`
Configure Webhook #
Endpoint: POST /webhooks
Request Body:
`json
{
“url”: “https://your-app.com/webhooks/voxpria”,
“events”: [“call.started”, “call.ended”],
“secret”: “your_webhook_secret”
}
`
Response:
`json
{
“id”: “webhook_abc123”,
“url”: “https://your-app.com/webhooks/voxpria”,
“events”: [“call.started”, “call.ended”],
“status”: “active”,
“created_at”: “2024-01-20T10:00:00Z”
}
`
Verify Webhook Signatures #
Webhooks include X-VoxPria-Signature header for verification.
Example Verification (Node.js):
`javascript
const crypto = require(‘crypto’);
function verifyWebhook(payload, signature, secret) {
const hmac = crypto.createHmac(‘sha256’, secret);
const digest = hmac.update(JSON.stringify(payload)).digest(‘hex’);
return crypto.timingSafeEqual(
Buffer.from(signature),
Buffer.from(digest)
);
}
`
Error Handling #
Error Response Format #
`json
{
“error”: {
“code”: “invalid_phone_number”,
“message”: “Phone number must be in E.164 format”,
“details”: {
“field”: “phone_number”,
“provided”: “2125551234”
}
}
}
`
Common Error Codes #
400 Bad Request:
invalid_phone_number– Phone number format incorrectinvalid_credentials– SIP credentials invalidmissing_required_field– Required field not provided
401 Unauthorized:
invalid_api_key– API key invalid or expiredapi_key_missing– No API key provided
403 Forbidden:
insufficient_permissions– API key lacks required permissionsfeature_not_enabled– SIP features not available on plan
404 Not Found:
trunk_not_found– Trunk ID doesn’t existphone_not_found– Phone number doesn’t exist
409 Conflict:
trunk_name_exists– Trunk name already in usephone_number_exists– Number already imported
429 Too Many Requests:
rate_limit_exceeded– Too many requests, slow downimport_limit_exceeded– Phone import rate limit hit
500 Internal Server Error:
server_error– Internal server issueprovisioning_failed– Provider provisioning failed
Rate Limits #
Current Limits #
| Endpoint | Limit | Window |
|———-|——-|——–|
| Phone Import | 10 requests | 1 minute |
| General API | 1000 requests | 1 hour |
| Webhooks | 100 deliveries | 1 minute |
Rate Limit Headers #
`
X-RateLimit-Limit: 10
X-RateLimit-Remaining: 7
X-RateLimit-Reset: 1234567890
`
Handling Rate Limits #
When you receive HTTP 429:
- Read
X-RateLimit-Resetheader - Wait until reset timestamp
- Retry request
- Implement exponential backoff
Example:
`javascript
async function importWithRetry(phoneNumber, maxRetries = 3) {
for (let i = 0; i < maxRetries; i++) {
try {
return await importPhoneNumber(phoneNumber);
} catch (error) {
if (error.status === 429) {
const resetTime = error.headers[‘x-ratelimit-reset’];
const waitTime = resetTime – Date.now() / 1000;
await sleep(waitTime * 1000);
continue;
}
throw error;
}
}
}
`
SDK Examples #
Node.js #
`javascript
const VoxPria = require(‘@voxpria/sdk’);
const client = new VoxPria({
apiKey: ‘vox_sk_test_abc123’
});
// Create trunk
const trunk = await client.trunks.create({
name: ‘My ElevenLabs Trunk’,
provider: ‘elevenlabs’,
credentials: {
username: ‘username’,
password: ‘password’
}
});
// Import number
const phone = await client.phoneNumbers.import({
phoneNumber: ‘+12125551234’,
trunkId: trunk.id,
engine: ‘elevenlabs’,
agentId: ‘agent_abc123’
});
// Provision number
await client.phoneNumbers.provision(phone.id);
// List calls
const calls = await client.calls.list({
phoneNumber: ‘+12125551234’,
startDate: ‘2024-01-15’
});
`
Python #
`python
from voxpria import VoxPria
client = VoxPria(api_key=’vox_sk_test_abc123′)
Create trunk #
trunk = client.trunks.create(
name=’My ElevenLabs Trunk’,
provider=’elevenlabs’,
credentials={
‘username’: ‘username’,
‘password’: ‘password’
}
)
Import number #
phone = client.phone_numbers.import_number(
phone_number=’+12125551234′,
trunk_id=trunk.id,
engine=’elevenlabs’,
agent_id=’agent_abc123′
)
Provision number #
client.phone_numbers.provision(phone.id)
List calls #
calls = client.calls.list(
phone_number=’+12125551234′,
start_date=’2024-01-15′
)
`
Testing #
Sandbox Environment #
Test API integration without affecting production:
`
Base URL: https://api.sandbox.voxpria.com/v1
`
Use test API keys:
`
vox_sk_test_abc123xyz789
`
Test Credentials #
Sandbox includes test SIP credentials:
- Username:
test_user - Password:
test_pass - Server:
sip.test.voxpria.com
Test Phone Numbers #
Use these numbers for testing:
+15555551234– Always succeeds+15555551235– Always fails provisioning+15555551236– Simulates slow provisioning
Best Practices #
API Keys #
- Use separate keys for development and production
- Rotate keys regularly
- Never commit keys to version control
- Use environment variables
Error Handling #
- Implement retry logic with exponential backoff
- Log errors for debugging
- Handle rate limits gracefully
- Validate data before API calls
Performance #
- Cache trunk and phone number data
- Use pagination for large result sets
- Batch operations when possible
- Monitor API response times
Security #
- Use HTTPS for all requests
- Verify webhook signatures
- Implement IP allowlisting if available
- Monitor API usage for anomalies
Support #
- API Documentation: https://voxpria.com/api
- Status Page: https://status.voxpria.com
- Support Email: support@voxpria.com
- Community Forum: https://community.voxpria.com
For urgent API issues, contact support with:
- Request ID (from error response)
- Timestamp of request
- Expected vs actual behavior
- Sample code that reproduces issue
