First Outbound Call
serverCall() starts an outbound call by sending call context to the Vonage API. The Vonage API then invokes your answer webhook with the context as custom_data, and your webhook returns an NCCO that decides routing.
Outbound Flow
- Client app calls
serverCall(context). - Vonage API invokes your answer webhook with context as
custom_data. - Your webhook returns NCCO.
- Vonage API connects media to the callee.
Client Snippet
const context = {
to: 'sip:alice@example.com',
from: 'agent-123'
};
try {
const callId = await client.serverCall(context);
console.log(`Outbound call started, callId: ${callId}`);
} catch (error) {
console.error('Failed to start outbound call', error);
}
val context = mapOf(
"to" to "sip:alice@example.com",
"from" to "agent-123"
)
client.serverCall(context) { error, callId ->
if (error != null) {
println("Failed to start outbound call: $error")
return@serverCall
}
println("Outbound call started, callId: $callId")
}
HashMap<String, String> context = new HashMap<>();
context.put("to", "sip:alice@example.com");
context.put("from", "agent-123");
client.serverCall(context, (error, callId) -> {
if (error != null) {
System.out.println("Failed to start outbound call: " + error);
return null;
}
System.out.println("Outbound call started, callId: " + callId);
return null;
});
let context = [
"to": "sip:alice@example.com",
"from": "agent-123"
]
client.serverCall(context) { error, callId in
guard error == nil, let callId = callId else {
print("Failed to start outbound call: \(error?.localizedDescription ?? "unknown")")
return
}
print("Outbound call started, callId: \(callId)")
}
NSDictionary *context = @{
@"to": @"sip:alice@example.com",
@"from": @"agent-123"
};
[client serverCall:context callback:^(NSError * _Nullable error, VGCallId _Nullable callId) {
if (error != nil || callId == nil) {
NSLog(@"Failed to start outbound call: %@", error);
return;
}
NSLog(@"Outbound call started, callId: %@", callId);
}];
Server Answer Webhook
The example below illustrates the required webhook response shape. Your actual implementation will vary based on your backend language and framework.
Your answer webhook must be publicly reachable and return valid NCCO.
Use "type": "app" in the connect endpoint to route the call to an SDK client by username. Use "type": "phone" to route to a PSTN number instead. See the NCCO connect endpoint types for all options.
const customData =
(req.body.custom_data as { to?: string } | undefined) ?? {};
const destination = customData.to ?? 'callee-username';
const answerNcco = [
{
action: 'connect',
endpoint: [
{
type: 'app',
user: destination
}
]
}
];
res.json(answerNcco);
NCCO reference: here
Handling Errors
serverCall can fail if there is no active session, the call setup times out, or the Vonage API encounters an issue with your webhook. Always handle the error:
try {
const callId = await client.serverCall({ context });
console.log("Call started:", callId);
} catch (error) {
console.error("Call failed:", error.type, error.message);
}
client.serverCall(context) { error, callId ->
if (error != null) {
println("Call failed: ${error.message}")
// Common causes:
// - No active session (call createSession first)
// - Network timeout
// - Answer webhook returned invalid NCCO
return@serverCall
}
println("Call started: $callId")
}
client.serverCall(context) { error, callId in
if let error = error {
print("Call failed: \(error.localizedDescription)")
return
}
print("Call started: \(callId ?? "")")
}
For a full list of possible error types, see Errors.