This endpoint retrieves the current webhook configuration for a phone number, showing the URLs configured to receive voice call and SMS events.
How It Works
- Provider Detection: Automatically detects which provider owns the number
- Configuration Retrieval: Fetches current webhook URLs from the provider
- Detailed Response: Returns complete webhook configuration with metadata
Real-Time Data: This endpoint queries the provider directly to get the most current webhook configuration, not cached data.
Path Parameters
phone_number
(string, required): Phone number to get webhooks for in E.164 format (e.g., +14155551234
)
Query Parameters
provider
(string, optional): Provider ("twilio"
or "telnyx"
). Auto-detected if not provided
GET /phone-numbers/+14155551234/webhooks?provider=twilio
Response
A successful request returns a 200 OK
status with current webhook configuration.
{
"success": true,
"phone_number": "+14155551234",
"provider": "twilio",
"voice_webhook_url": "https://your-app.com/webhooks/voice",
"sms_webhook_url": "https://your-app.com/webhooks/sms",
"configuration": {
"voice_webhook_url": "https://your-app.com/webhooks/voice",
"voice_method": "POST",
"sms_webhook_url": "https://your-app.com/webhooks/sms",
"sms_method": "POST",
"status_callback_url": "https://your-app.com/status",
"status_callback_method": "POST",
"phone_number_sid": "PN1234567890abcdef",
"friendly_name": "Support Line"
}
}
Response Fields
success
(boolean): Whether the request completed successfully
phone_number
(string): The queried phone number
provider
(string): Provider that owns the number (“twilio” or “telnyx”)
voice_webhook_url
(string): Current voice webhook URL
sms_webhook_url
(string): Current SMS webhook URL
configuration
(object): Complete webhook configuration details
- For Twilio:
voice_method
(string): HTTP method for voice webhooks
sms_method
(string): HTTP method for SMS webhooks
status_callback_url
(string): URL for status callbacks
phone_number_sid
(string): Twilio phone number SID
friendly_name
(string): Display name for the number
- For Telnyx:
connection_id
(string): Associated connection ID
phone_number_id
(string): Telnyx phone number ID
status
(string): Number status
features
(array): Supported features
Error Responses
400 Bad Request
Returned when the request contains invalid parameters.
{
"detail": "Phone number must be in E.164 format (e.g., +1234567890)"
}
404 Not Found
Returned when the phone number is not found.
{
"detail": "Phone number +14155551234 not found in database"
}
500 Internal Server Error
Returned when the provider API fails.
{
"detail": "Could not retrieve webhook configuration for +14155551234"
}
Provider-Specific Responses
Twilio Response Example
{
"success": true,
"phone_number": "+14155551234",
"provider": "twilio",
"voice_webhook_url": "https://api.yourapp.com/twiml",
"sms_webhook_url": "https://api.yourapp.com/twiml",
"configuration": {
"voice_webhook_url": "https://api.yourapp.com/twiml",
"voice_method": "POST",
"sms_webhook_url": "https://api.yourapp.com/twiml",
"sms_method": "POST",
"status_callback_url": "https://api.yourapp.com/status",
"status_callback_method": "POST",
"phone_number_sid": "PN1234567890abcdef1234567890abcdef",
"friendly_name": "Customer Support Line"
}
}
Telnyx Response Example
{
"success": true,
"phone_number": "+14155551234",
"provider": "telnyx",
"voice_webhook_url": "Configured at Connection level",
"sms_webhook_url": "Configured at Connection level",
"configuration": {
"connection_id": "1234567890",
"phone_number_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"status": "active",
"features": ["voice", "sms", "mms"]
}
}
Telnyx Limitation: Telnyx webhook URLs are configured at the Connection/Application level, so the exact webhook URLs may not be directly retrievable via the phone number API. The response indicates they are “Configured at Connection level”.
Use Cases
Configuration Audit
Verify webhook configurations across all numbers:
# Check multiple numbers
for number in "+14155551234" "+12125555678" "+13105559999"; do
curl -H "Authorization: Bearer YOUR_API_KEY" \
"https://api.burki.dev/phone-numbers/${number}/webhooks"
done
Environment Verification
Confirm webhooks point to the correct environment:
async function verifyEnvironmentWebhooks(phoneNumbers, expectedEnv) {
for (const phoneNumber of phoneNumbers) {
const config = await getPhoneWebhooks(phoneNumber);
if (!config.voice_webhook_url.includes(expectedEnv)) {
console.warn(`❌ ${phoneNumber} points to wrong environment`);
} else {
console.log(`✅ ${phoneNumber} correctly configured`);
}
}
}
Debugging Call Issues
Check webhook configuration when troubleshooting:
def debug_call_issues(phone_number):
config = get_phone_webhooks(phone_number)
print(f"Phone: {config['phone_number']}")
print(f"Provider: {config['provider']}")
print(f"Voice Webhook: {config['voice_webhook_url']}")
# Test webhook accessibility
if config['voice_webhook_url']:
try:
response = requests.get(config['voice_webhook_url'])
print(f"Webhook Status: {response.status_code}")
except Exception as e:
print(f"Webhook Error: {e}")
Integration Examples
Node.js
const axios = require('axios');
async function getPhoneWebhooks(phoneNumber, provider = null) {
try {
const params = provider ? `?provider=${provider}` : '';
const response = await axios.get(`https://api.burki.dev/phone-numbers/${phoneNumber}/webhooks${params}`, {
headers: {
'Authorization': 'Bearer YOUR_API_KEY'
}
});
return response.data;
} catch (error) {
console.error('Failed to get webhooks:', error.response.data);
throw error;
}
}
// Usage
const config = await getPhoneWebhooks('+14155551234');
console.log('Voice webhook:', config.voice_webhook_url);
console.log('SMS webhook:', config.sms_webhook_url);
Python
import requests
def get_phone_webhooks(phone_number, provider=None):
url = f"https://api.burki.dev/phone-numbers/{phone_number}/webhooks"
headers = {"Authorization": "Bearer YOUR_API_KEY"}
params = {}
if provider:
params["provider"] = provider
response = requests.get(url, headers=headers, params=params)
if response.status_code == 200:
return response.json()
else:
raise Exception(f"Failed to get webhooks: {response.json()['detail']}")
# Usage
config = get_phone_webhooks("+14155551234")
print(f"Voice: {config['voice_webhook_url']}")
print(f"SMS: {config['sms_webhook_url']}")
PHP
<?php
function getPhoneWebhooks($phoneNumber, $provider = null) {
$url = "https://api.burki.dev/phone-numbers/" . urlencode($phoneNumber) . "/webhooks";
if ($provider) {
$url .= "?provider=" . urlencode($provider);
}
$headers = ['Authorization: Bearer YOUR_API_KEY'];
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
if ($httpCode === 200) {
return json_decode($response, true);
} else {
throw new Exception("Failed to get webhooks: " . $response);
}
}
// Usage
$config = getPhoneWebhooks('+14155551234');
echo "Voice: " . $config['voice_webhook_url'] . "\n";
echo "SMS: " . $config['sms_webhook_url'] . "\n";
?>
Batch Operations
Check Multiple Numbers
async function auditPhoneWebhooks(phoneNumbers) {
const results = [];
for (const phoneNumber of phoneNumbers) {
try {
const config = await getPhoneWebhooks(phoneNumber);
results.push({
phoneNumber,
provider: config.provider,
voiceWebhook: config.voice_webhook_url,
smsWebhook: config.sms_webhook_url,
status: 'success'
});
} catch (error) {
results.push({
phoneNumber,
status: 'error',
error: error.message
});
}
}
return results;
}
// Usage
const phoneNumbers = ['+14155551234', '+12125555678', '+13105559999'];
const audit = await auditPhoneWebhooks(phoneNumbers);
console.table(audit);
Environment Comparison
def compare_webhook_environments(phone_numbers):
"""Compare webhook environments across numbers"""
environments = {}
for phone_number in phone_numbers:
try:
config = get_phone_webhooks(phone_number)
voice_url = config.get('voice_webhook_url', '')
# Extract environment from URL
if 'staging' in voice_url:
env = 'staging'
elif 'production' in voice_url or 'api' in voice_url:
env = 'production'
else:
env = 'unknown'
if env not in environments:
environments[env] = []
environments[env].append(phone_number)
except Exception as e:
print(f"Error checking {phone_number}: {e}")
return environments
Monitoring and Alerting
Webhook Health Check
import requests
from urllib.parse import urlparse
def health_check_webhooks(phone_numbers):
"""Check if webhook URLs are accessible"""
issues = []
for phone_number in phone_numbers:
config = get_phone_webhooks(phone_number)
for webhook_type in ['voice_webhook_url', 'sms_webhook_url']:
url = config.get(webhook_type)
if url and not url.startswith('Configured'):
try:
response = requests.get(url, timeout=5)
if response.status_code >= 400:
issues.append({
'phone_number': phone_number,
'webhook_type': webhook_type,
'url': url,
'status_code': response.status_code
})
except Exception as e:
issues.append({
'phone_number': phone_number,
'webhook_type': webhook_type,
'url': url,
'error': str(e)
})
return issues
Configuration Drift Detection
async function detectConfigDrift(phoneNumbers, expectedWebhooks) {
const drifts = [];
for (const phoneNumber of phoneNumbers) {
const current = await getPhoneWebhooks(phoneNumber);
const expected = expectedWebhooks[phoneNumber];
if (!expected) continue;
if (current.voice_webhook_url !== expected.voice) {
drifts.push({
phoneNumber,
type: 'voice',
current: current.voice_webhook_url,
expected: expected.voice
});
}
if (current.sms_webhook_url !== expected.sms) {
drifts.push({
phoneNumber,
type: 'sms',
current: current.sms_webhook_url,
expected: expected.sms
});
}
}
return drifts;
}
Best Practices
Regular Auditing
- Daily Checks: Verify webhook configurations daily
- Environment Validation: Ensure correct environment URLs
- Accessibility Testing: Test webhook URL accessibility
- Provider Sync: Compare with provider console settings
Error Handling
def safe_get_webhooks(phone_number, retries=3):
"""Get webhooks with retry logic"""
for attempt in range(retries):
try:
return get_phone_webhooks(phone_number)
except Exception as e:
if attempt == retries - 1:
raise
time.sleep(2 ** attempt) # Exponential backoff
Caching Strategy
class WebhookConfigCache {
constructor(ttl = 300000) { // 5 minutes TTL
this.cache = new Map();
this.ttl = ttl;
}
async get(phoneNumber) {
const cached = this.cache.get(phoneNumber);
if (cached && Date.now() - cached.timestamp < this.ttl) {
return cached.data;
}
const fresh = await getPhoneWebhooks(phoneNumber);
this.cache.set(phoneNumber, {
data: fresh,
timestamp: Date.now()
});
return fresh;
}
}
This endpoint is essential for maintaining visibility into your webhook configurations and ensuring your phone numbers are properly connected to your application’s event handling endpoints.