Get started12 min
1
Use the API surface that is already live
QuickCallAI SDKs are thin server-side clients around the same authenticated call pipeline used by the dashboard. Keep tokens on your server, call the production API, then poll status or listen to webhooks for the final outcome.
- Default API base: https://ai.quickcall.tech/api
- Create calls through POST /calls/demo/initiate
- Read lifecycle state through GET /calls/demo/{call_id}/status
- End a live call through POST /calls/demo/{call_id}/end
2
Choose your language
Each SDK keeps the same request fields so teams can switch between languages without changing the call workflow.
JavaScript / TypeScript SDK
type QuickCallConfig = {
apiKey: string
baseUrl?: string
}
type InitiateCallInput = {
phoneNumber: string
customerName: string
prompt: string
language?: string
voiceModel?: string
provider?: "twilio" | "vobiz" | "frejun" | "livekit"
agentId?: string
transferPhoneNumber?: string
}
type QuickCallApiResponse = {
success?: boolean
message?: string
error?: string
[key: string]: unknown
}
type CreateCallResponse = QuickCallApiResponse & {
call_id?: string | number
call_sid?: string
status?: string
}
type CallStatusResponse = QuickCallApiResponse & {
call_id?: string | number
call_sid?: string
provider_call_id?: string
status?: string
lifecycle_state?: string
transcript?: unknown
summary?: string
}
export class QuickCallAI {
private readonly apiKey: string
private readonly baseUrl: string
constructor(config: QuickCallConfig) {
this.apiKey = config.apiKey
this.baseUrl = (config.baseUrl || "https://ai.quickcall.tech/api").replace(/\/+$/, "")
}
private async request<T extends QuickCallApiResponse = QuickCallApiResponse>(
path: string,
init: RequestInit = {},
): Promise<T> {
const response = await fetch(`${this.baseUrl}${path}`, {
...init,
headers: {
Authorization: `Bearer ${this.apiKey}`,
"Content-Type": "application/json",
...(init.headers || {}),
},
})
const data = await response.json().catch(() => ({})) as QuickCallApiResponse
if (!response.ok || data.success === false) {
throw new Error(data.message || data.error || `QuickCallAI API error: ${response.status}`)
}
return data as T
}
initiateCall(input: InitiateCallInput): Promise<CreateCallResponse> {
return this.request<CreateCallResponse>("/calls/demo/initiate", {
method: "POST",
body: JSON.stringify({
phone_number: input.phoneNumber,
customer_name: input.customerName,
prompt: input.prompt,
language: input.language || "en-US",
voice_model: input.voiceModel || "aura-asteria-en",
provider: input.provider || "twilio",
agent_id: input.agentId || null,
transfer_phone_number: input.transferPhoneNumber || null,
}),
})
}
getCallStatus(callId: string): Promise<CallStatusResponse> {
return this.request<CallStatusResponse>(`/calls/demo/${encodeURIComponent(callId)}/status`)
}
endCall(callId: string): Promise<QuickCallApiResponse> {
return this.request(`/calls/demo/${encodeURIComponent(callId)}/end`, { method: "POST" })
}
}Python SDK
from urllib.parse import quote
import requests
class QuickCallError(RuntimeError):
pass
class QuickCallAI:
def __init__(self, api_key: str, base_url: str = "https://ai.quickcall.tech/api", timeout: int = 30):
self.api_key = api_key
self.base_url = base_url.rstrip("/")
self.timeout = timeout
def _request(self, method: str, path: str, json=None):
response = requests.request(
method,
f"{self.base_url}{path}",
headers={
"Authorization": f"Bearer {self.api_key}",
"Content-Type": "application/json",
},
json=json,
timeout=self.timeout,
)
try:
data = response.json() if response.content else {}
except ValueError:
data = {}
if not response.ok or data.get("success") is False:
raise QuickCallError(data.get("message") or data.get("error") or response.text)
return data
def initiate_call(self, phone_number: str, customer_name: str, prompt: str, **options):
return self._request("POST", "/calls/demo/initiate", {
"phone_number": phone_number,
"customer_name": customer_name,
"prompt": prompt,
"language": options.get("language", "en-US"),
"voice_model": options.get("voice_model", "aura-asteria-en"),
"provider": options.get("provider", "twilio"),
"agent_id": options.get("agent_id"),
"transfer_phone_number": options.get("transfer_phone_number"),
})
def get_call_status(self, call_id: str):
return self._request("GET", f"/calls/demo/{quote(call_id, safe='')}/status")
def end_call(self, call_id: str):
return self._request("POST", f"/calls/demo/{quote(call_id, safe='')}/end")PHP SDK
<?php
final class QuickCallAI
{
public function __construct(
private string $apiKey,
private string $baseUrl = 'https://ai.quickcall.tech/api'
) {
$this->baseUrl = rtrim($this->baseUrl, '/');
}
private function request(string $method, string $path, ?array $payload = null): array
{
$ch = curl_init($this->baseUrl . $path);
curl_setopt_array($ch, [
CURLOPT_CUSTOMREQUEST => $method,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . $this->apiKey,
'Content-Type: application/json',
],
]);
if ($payload !== null) {
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($payload));
}
$body = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);
if ($body === false) {
throw new RuntimeException(curl_error($ch));
}
curl_close($ch);
$data = json_decode($body, true) ?: [];
if ($status >= 400 || ($data['success'] ?? true) === false) {
throw new RuntimeException($data['message'] ?? $data['error'] ?? $body);
}
return $data;
}
public function initiateCall(array $input): array
{
return $this->request('POST', '/calls/demo/initiate', [
'phone_number' => $input['phone_number'],
'customer_name' => $input['customer_name'] ?? 'Customer',
'prompt' => $input['prompt'],
'language' => $input['language'] ?? 'en-US',
'voice_model' => $input['voice_model'] ?? 'aura-asteria-en',
'provider' => $input['provider'] ?? 'twilio',
'agent_id' => $input['agent_id'] ?? null,
]);
}
public function getCallStatus(string $callId): array
{
return $this->request('GET', '/calls/demo/' . rawurlencode($callId) . '/status');
}
public function endCall(string $callId): array
{
return $this->request('POST', '/calls/demo/' . rawurlencode($callId) . '/end');
}
}Go SDK
package quickcallai
import (
"bytes"
"encoding/json"
"fmt"
"io"
"net/http"
"net/url"
"strings"
"time"
)
type Client struct {
APIKey string
BaseURL string
HTTP *http.Client
}
type InitiateCallRequest struct {
PhoneNumber string `json:"phone_number"`
CustomerName string `json:"customer_name"`
Prompt string `json:"prompt"`
Language string `json:"language,omitempty"`
VoiceModel string `json:"voice_model,omitempty"`
Provider string `json:"provider,omitempty"`
AgentID *string `json:"agent_id,omitempty"`
}
func New(apiKey string) *Client {
return &Client{
APIKey: apiKey,
BaseURL: "https://ai.quickcall.tech/api",
HTTP: &http.Client{Timeout: 30 * time.Second},
}
}
func (c *Client) do(method, path string, payload any, out any) error {
var body bytes.Buffer
if payload != nil {
if err := json.NewEncoder(&body).Encode(payload); err != nil {
return err
}
}
req, err := http.NewRequest(method, strings.TrimRight(c.BaseURL, "/")+path, &body)
if err != nil {
return err
}
req.Header.Set("Authorization", "Bearer "+c.APIKey)
req.Header.Set("Content-Type", "application/json")
resp, err := c.HTTP.Do(req)
if err != nil {
return err
}
defer resp.Body.Close()
respBody, err := io.ReadAll(resp.Body)
if err != nil {
return err
}
if len(respBody) == 0 {
return nil
}
var apiData map[string]any
if err := json.Unmarshal(respBody, &apiData); err != nil {
return err
}
if resp.StatusCode >= 400 || apiData["success"] == false {
return fmt.Errorf("quickcallai api error: %s %v", resp.Status, apiData)
}
if out == nil {
return nil
}
return json.Unmarshal(respBody, out)
}
func (c *Client) InitiateCall(input InitiateCallRequest, out any) error {
if input.Language == "" {
input.Language = "en-US"
}
if input.VoiceModel == "" {
input.VoiceModel = "aura-asteria-en"
}
if input.Provider == "" {
input.Provider = "twilio"
}
return c.do(http.MethodPost, "/calls/demo/initiate", input, out)
}
func (c *Client) GetCallStatus(callID string, out any) error {
return c.do(http.MethodGet, "/calls/demo/"+url.PathEscape(callID)+"/status", nil, out)
}
func (c *Client) EndCall(callID string, out any) error {
return c.do(http.MethodPost, "/calls/demo/"+url.PathEscape(callID)+"/end", nil, out)
}REST / cURL
curl -X POST "https://ai.quickcall.tech/api/calls/demo/initiate" \
-H "Authorization: Bearer $QUICKCALLAI_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"phone_number": "+15551234567",
"customer_name": "Asha Patel",
"prompt": "Confirm interest, answer questions, and book a demo slot.",
"language": "en-IN",
"voice_model": "google:en-IN-Chirp3-HD-Charon",
"provider": "twilio"
}'
curl "https://ai.quickcall.tech/api/calls/demo/CALL_ID/status" \
-H "Authorization: Bearer $QUICKCALLAI_API_KEY"3
Production guardrails
A production SDK must preserve the runtime lock that protects the real call path from drift.
- Always send E.164 phone numbers with a leading plus sign.
- Use exact provider and voice choices only after testing the route in the dashboard.
- Do not send API keys from browser code.
- Store call_id and call_sid so analytics, transcripts, recordings, and billing can reconcile later.
