Skip to main content

Click-to-Call

The Click-to-Call feature allows you to initiate outbound calls directly from your application. When triggered, the employee's phone rings first, and once they answer, the system dials the target number.

Required Scopes

  • calls.create — Required to initiate calls
  • phones.read — Required to list available phones

How It Works

List Available Phones

Before initiating a call, you need to know which phone lines are available:

curl "https://app.sipsim.com/api/v2/phones?status=active" \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN"

Phone Object

{
"id": 123,
"name": "Sales Department Phone",
"status": "active",
"internal_number": 101,
"number": "+33612345678",
"created_at": "2024-01-15T10:30:00Z",
"updated_at": "2024-06-20T14:45:00Z",
"group": {
"group_id": 5,
"group_title": "Sales Team"
},
"outbound_setting": {
"outbound_number": "+33987654321",
"use_different_outbound_number": false,
"outbound_number_phone_id": null
},
"record_setting": {
"record_inbound_call": true,
"record_outbound_call": true
},
"voicemail_setting": {
"allow_voicemail": true,
"voicemail_file_id": null
},
"forwarding_setting": {
"forced": {
"enabled": false,
"forward_number": null
},
"conditional": {
"enabled": true,
"timeout_seconds": 25,
"forward_number": "+33555888999"
}
},
"audio_setting": {
"inbound_call_preroll_id": null,
"outbound_call_preroll_id": null,
"no_answer_file_id": null,
"wait_preroll_dial": 0
}
}

Phone Fields

FieldTypeDescription
idintegerUnique identifier of the phone
namestringName or label of the phone
statusstringStatus: not_activated, active, inactive
internal_numberintegerInternal extension number (100-999)
numberstringPhone number (E.164 format)
created_atstringWhen the phone was created (ISO 8601)
updated_atstringWhen the phone was last updated (ISO 8601)
groupobjectAssigned group (group_id, group_title)
outbound_settingobjectOutbound caller ID settings
record_settingobjectCall recording settings
voicemail_settingobjectVoicemail settings
forwarding_settingobjectCall forwarding settings
audio_settingobjectAudio file settings

Initiate a Call

Make a POST request to start a click-to-call:

curl -X POST "https://app.sipsim.com/api/v2/calls" \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"phone_id": 123,
"target_number": "+33698765432"
}'

Request Parameters

ParameterTypeRequiredDescription
phone_idintegerYesID of the phone line to use
target_numberstringYesPhone number to call (international format)

Response

{
"status": 201,
"request_id": "...",
"timestamp": "2024-01-15T10:30:00Z",
"data": {
"id": "call_xyz789",
"phone_id": 123,
"target_number": "+33698765432",
"status": "initiating"
}
}

Error Handling

Phone Busy (409 Conflict)

If the phone already has an active call:

{
"status": 409,
"errors": ["Phone is currently on another call"],
"request_id": "...",
"timestamp": "2024-01-15T10:30:00Z",
"path": "/api/v2/calls"
}

How to handle:

import requests
import time

def initiate_call_with_retry(phone_id, target_number, max_retries=3):
"""Initiate a call with retry logic for busy phone."""
for attempt in range(max_retries):
response = requests.post(
"https://app.sipsim.com/api/v2/calls",
headers={
"Authorization": f"Bearer {access_token}",
"Content-Type": "application/json"
},
json={
"phone_id": phone_id,
"target_number": target_number
}
)

if response.status_code == 201:
return response.json()["data"]

if response.status_code == 409:
# Phone busy, wait and retry
wait_time = 30 * (attempt + 1) # 30s, 60s, 90s
print(f"Phone busy, retrying in {wait_time}s...")
time.sleep(wait_time)
continue

# Other error, don't retry
response.raise_for_status()

raise Exception("Max retries exceeded - phone still busy")

Invalid Phone Number

If the target number is invalid:

{
"status": 400,
"errors": ["target_number is invalid"],
"request_id": "...",
"timestamp": "2024-01-15T10:30:00Z",
"path": "/api/v2/calls"
}
Phone Number Format

Always use international format (E.164) for phone numbers:

  • Correct: +33612345678
  • Incorrect: 0612345678, 06 12 34 56 78

CRM Integration Example

A common use case is adding click-to-call buttons in your CRM:

from flask import Flask, request, jsonify
import requests

app = Flask(__name__)
access_token = "YOUR_ACCESS_TOKEN"

@app.route("/api/click-to-call", methods=["POST"])
def click_to_call():
"""Handle click-to-call from CRM interface."""
data = request.json
phone_id = data["phone_id"] # ID of the SIPSIM phone to use
target_number = data["target_number"]

# Initiate the call
call_response = requests.post(
"https://app.sipsim.com/api/v2/calls",
headers={
"Authorization": f"Bearer {access_token}",
"Content-Type": "application/json"
},
json={
"phone_id": phone_id,
"target_number": target_number
}
)

if call_response.status_code == 201:
call = call_response.json()["data"]
return jsonify({
"success": True,
"call_id": call["id"],
"message": "Call initiated - your phone will ring shortly"
})
else:
error = call_response.json()
return jsonify({
"success": False,
"error": error["errors"][0]
}), call_response.status_code

Best Practices

  1. Validate phone numbers before sending to the API
  2. Show feedback to users — Let them know the call is being initiated
  3. Handle the busy case gracefully — Inform users if the line is busy
  4. Log call IDs for troubleshooting and CRM integration
  5. Rate limit click-to-call buttons to prevent accidental double-clicks

Next Steps