Your First API Call
Now that you have your access token, let's make your first API call and understand how the SIPSIM API works.
Making a Request
All API requests follow this pattern:
curl https://app.sipsim.com/api/v2/{endpoint} \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
-H "Content-Type: application/json"
Get Account Information
Let's start with a simple request to verify your integration is working:
- cURL
- Python
- JavaScript
- Ruby
curl https://app.sipsim.com/api/v2/account \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN"
import requests
access_token = "YOUR_ACCESS_TOKEN"
response = requests.get(
"https://app.sipsim.com/api/v2/account",
headers={"Authorization": f"Bearer {access_token}"}
)
data = response.json()
print(f"Connected as: {data['data']['company_name']}")
const accessToken = 'YOUR_ACCESS_TOKEN';
const response = await fetch('https://app.sipsim.com/api/v2/account', {
headers: {
'Authorization': `Bearer ${accessToken}`
}
});
const data = await response.json();
console.log('Connected as:', data.data.company_name);
require 'net/http'
require 'json'
access_token = 'YOUR_ACCESS_TOKEN'
uri = URI('https://app.sipsim.com/api/v2/account')
request = Net::HTTP::Get.new(uri)
request['Authorization'] = "Bearer #{access_token}"
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) do |http|
http.request(request)
end
data = JSON.parse(response.body)
puts "Connected as: #{data['data']['company_name']}"
Understanding the Response
All SIPSIM API responses follow a consistent envelope format:
{
"status": 200,
"request_id": "550e8400-e29b-41d4-a716-446655440000",
"timestamp": "2024-01-15T10:30:00Z",
"data": {
"id": 12345,
"company_name": "Acme Corporation",
"email": "admin@acme.com"
}
}
Response Fields
| Field | Type | Description |
|---|---|---|
status | integer | HTTP status code |
request_id | string | Unique identifier for this request (useful for debugging) |
timestamp | string | ISO 8601 timestamp of the response |
data | object/array | The actual response data |
pagination | object | Pagination info (only for list endpoints) |
Pagination
List endpoints return paginated results. The SIPSIM API uses keyset pagination for efficient navigation through large datasets.
Example: List Calls
curl "https://app.sipsim.com/api/v2/calls?start_time=2024-01-01T00:00:00Z&limit=100" \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN"
Paginated Response
{
"status": 200,
"request_id": "...",
"timestamp": "2024-01-15T10:30:00Z",
"data": [
{ "id": "call_123", ... },
{ "id": "call_124", ... }
],
"pagination": {
"count": 100,
"limit": 100,
"page": "eyJpZCI6ImNhbGxfMjI0In0=",
"has_more": true
}
}
Pagination Fields
| Field | Description |
|---|---|
count | Number of items in the current response |
limit | Maximum items per page |
page | Token for the next page (use as page parameter) |
has_more | Whether more pages exist |
Fetching the Next Page
To get the next page, pass the page token:
curl "https://app.sipsim.com/api/v2/calls?start_time=2024-01-01T00:00:00Z&limit=100&page=eyJpZCI6ImNhbGxfMjI0In0=" \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN"
Complete Pagination Example
- Python
- JavaScript
import requests
access_token = "YOUR_ACCESS_TOKEN"
base_url = "https://app.sipsim.com/api/v2"
def get_all_calls(start_time):
"""Fetch all calls using pagination."""
all_calls = []
page = None
while True:
params = {
"start_time": start_time,
"limit": 1000
}
if page:
params["page"] = page
response = requests.get(
f"{base_url}/calls",
headers={"Authorization": f"Bearer {access_token}"},
params=params
)
data = response.json()
all_calls.extend(data["data"])
pagination = data.get("pagination", {})
if not pagination.get("has_more"):
break
page = pagination["page"]
return all_calls
# Get all calls from 2024
calls = get_all_calls("2024-01-01T00:00:00Z")
print(f"Total calls: {len(calls)}")
const accessToken = 'YOUR_ACCESS_TOKEN';
const baseUrl = 'https://app.sipsim.com/api/v2';
async function getAllCalls(startTime) {
const allCalls = [];
let page = null;
while (true) {
const params = new URLSearchParams({
start_time: startTime,
limit: '1000'
});
if (page) params.set('page', page);
const response = await fetch(`${baseUrl}/calls?${params}`, {
headers: { 'Authorization': `Bearer ${accessToken}` }
});
const data = await response.json();
allCalls.push(...data.data);
if (!data.pagination?.has_more) break;
page = data.pagination.page;
}
return allCalls;
}
// Get all calls from 2024
const calls = await getAllCalls('2024-01-01T00:00:00Z');
console.log(`Total calls: ${calls.length}`);
Error Handling
When something goes wrong, the API returns an error response:
{
"status": 404,
"errors": ["Record does not exist"],
"request_id": "550e8400-e29b-41d4-a716-446655440000",
"timestamp": "2024-01-15T10:30:00Z",
"path": "/api/v2/calls/invalid_id"
}
Common Error Codes
| Status | Meaning | Common Causes |
|---|---|---|
400 | Bad Request | Invalid parameters, missing required fields |
401 | Unauthorized | Invalid or expired access token |
403 | Forbidden | Valid token but insufficient permissions |
404 | Not Found | Resource doesn't exist |
409 | Conflict | Resource already exists or operation conflicts |
429 | Too Many Requests | Rate limit exceeded |
500 | Internal Server Error | Server-side error (contact support) |
Handling Errors
- Python
import requests
def api_call(endpoint, method="GET", **kwargs):
"""Make an API call with error handling."""
response = requests.request(
method,
f"https://app.sipsim.com/api/v2{endpoint}",
headers={"Authorization": f"Bearer {access_token}"},
**kwargs
)
data = response.json()
if response.status_code == 401:
# Token expired - refresh and retry
refresh_access_token()
return api_call(endpoint, method, **kwargs)
if response.status_code == 429:
# Rate limited - wait and retry
import time
time.sleep(60)
return api_call(endpoint, method, **kwargs)
if response.status_code >= 400:
raise Exception(f"API Error {data['status']}: {data['errors']}")
return data
Best Practices
- Always check the status code — Don't assume success
- Use request_id for debugging — Include it when contacting support
- Implement retry logic — Handle transient errors gracefully
- Cache when appropriate — Reduce API calls for data that doesn't change often
- Use pagination limits wisely — Larger limits mean fewer requests but more memory
Next Steps
Now that you understand the basics, explore specific use cases:
- Working with Calls — Access and filter call history
- Click-to-Call — Initiate calls from your application
- AI Features — Use transcription and summaries