Click-to-call (originate)
curl --request POST \ --url https://api.sipstack.com/api/v2/nova/calls \ --header 'Content-Type: application/json' \ --header 'x-api-key: <x-api-key>' \ --data '{ "from": "1001", "to": "+14165550100" }'import requests
url = "https://api.sipstack.com/api/v2/nova/calls"
payload = { "from": "1001", "to": "+14165550100"}headers = { "x-api-key": "<x-api-key>", "Content-Type": "application/json"}
response = requests.post(url, json=payload, headers=headers)
print(response.json())const url = 'https://api.sipstack.com/api/v2/nova/calls';const options = { method: 'POST', headers: {'x-api-key': '<x-api-key>', 'Content-Type': 'application/json'}, body: '{"from":"1001","to":"+14165550100"}'};
try { const response = await fetch(url, options); const data = await response.json(); console.log(data);} catch (error) { console.error(error);}import axios from 'axios';
const options = { method: 'POST', url: 'https://api.sipstack.com/api/v2/nova/calls', headers: {'x-api-key': '<x-api-key>', 'Content-Type': 'application/json'}, data: {from: '1001', to: '+14165550100'}};
try { const { data } = await axios.request(options); console.log(data);} catch (error) { console.error(error);}Places an outbound “click-to-call” for your organization using an
answer-first callback: SIPSTACK rings your own extension
(from) for about 2 rings, and only once you answer does it dial
the destination (to). This mirrors picking up your deskphone and
dialing — the outbound caller-ID, suspended-outbound gating, and
international/emergency routing all come from that extension’s own
dialplan (a caller cannot spoof another number).
- No voicemail. An unanswered
fromleg fails cleanly after ~2 rings; it never rolls to voicemail, and the destination is never dialed. - Offline device → nothing happens. If your extension is not registered, the call fails at the switch with no destination call.
- Requires the
calls:writescope.
:::note
Click-to-call must be enabled for API access on your organization.
Until it is, this endpoint returns 403 — the read endpoints below are
unaffected.
:::
Authorizations
Section titled “Authorizations ”Request Body required
Section titled “Request Body required ”object
One of your organization’s provisioned, enabled extension numbers. The call is placed as if this extension dialed it.
Example
1001Destination phone number (optional leading +, 3–20 digits). Feature codes, extensions, and emergency numbers are rejected.
Example
+14165550100Responses
Section titled “ Responses ”Origination accepted — your extension is ringing.
object
object
Example
{ "success": true, "data": { "status": "originating", "from": "1001", "to": "+14165550100" }}Missing from, or to is not a valid dialable number (feature codes / extensions / emergency numbers are rejected).
Inline error shape used by the messaging API and management endpoints.
object
Example
{ "success": false, "error": "Recipient phone number (to) is required"}Missing or invalid API key.
Inline error shape used by the messaging API and management endpoints.
object
Example
{ "success": false, "error": "Recipient phone number (to) is required"}Click-to-call is not enabled for API access, or the key is missing the calls:write scope.
Inline error shape used by the messaging API and management endpoints.
object
Example
{ "success": false, "error": "Recipient phone number (to) is required"}No Nova PBX is provisioned, or from is not one of your extensions.
Inline error shape used by the messaging API and management endpoints.
object
Example
{ "success": false, "error": "Recipient phone number (to) is required"}The from extension is disabled.
Inline error shape used by the messaging API and management endpoints.
object
Example
{ "success": false, "error": "Recipient phone number (to) is required"}The voice node is offline or temporarily unavailable — retry shortly.
Inline error shape used by the messaging API and management endpoints.
object
Example
{ "success": false, "error": "Recipient phone number (to) is required"}