API Overview
The Voice360 API v3 provides programmatic access to your Voice360 account for managing calls, queues, SMS, and user data.
Authentication
The Voice360 API uses API Key authentication for all requests. Pass your API key in the request headers for secure access.
How to Authenticate
API Key Authentication
Voice360 supports two types of API keys. Both use the same X-API-Key header:
User API Key
For individual users accessing their own data.
- Mobile apps
- Browser extensions
- Personal integrations
Only your own profile, numbers, and call history
abc123xyz...
Developer API Key
For account-level access to all data.
- Backend integrations
- Dashboards
- CRM integrations
All users, queues, and account-wide data
v360_dev_...
Quick Comparison
| Feature | User Key | Developer Key |
|---|---|---|
| Scope | Single user | Entire account |
| Access /user/* endpoints? | ✅ Yes | ❌ No |
| Access /queues, /availability? | ❌ No | ✅ Yes |
X-API-Key: your_api_key_here
💡 Pro Tip: Each endpoint in this documentation shows which key types it supports via colored badges. Look for User API Key or Developer API Key badges on each endpoint.
Rate Limit: 1000 requests per minute (applies to both key types)
Public Endpoints (No Authentication)
Limited endpoints available without authentication for status pages and public dashboards.
Available Endpoints:
- User availability status (online/offline only)
- Queue basic information
- Queue availability (agent counts)
Rate Limit: 100 requests per minute per IP
Base URL & Versioning
Production Environment
https://api.voice360.app/v3/voice
Response Format
All API responses follow a consistent JSON structure for predictable integration:
{
"result": {
// Response data goes here
},
"error": false,
"message": "Success",
"timestamp": "2024-01-15T10:30:00Z"
}
{
"result": null,
"error": true,
"message": "Invalid API key provided",
"error_code": "AUTH_INVALID_KEY",
"timestamp": "2024-01-15T10:30:00Z"
}
Response Fields
User Management Endpoints
Get real-time availability status for all users in an account. Shows online/offline state and active calls.
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| account_id | integer | Required | Your Voice360 account ID |
Response Fields
Example Response
{
"result": [
{
"pk": 123,
"presence_id": "1001",
"callerID": "John Smith",
"first_name": "John",
"last_name": "Smith",
"devices_registered": true,
"channels": [
{
"to": "5551234",
"from": "1001",
"call_seconds": 45,
"direction": "outbound"
}
]
}
],
"error": false,
"message": "User availability data"
}
Queue Operations
List all queues in your account. Internal system queues are automatically filtered out.
Response Example
{
"result": [
{
"pk": 100134,
"name": "100134",
"queue_name": "Sales Queue",
"extension": "8001",
"strategy": "ringall",
"musiconhold": "default",
"timeout": 20,
"retry": 5,
"wrapuptime": 10,
"maxlen": 0,
"joinempty": "yes",
"leavewhenempty": "no",
"ringinuse": "no"
},
{
"pk": 100135,
"name": "100135",
"queue_name": "Support Queue",
"extension": "8002",
"strategy": "fewestcalls",
"musiconhold": "default",
"timeout": 30,
"retry": 5,
"wrapuptime": 10,
"maxlen": 0,
"joinempty": "yes",
"leavewhenempty": "no",
"ringinuse": "no"
}
],
"error": false,
"message": "List of queues"
}
Get detailed information about a specific queue including configuration and assigned users.
Response Fields
Queue Availability
Get real-time agent availability metrics for all queues. Shows online agents and call activity.
Response Example
{
"result": [
{
"pk": 100134,
"name": "100134",
"queue_name": "Sales Queue",
"extension": "8001",
"is_ready": true,
"agents_online": 3,
"agents_available": 2,
"agents_on_call": 1,
"active_calls": 5
}
],
"error": false,
"message": "Queue availability data"
}
Get detailed availability for a specific queue.
Response Fields
Call Management
Initiate an outbound call from an extension to an external number.
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
| from | string | Required | Extension number making the call |
| to | string | Required | Destination phone number |
| caller_id | string | Optional caller ID to display | |
| recording | boolean | Enable call recording (default: false) |
Example Request
curl -X POST https://api.voice360.app/v3/voice/61/call/outbound \
-H "X-API-Key: your_api_key" \
-H "Content-Type: application/json" \
-d '{
"from": "1001",
"to": "+15551234567",
"caller_id": "+15559876543",
"recording": true
}'
Example Response
{
"result": {
"call_id": "c12345-67890-abcdef",
"status": "initiating",
"from": "1001",
"to": "+15551234567",
"timestamp": "2024-01-15T10:30:00Z"
},
"error": false,
"message": "Call initiated successfully"
}
SMS Services
Send an SMS message from your Voice360 phone number.
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
| from | string | Required | Your Voice360 phone number |
| to | string | Required | Recipient phone number |
| message | string | Required | SMS message content (max 160 chars) |
Example Request
const sendSMS = async () => {
const response = await fetch('https://api.voice360.app/v3/voice/61/sms/send', {
method: 'POST',
headers: {
'X-API-Key': 'your_api_key',
'Content-Type': 'application/json'
},
body: JSON.stringify({
from: '+15559876543',
to: '+15551234567',
message: 'Hello from Voice360!'
})
});
const result = await response.json();
console.log(result);
};
User Profile & Numbers
Get the authenticated user's profile and extension details including voicemail settings, call forwarding, and device information.
Response Fields
Example Response
{
"result": {
"pk": 123,
"asterisk_user_id": 456,
"presence_id": "1001",
"callerID": "John Smith",
"first_name": "John",
"last_name": "Smith",
"email": "john.smith@company.com",
"voicemail_enabled": true,
"forward_enabled": false,
"forward_number": null,
"time_zone": "America/New_York"
},
"error": false,
"message": "User profile details"
}
Get list of phone numbers (DIDs) assigned to the authenticated user for making calls and sending SMS.
Response Fields
Example Response
{
"result": [
{
"pk": 789,
"number": "+15551234567",
"friendly_name": "Main Business Line",
"sms_enabled": true,
"mms_enabled": true
},
{
"pk": 790,
"number": "+15559876543",
"friendly_name": "Support Line",
"sms_enabled": true,
"mms_enabled": false
}
],
"error": false,
"message": "List of phone numbers assigned to user"
}
Example Request
const getUserNumbers = async () => {
const response = await fetch('https://api.voice360.app/v3/voice/61/user/numbers', {
method: 'GET',
headers: {
'X-API-Key': 'your_api_key'
}
});
const result = await response.json();
console.log('My phone numbers:', result.result);
};
Webhooks
Webhooks allow you to receive real-time notifications when events occur in your Voice360 account. Configure a webhook URL to receive HTTP POST requests for events like incoming calls, SMS messages, and queue activity.
How Webhooks Work
- Configure a webhook in your Voice360 portal with your endpoint URL and event type
- When the event occurs, Voice360 sends an HTTP POST request to your URL with event data
- Your server processes the webhook payload and responds with 200 OK
- If delivery fails, Voice360 automatically retries based on your retry configuration
Available Event Types
Call Events
| INCOMING_EXTERNAL_CALL | Fires when an external call comes in |
| CALL_ENDED | Fires when any call ends |
| USER_DIAL | Fires when a user initiates an outbound call |
| USER_ANSWER | Fires when a user answers a call |
| USER_HANGUP | Fires when an outbound call ends |
SMS Events
| SMS_RECEIVED | Fires when an SMS is received |
| SMS_SENT | Fires when an SMS is sent |
| SMS_DELIVERED | Fires when carrier confirms delivery |
Queue Events
| QUEUE_NO_ANSWER | Call not answered by any agent |
| QUEUE_HANGUP_TIMEOUT | Caller times out waiting in queue |
| QUEUE_HANGUP_ABANDONED | Caller hangs up while waiting |
Example Webhook Payload
{
"event_name": "SMS_RECEIVED",
"account_id": "12345",
"timestamp": 1704067200,
"metadata": {
"from_number": "+15551234567",
"to_number": "+15559876543",
"body": "Hello, this is a test message",
"message_id": "msg_abc123"
}
}
Configuring Webhooks
Webhooks are configured through the Voice360 portal at Settings → Webhooks. For each webhook, you'll configure:
- Name: Descriptive name for the webhook
- URL: Your endpoint URL (must be HTTPS in production)
- Event Type: Which event to listen for
- HTTP Method: GET or POST (POST recommended)
- Retries: Number of retry attempts (1-5)
Best Practices
- Always respond with 200 OK quickly (process asynchronously if needed)
- Validate webhook payloads came from Voice360 (check source IP or add auth tokens to your URL)
- Use HTTPS endpoints in production
- Implement idempotency - you may receive the same event multiple times
- Log all webhook requests for debugging
Code Examples
Complete examples showing how to integrate with the Voice360 API in popular programming languages.
#!/bin/bash
# Set your API credentials
API_KEY="your_api_key"
ACCOUNT_ID="61"
BASE_URL="https://api.voice360.app/v3/voice"
# Get user availability
echo "Fetching user availability..."
curl -H "X-API-Key: $API_KEY" \
"$BASE_URL/$ACCOUNT_ID/availability"
# List all queues
echo "Fetching queues..."
curl -H "X-API-Key: $API_KEY" \
"$BASE_URL/$ACCOUNT_ID/queues"
# Get queue availability
echo "Fetching queue availability..."
curl -H "X-API-Key: $API_KEY" \
"$BASE_URL/$ACCOUNT_ID/availability/queues"
# Initiate an outbound call
echo "Initiating outbound call..."
curl -X POST "$BASE_URL/$ACCOUNT_ID/call/outbound" \
-H "X-API-Key: $API_KEY" \
-H "Content-Type: application/json" \
-d '{
"from": "1001",
"to": "+15551234567",
"recording": true
}'
class Voice360API {
constructor(apiKey, accountId) {
this.apiKey = apiKey;
this.accountId = accountId;
this.baseUrl = 'https://api.voice360.app/v3/voice';
}
async request(endpoint, options = {}) {
const url = `${this.baseUrl}/${this.accountId}${endpoint}`;
const response = await fetch(url, {
...options,
headers: {
'X-API-Key': this.apiKey,
'Content-Type': 'application/json',
...options.headers
}
});
if (!response.ok) {
throw new Error(`API Error: ${response.status} ${response.statusText}`);
}
return response.json();
}
// User methods
async getUserAvailability() {
return this.request('/availability');
}
// Queue methods
async getQueues() {
return this.request('/queues');
}
async getQueueDetails(queueId) {
return this.request(`/queues/${queueId}`);
}
async getQueueAvailability(queueId = null) {
const endpoint = queueId
? `/availability/queues/${queueId}`
: '/availability/queues';
return this.request(endpoint);
}
// Call methods
async initiateCall(from, to, options = {}) {
return this.request('/call/outbound', {
method: 'POST',
body: JSON.stringify({ from, to, ...options })
});
}
// SMS methods
async sendSMS(from, to, message) {
return this.request('/sms/send', {
method: 'POST',
body: JSON.stringify({ from, to, message })
});
}
}
// Usage example
async function main() {
const api = new Voice360API('your_api_key', 61);
try {
// Get all online users
const availability = await api.getUserAvailability();
const onlineUsers = availability.result.filter(u => u.devices_registered);
console.log(`${onlineUsers.length} users online`);
// Check queue status
const queues = await api.getQueueAvailability();
const readyQueues = queues.result.filter(q => q.is_ready);
console.log(`${readyQueues.length} queues have agents available`);
// Make an outbound call
const call = await api.initiateCall('1001', '+15551234567', {
caller_id: '+15559876543',
recording: true
});
console.log(`Call initiated: ${call.result.call_id}`);
} catch (error) {
console.error('API Error:', error);
}
}
main();
import requests
import json
from typing import Optional, Dict, Any
class Voice360API:
"""Voice360 API Client for Python"""
def __init__(self, api_key: str, account_id: int):
self.api_key = api_key
self.account_id = account_id
self.base_url = 'https://api.voice360.app/v3/voice'
self.session = requests.Session()
self.session.headers.update({
'X-API-Key': api_key,
'Content-Type': 'application/json'
})
def _request(self, method: str, endpoint: str, **kwargs) -> Dict[str, Any]:
"""Make an API request"""
url = f'{self.base_url}/{self.account_id}{endpoint}'
response = self.session.request(method, url, **kwargs)
response.raise_for_status()
return response.json()
def get_user_availability(self) -> Dict[str, Any]:
"""Get user availability status"""
return self._request('GET', '/availability')
def get_queues(self) -> Dict[str, Any]:
"""List all queues"""
return self._request('GET', '/queues')
def get_queue_details(self, queue_id: int) -> Dict[str, Any]:
"""Get details for a specific queue"""
return self._request('GET', f'/queues/{queue_id}')
def get_queue_availability(self, queue_id: Optional[int] = None) -> Dict[str, Any]:
"""Get queue availability metrics"""
endpoint = f'/availability/queues/{queue_id}' if queue_id else '/availability/queues'
return self._request('GET', endpoint)
def initiate_call(self, from_ext: str, to_number: str, **options) -> Dict[str, Any]:
"""Initiate an outbound call"""
data = {'from': from_ext, 'to': to_number, **options}
return self._request('POST', '/call/outbound', json=data)
def send_sms(self, from_number: str, to_number: str, message: str) -> Dict[str, Any]:
"""Send an SMS message"""
data = {'from': from_number, 'to': to_number, 'message': message}
return self._request('POST', '/sms/send', json=data)
def main():
# Initialize the API client
api = Voice360API('your_api_key', 61)
try:
# Get user availability
availability = api.get_user_availability()
online_users = [u for u in availability['result'] if u['devices_registered']]
print(f"Online users: {len(online_users)}")
# Check queue status
queues = api.get_queue_availability()
ready_queues = [q for q in queues['result'] if q['is_ready']]
print(f"Queues with agents: {len(ready_queues)}")
# Display queue details
for queue in ready_queues:
print(f" - {queue['queue_name']}: {queue['agents_online']} agents online")
# Initiate a call
call = api.initiate_call(
from_ext='1001',
to_number='+15551234567',
caller_id='+15559876543',
recording=True
)
print(f"Call initiated: {call['result']['call_id']}")
# Send an SMS
sms = api.send_sms(
from_number='+15559876543',
to_number='+15551234567',
message='Hello from Voice360!'
)
print(f"SMS sent: {sms['message']}")
except requests.exceptions.RequestException as e:
print(f"API Error: {e}")
except KeyError as e:
print(f"Unexpected response format: {e}")
if __name__ == '__main__':
main()
<?php
class Voice360API {
private $apiKey;
private $accountId;
private $baseUrl = 'https://api.voice360.app/v3/voice';
public function __construct($apiKey, $accountId) {
$this->apiKey = $apiKey;
$this->accountId = $accountId;
}
private function request($method, $endpoint, $data = null) {
$url = "{$this->baseUrl}/{$this->accountId}{$endpoint}";
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
'X-API-Key: ' . $this->apiKey,
'Content-Type: application/json'
]);
if ($method === 'POST') {
curl_setopt($ch, CURLOPT_POST, true);
if ($data) {
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));
}
}
$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
if ($httpCode >= 400) {
throw new Exception("API Error: HTTP {$httpCode}");
}
return json_decode($response, true);
}
public function getUserAvailability() {
return $this->request('GET', '/availability');
}
public function getQueues() {
return $this->request('GET', '/queues');
}
public function getQueueDetails($queueId) {
return $this->request('GET', "/queues/{$queueId}");
}
public function getQueueAvailability($queueId = null) {
$endpoint = $queueId
? "/availability/queues/{$queueId}"
: '/availability/queues';
return $this->request('GET', $endpoint);
}
public function initiateCall($from, $to, $options = []) {
$data = array_merge(['from' => $from, 'to' => $to], $options);
return $this->request('POST', '/call/outbound', $data);
}
public function sendSMS($from, $to, $message) {
return $this->request('POST', '/sms/send', [
'from' => $from,
'to' => $to,
'message' => $message
]);
}
}
// Usage example
try {
$api = new Voice360API('your_api_key', 61);
// Get user availability
$availability = $api->getUserAvailability();
$onlineUsers = array_filter($availability['result'], function($u) {
return $u['devices_registered'];
});
echo "Online users: " . count($onlineUsers) . "\n";
// Check queue status
$queues = $api->getQueueAvailability();
foreach ($queues['result'] as $queue) {
if ($queue['is_ready']) {
echo "Queue {$queue['queue_name']}: {$queue['agents_online']} agents online\n";
}
}
// Make a call
$call = $api->initiateCall('1001', '+15551234567', [
'caller_id' => '+15559876543',
'recording' => true
]);
echo "Call initiated: {$call['result']['call_id']}\n";
} catch (Exception $e) {
echo "Error: " . $e->getMessage() . "\n";
}
?>
using System;
using System.Net.Http;
using System.Threading.Tasks;
using System.Text;
using Newtonsoft.Json;
public class Voice360API
{
private readonly HttpClient client;
private readonly string accountId;
private readonly string baseUrl = "https://api.voice360.app/v3/voice";
public Voice360API(string apiKey, int accountId)
{
this.accountId = accountId.ToString();
client = new HttpClient();
client.DefaultRequestHeaders.Add("X-API-Key", apiKey);
}
private async Task<T> RequestAsync<T>(HttpMethod method, string endpoint, object data = null)
{
var url = $"{baseUrl}/{accountId}{endpoint}";
var request = new HttpRequestMessage(method, url);
if (data != null)
{
var json = JsonConvert.SerializeObject(data);
request.Content = new StringContent(json, Encoding.UTF8, "application/json");
}
var response = await client.SendAsync(request);
response.EnsureSuccessStatusCode();
var responseJson = await response.Content.ReadAsStringAsync();
return JsonConvert.DeserializeObject<T>(responseJson);
}
public async Task<dynamic> GetUserAvailabilityAsync()
{
return await RequestAsync<dynamic>(HttpMethod.Get, "/availability");
}
public async Task<dynamic> GetQueuesAsync()
{
return await RequestAsync<dynamic>(HttpMethod.Get, "/queues");
}
public async Task<dynamic> InitiateCallAsync(string from, string to, object options = null)
{
var data = new { from, to };
if (options != null)
{
// Merge options with data
var json = JsonConvert.SerializeObject(data);
var optionsJson = JsonConvert.SerializeObject(options);
var merged = JsonConvert.DeserializeObject<dynamic>(json);
var optionsObj = JsonConvert.DeserializeObject<dynamic>(optionsJson);
foreach (var prop in optionsObj)
{
merged[prop.Name] = prop.Value;
}
data = merged;
}
return await RequestAsync<dynamic>(HttpMethod.Post, "/call/outbound", data);
}
}
// Usage
class Program
{
static async Task Main(string[] args)
{
var api = new Voice360API("your_api_key", 61);
try
{
// Get user availability
var availability = await api.GetUserAvailabilityAsync();
Console.WriteLine($"Users fetched: {availability.result.Count}");
// Get queues
var queues = await api.GetQueuesAsync();
Console.WriteLine($"Queues fetched: {queues.result.Count}");
// Initiate a call
var call = await api.InitiateCallAsync("1001", "+15551234567", new {
caller_id = "+15559876543",
recording = true
});
Console.WriteLine($"Call initiated: {call.result.call_id}");
}
catch (Exception ex)
{
Console.WriteLine($"Error: {ex.Message}");
}
}
}
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.net.URI;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.util.Map;
import java.util.HashMap;
public class Voice360API {
private final HttpClient client;
private final String apiKey;
private final int accountId;
private final String baseUrl = "https://api.voice360.app/v3/voice";
private final ObjectMapper mapper;
public Voice360API(String apiKey, int accountId) {
this.apiKey = apiKey;
this.accountId = accountId;
this.client = HttpClient.newHttpClient();
this.mapper = new ObjectMapper();
}
private Map<String, Object> request(String method, String endpoint, Map<String, Object> data) throws Exception {
String url = baseUrl + "/" + accountId + endpoint;
HttpRequest.Builder builder = HttpRequest.newBuilder()
.uri(URI.create(url))
.header("X-API-Key", apiKey)
.header("Content-Type", "application/json");
if ("POST".equals(method) && data != null) {
String json = mapper.writeValueAsString(data);
builder.POST(HttpRequest.BodyPublishers.ofString(json));
} else {
builder.GET();
}
HttpRequest request = builder.build();
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
if (response.statusCode() >= 400) {
throw new RuntimeException("API Error: " + response.statusCode());
}
return mapper.readValue(response.body(), Map.class);
}
public Map<String, Object> getUserAvailability() throws Exception {
return request("GET", "/availability", null);
}
public Map<String, Object> getQueues() throws Exception {
return request("GET", "/queues", null);
}
public Map<String, Object> initiateCall(String from, String to, Map<String, Object> options) throws Exception {
Map<String, Object> data = new HashMap<>();
data.put("from", from);
data.put("to", to);
if (options != null) {
data.putAll(options);
}
return request("POST", "/call/outbound", data);
}
public static void main(String[] args) {
Voice360API api = new Voice360API("your_api_key", 61);
try {
// Get user availability
Map<String, Object> availability = api.getUserAvailability();
System.out.println("Availability: " + availability);
// Get queues
Map<String, Object> queues = api.getQueues();
System.out.println("Queues: " + queues);
// Initiate call
Map<String, Object> options = new HashMap<>();
options.put("caller_id", "+15559876543");
options.put("recording", true);
Map<String, Object> call = api.initiateCall("1001", "+15551234567", options);
System.out.println("Call initiated: " + call);
} catch (Exception e) {
System.err.println("Error: " + e.getMessage());
}
}
}
Rate Limits
API rate limits are enforced to ensure fair usage and maintain service quality for all users.
| Authentication Type | Rate Limit | Window | Headers Returned |
|---|---|---|---|
| API Key | 1000 requests | Per minute | X-RateLimit-Limit, X-RateLimit-Remaining |
| No Auth (Public) | 100 requests | Per minute per IP | X-RateLimit-Limit, X-RateLimit-Remaining |
Error Handling
The API uses standard HTTP status codes to indicate success or failure of requests.
| Status Code | Error Code | Description |
|---|---|---|
| 200 | - | Success - Request completed successfully |
| 400 | BAD_REQUEST | Invalid request parameters or malformed request |
| 401 | AUTH_REQUIRED | Authentication required but not provided |
| 403 | AUTH_INVALID | Invalid API key or insufficient permissions |
| 404 | NOT_FOUND | Requested resource not found |
| 429 | RATE_LIMITED | Too many requests - rate limit exceeded |
| 500 | INTERNAL_ERROR | Internal server error - please try again |
| 503 | SERVICE_UNAVAILABLE | Service temporarily unavailable |
Error Response Example
{
"result": null,
"error": true,
"message": "Invalid API key provided",
"error_code": "AUTH_INVALID",
"details": {
"provided_key": "partial_key_xxx...",
"help": "Please check your API key at https://voice360.app/settings/api"
},
"timestamp": "2024-01-15T10:30:00Z"
}