hiSocial Voice Broadcast API
Place WhatsApp voice calls from your own number, run bulk voice campaigns, manage contacts and pull delivery reports — all programmatically over a simple REST API.
Base URL & response format
https://vapi.hisocial.in/api/v1 — e.g. https://vapi.hisocial.in/api/v1/creditsContent-Type: application/json on POST.Authentication
Send your API key on every request, using either header:
# Option 1 — Bearer token Authorization: Bearer hs_live_xxxxxxxxxxxxxxxxxxxxxxxx # Option 2 — X-API-Key header X-API-Key: hs_live_xxxxxxxxxxxxxxxxxxxxxxxx
Quick test
curl "https://vapi.hisocial.in/api/v1/credits" \ -H "Authorization: Bearer hs_live_xxxxxxxxxxxx"
Rate limiting
Each API key is limited to 60 requests per minute. Every response carries these headers:
429.When you exceed the limit you receive 429 with a JSON message. Back off until Retry-After seconds have passed.
Errors
Errors return the matching HTTP status and a JSON body { "message": "..." }.
Account
Returns the voice-credit balance for your account. One credit is consumed per completed call; non-completed calls are auto-refunded.
Request
curl "https://vapi.hisocial.in/api/v1/credits" \ -H "Authorization: Bearer hs_live_xxxx"
200 Response
{ "credits": 4820 }
Lists your connected WhatsApp devices. Use a device's id as deviceId when placing a call or creating a campaign. live reflects the real-time connection state.
200 Response
{
"devices": [
{
"id": 12,
"name": "Sales line",
"session_id": "dev_9f1c…",
"status": "connected",
"live": "open"
}
]
}
Voice calls
Places a single voice call to one number from a connected device. Returns immediately with identifiers; the call runs asynchronously. A credit is charged when the call connects and is refunded automatically if it doesn't complete.
Body parameters
| Field | Type | Notes |
|---|---|---|
deviceId required | integer | ID of a connected device (see /v1/devices). |
phone required | string | Recipient number in international format, e.g. 919812345678. |
mode optional | string | ai (default), tts, or human. |
ttsText optional | string | Text spoken to the recipient (for tts mode). |
voice optional | string | Voice name for speech synthesis. |
language optional | string | Language / locale hint, e.g. hi-IN. |
greeting optional | string | Opening line for ai mode. |
persona optional | string | AI agent persona / instructions. |
recipientName optional | string | Name used to personalise the call. |
Request
curl -X POST "https://vapi.hisocial.in/api/v1/call" \ -H "Authorization: Bearer hs_live_xxxx" \ -H "Content-Type: application/json" \ -d '{ "deviceId": 12, "phone": "919812345678", "mode": "tts", "ttsText": "Hello! Your order has shipped.", "language": "hi-IN" }'
201 Response
{
"dialId": "f3a9c1e2-…",
"callId": 88213
}
Checks whether a call placed via /v1/call is still active. Poll this to know when a call has ended.
200 Response
{ "active": true }
Ends an in-progress call immediately.
200 Response
{ "ok": true }
Campaigns
Imports a pre-recorded audio / mp3 link into your account. The file is downloaded to hiSocial and returns a local audioUrl you can use in an audio campaign. Supported: mp3, wav, ogg, m4a, aac, opus (max 25 MB).
Body parameters
| Field | Type | Notes |
|---|---|---|
url required | string | Public http/https link to the audio file, e.g. https://cdn.example.com/promo.mp3. |
Request
curl -X POST "https://vapi.hisocial.in/api/v1/audio" \ -H "Authorization: Bearer hs_live_xxxx" \ -H "Content-Type: application/json" \ -d '{"url":"https://cdn.example.com/promo.mp3"}'
201 Response
{
"audioUrl": "/uploads/voice_8f2c….mp3",
"bytes": 184320,
"contentType": "audio/mpeg"
}
audioUrl as the audioUrl when creating an audio campaign. Tip: you can skip this step — passing a full https://…mp3 link directly as audioUrl in Create campaign auto-imports it.Lists all your campaigns, newest first. voiceReady indicates whether voice rendering is available on the server.
200 Response
{
"campaigns": [
{ "id": 31, "name": "Diwali offer", "voice_type": "tts",
"status": "running", "group_id": 7, "device_id": 12 }
],
"voiceReady": true
}
Creates a bulk voice campaign. The campaign is created in a draft state — call /v1/campaigns/:id/start to begin dialing.
Body parameters
| Field | Type | Notes |
|---|---|---|
name required | string | Campaign name. |
deviceId optional | integer | Device to dial from. |
groupId optional | integer | Contact group to call (see contact groups). |
voiceType optional | string | tts (default), audio, or ai. |
ttsText optional | string | Message text for tts. |
ttsVoice, ttsLanguage optional | string | Voice & language for tts. |
audioUrl optional | string | Audio for audio mode. Pass a local /uploads/… path (from /v1/audio) or a public mp3 link — an external https://…mp3 is auto-downloaded. |
aiPrompt, aiScript optional | string | Instructions / script for ai mode. |
aiInteractive optional | boolean | Two-way AI conversation (default true). |
scheduledAt optional | string | ISO datetime to auto-start later. |
delayBetweenCalls optional | integer | Seconds between calls (0–3600, default 5). |
ringTimeout optional | integer | Ring timeout seconds (10–120, default 60). |
batchSize, batchSleep optional | integer | Batch size & pause between batches. |
Request
curl -X POST "https://vapi.hisocial.in/api/v1/campaigns" \ -H "Authorization: Bearer hs_live_xxxx" \ -H "Content-Type: application/json" \ -d '{ "name": "Diwali offer", "deviceId": 12, "groupId": 7, "voiceType": "tts", "ttsText": "Namaste! Diwali par 20% off.", "ttsLanguage": "hi-IN", "delayBetweenCalls": 8 }'
201 Response
{ "campaign": { "id": 31, "name": "Diwali offer", "status": "draft" } }
Starts (begins dialing the campaign's contact group) or stops a running campaign.
Request
curl -X POST "https://vapi.hisocial.in/api/v1/campaigns/31/start" \ -H "Authorization: Bearer hs_live_xxxx"
Duplicates a campaign as a fresh draft (same settings, no call history). Handy for re-running a completed campaign.
201 Response
{ "campaign": { "id": 53, "name": "Diwali offer (copy)", "status": "draft" } }
Delivery & credit analytics for one campaign: answer rate, completion, credits used/refunded, average duration, status & hour breakdown.
200 Response
{
"total": 1740, "completed": 1215, "answerRate": 70,
"creditsUsed": 1215, "creditsRefunded": 525,
"avgDurationSeconds": 31,
"byStatus": [ { "status": "completed", "count": 1215 } ],
"byHour": [ { "hour": 11, "total": 300, "completed": 240 } ]
}
Contacts
Lists your contact groups with a live contact count.
200 Response
{
"groups": [
{ "id": 7, "name": "Delhi leads", "description": "Q3", "contactCount": 1240 }
]
}
Creates a new contact group.
Body parameters
| Field | Type | Notes |
|---|---|---|
name required | string | Group name. |
description optional | string | Free-text description. |
201 Response
{ "group": { "id": 8, "name": "Mumbai leads" } }
Lists all contacts in a group.
200 Response
{
"group": { "id": 7, "name": "Delhi leads" },
"contacts": [
{ "id": 5501, "name": "Rahul", "phone": "919812345678" }
]
}
Reports
Aggregated call statistics for your account, with an optional date range.
Query parameters
| Field | Type | Notes |
|---|---|---|
from optional | string | Start date YYYY-MM-DD (inclusive). |
to optional | string | End date YYYY-MM-DD (inclusive). |
Request
curl "https://vapi.hisocial.in/api/v1/reports/summary?from=2026-09-01&to=2026-09-30" \ -H "Authorization: Bearer hs_live_xxxx"
200 Response
{
"range": { "from": "2026-09-01", "to": "2026-09-30" },
"total": 1740,
"completed": 1215,
"creditsUsed": 1215,
"creditsRefunded": 525,
"totalDurationSeconds": 38210,
"byStatus": [
{ "status": "completed", "count": 1215 },
{ "status": "no_answer", "count": 340 }
]
}
Returns your most recent calls (up to 500), newest first, including status, duration and transcription.
200 Response
{
"calls": [
{ "id": 88213, "phone_number": "919812345678", "status": "completed",
"duration_seconds": 42, "campaign_name": "Diwali offer",
"created_at": "2026-09-20 11:04:00" }
]
}
Returns full detail for one call, including the transcription and any customer replies received after the call.
200 Response
{
"call": {
"id": 88213, "status": "completed", "duration_seconds": 42,
"transcription": "Agent: Namaste…",
"replies": [ { "body": "Yes, interested", "wa_timestamp": "…" } ]
}
}
Downloads all your calls as an Excel .xlsx file (contact, number, campaign, status, duration, transcription, notes, date).
Request
curl "https://vapi.hisocial.in/api/v1/calls/export" \ -H "Authorization: Bearer hs_live_xxxx" \ -o reports.xlsx
Response
Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet
(binary .xlsx file)
Webhooks
Get a live POST to your server the moment a call finishes — no polling needed.
Events
Payload
Sent as JSON in the request body:
POST https://your-app.com/hisocial-webhook X-HiSocial-Event: call.completed X-HiSocial-Signature: sha256=<hmac> { "event": "call.completed", "call": { "id": 88213, "campaignId": 31, "campaign": "Diwali offer", "phone": "919812345678", "status": "completed", "durationSeconds": 27, "createdAt": "2026-09-20 11:04:00" }, "sentAt": "2026-09-20T11:05:00.000Z" }
Verify the signature
Each request carries X-HiSocial-Signature: sha256=<hmac> — an HMAC-SHA256 of the raw request body using your webhook secret. Always verify it before trusting the payload.
// Node.js (Express) const crypto = require('crypto'); function verify(rawBody, header, secret) { const expected = 'sha256=' + crypto.createHmac('sha256', secret).update(rawBody).digest('hex'); return crypto.timingSafeEqual(Buffer.from(header), Buffer.from(expected)); }
# Python (Flask) import hmac, hashlib def verify(raw_body, header, secret): expected = "sha256=" + hmac.new(secret.encode(), raw_body, hashlib.sha256).hexdigest() return hmac.compare_digest(header, expected)
2xx quickly. Only new calls (after you add the webhook) are delivered. Up to 10 active webhooks per account.SDKs & code samples
Copy-paste starters in PHP and JavaScript. Swap hs_live_xxxx for your key from My Account → Developer API.
PHP
A tiny reusable client (cURL)
<?php // hisocial.php — minimal hiSocial API client class HiSocial { private $base = 'https://vapi.hisocial.in/api'; private $key; public function __construct($apiKey) { $this->key = $apiKey; } public function request($method, $path, $body = null) { $ch = curl_init($this->base . $path); $headers = ['Authorization: Bearer ' . $this->key]; curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $method); if ($body !== null) { $headers[] = 'Content-Type: application/json'; curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($body)); } curl_setopt($ch, CURLOPT_HTTPHEADER, $headers); $res = curl_exec($ch); $code = curl_getinfo($ch, CURLINFO_HTTP_CODE); curl_close($ch); return ['status' => $code, 'body' => json_decode($res, true)]; } } $hi = new HiSocial('hs_live_xxxx'); // 1) Check credit balance $credits = $hi->request('GET', '/v1/credits'); echo "Credits: " . $credits['body']['credits'] . "\n"; // 2) Place a voice call $call = $hi->request('POST', '/v1/call', [ 'deviceId' => 12, 'phone' => '919812345678', 'mode' => 'tts', 'ttsText' => 'Namaste! Aapka order ship ho gaya hai.', 'language' => 'hi-IN', ]); echo "dialId: " . $call['body']['dialId'] . "\n"; // 3) Monthly report summary $rep = $hi->request('GET', '/v1/reports/summary?from=2026-09-01&to=2026-09-30'); print_r($rep['body']);
JavaScript / Node.js
Using the built-in fetch (Node 18+)
// hisocial.mjs — minimal hiSocial API client const BASE = 'https://vapi.hisocial.in/api'; const API_KEY = 'hs_live_xxxx'; async function hi(method, path, body) { const res = await fetch(BASE + path, { method, headers: { 'Authorization': `Bearer ${API_KEY}`, ...(body ? { 'Content-Type': 'application/json' } : {}), }, body: body ? JSON.stringify(body) : undefined, }); if (!res.ok) throw new Error(`${res.status}: ${(await res.json()).message}`); return res.json(); } // 1) Credit balance const { credits } = await hi('GET', '/v1/credits'); console.log('Credits:', credits); // 2) Create a campaign and start it const { campaign } = await hi('POST', '/v1/campaigns', { name: 'Diwali offer', deviceId: 12, groupId: 7, voiceType: 'tts', ttsText: 'Namaste! Diwali par 20% off.', ttsLanguage: 'hi-IN', }); await hi('POST', `/v1/campaigns/${campaign.id}/start`); console.log('Campaign started:', campaign.id); // 3) Report summary const report = await hi('GET', '/v1/reports/summary?from=2026-09-01&to=2026-09-30'); console.log(report);
Browser (fetch)
The API sends CORS headers for app.hisocial.in, so you can call it from the browser too. Never ship a secret key in public web pages — use browser calls only for internal/admin tools.
const res = await fetch('https://vapi.hisocial.in/api/v1/reports/summary', { headers: { 'X-API-Key': 'hs_live_xxxx' }, }); const data = await res.json(); // rate-limit headers are readable in the browser: console.log(res.headers.get('X-RateLimit-Remaining'), 'requests left'); console.log(data);
Python
Using requests (pip install requests)
# hisocial.py — minimal hiSocial API client import requests BASE = "https://vapi.hisocial.in/api" API_KEY = "hs_live_xxxx" class HiSocial: def __init__(self, api_key, base=BASE): self.s = requests.Session() self.s.headers.update({"Authorization": f"Bearer {api_key}"}) self.base = base def request(self, method, path, json=None): r = self.s.request(method, self.base + path, json=json) if r.status_code == 429: raise RuntimeError(f"Rate limited, retry after {r.headers.get('Retry-After')}s") r.raise_for_status() return r.json() hi = HiSocial(API_KEY) # 1) Credit balance print("Credits:", hi.request("GET", "/v1/credits")["credits"]) # 2) Place a voice call call = hi.request("POST", "/v1/call", json={ "deviceId": 12, "phone": "919812345678", "mode": "tts", "ttsText": "Namaste! Aapka order ship ho gaya hai.", "language": "hi-IN", }) print("dialId:", call["dialId"]) # 3) Monthly report summary report = hi.request("GET", "/v1/reports/summary?from=2026-09-01&to=2026-09-30") print(report)
Export the call report to a file
import requests r = requests.get( "https://vapi.hisocial.in/api/v1/calls/export", headers={"X-API-Key": "hs_live_xxxx"}, ) with open("reports.xlsx", "wb") as f: f.write(r.content) print("Saved reports.xlsx")
Go
Standard library only (net/http)
// hisocial.go — minimal hiSocial API client package main import ( "bytes" "encoding/json" "fmt" "io" "net/http" ) const ( baseURL = "https://vapi.hisocial.in/api" apiKey = "hs_live_xxxx" ) func request(method, path string, body any) (map[string]any, error) { var buf io.Reader if body != nil { b, _ := json.Marshal(body) buf = bytes.NewReader(b) } req, _ := http.NewRequest(method, baseURL+path, buf) req.Header.Set("Authorization", "Bearer "+apiKey) if body != nil { req.Header.Set("Content-Type", "application/json") } resp, err := http.DefaultClient.Do(req) if err != nil { return nil, err } defer resp.Body.Close() data, _ := io.ReadAll(resp.Body) if resp.StatusCode >= 400 { return nil, fmt.Errorf("%d: %s", resp.StatusCode, data) } var out map[string]any json.Unmarshal(data, &out) return out, nil } func main() { // 1) Credit balance credits, _ := request("GET", "/v1/credits", nil) fmt.Println("Credits:", credits["credits"]) // 2) Place a voice call call, err := request("POST", "/v1/call", map[string]any{ "deviceId": 12, "phone": "919812345678", "mode": "tts", "ttsText": "Namaste! Aapka order ship ho gaya hai.", "language": "hi-IN", }) if err != nil { panic(err) } fmt.Println("dialId:", call["dialId"]) // 3) Report summary report, _ := request("GET", "/v1/reports/summary?from=2026-09-01&to=2026-09-30", nil) fmt.Println(report) }
Ruby
Standard library only (net/http)
# hisocial.rb — minimal hiSocial API client require "net/http" require "json" require "uri" class HiSocial BASE = "https://vapi.hisocial.in/api" def initialize(api_key) @api_key = api_key end def request(method, path, body = nil) uri = URI(BASE + path) klass = { "GET" => Net::HTTP::Get, "POST" => Net::HTTP::Post }[method] req = klass.new(uri) req["Authorization"] = "Bearer #{@api_key}" if body req["Content-Type"] = "application/json" req.body = body.to_json end res = Net::HTTP.start(uri.host, uri.port, use_ssl: true) { |http| http.request(req) } raise "#{res.code}: #{res.body}" if res.code.to_i >= 400 JSON.parse(res.body) end end hi = HiSocial.new("hs_live_xxxx") # 1) Credit balance puts "Credits: #{hi.request('GET', '/v1/credits')['credits']}" # 2) Place a voice call call = hi.request("POST", "/v1/call", { deviceId: 12, phone: "919812345678", mode: "tts", ttsText: "Namaste! Aapka order ship ho gaya hai.", language: "hi-IN" }) puts "dialId: #{call['dialId']}" # 3) Report summary report = hi.request("GET", "/v1/reports/summary?from=2026-09-01&to=2026-09-30") pp report
Java
Java 11+ java.net.http.HttpClient (no dependencies)
// HiSocial.java — minimal hiSocial API client import java.net.URI; import java.net.http.*; import java.net.http.HttpRequest.BodyPublishers; import java.net.http.HttpResponse.BodyHandlers; public class HiSocial { static final String BASE = "https://vapi.hisocial.in/api"; static final String API_KEY = "hs_live_xxxx"; static final HttpClient client = HttpClient.newHttpClient(); static String request(String method, String path, String jsonBody) throws Exception { HttpRequest.Builder b = HttpRequest.newBuilder() .uri(URI.create(BASE + path)) .header("Authorization", "Bearer " + API_KEY); if (jsonBody != null) { b.header("Content-Type", "application/json") .method(method, BodyPublishers.ofString(jsonBody)); } else { b.method(method, BodyPublishers.noBody()); } HttpResponse<String> res = client.send(b.build(), BodyHandlers.ofString()); if (res.statusCode() >= 400) throw new RuntimeException(res.statusCode() + ": " + res.body()); return res.body(); } public static void main(String[] args) throws Exception { // 1) Credit balance System.out.println(request("GET", "/v1/credits", null)); // 2) Place a voice call String body = """ {"deviceId":12,"phone":"919812345678","mode":"tts", "ttsText":"Namaste! Aapka order ship ho gaya hai.","language":"hi-IN"} """; System.out.println(request("POST", "/v1/call", body)); // 3) Report summary System.out.println(request("GET", "/v1/reports/summary?from=2026-09-01&to=2026-09-30", null)); } }
C# / .NET
.NET 6+ HttpClient + System.Text.Json (built in)
// HiSocial.cs — minimal hiSocial API client using System.Net.Http; using System.Net.Http.Json; using System.Text.Json; var http = new HttpClient { BaseAddress = new Uri("https://vapi.hisocial.in/api") }; http.DefaultRequestHeaders.Add("Authorization", "Bearer hs_live_xxxx"); // 1) Credit balance var credits = await http.GetFromJsonAsync<JsonElement>("/v1/credits"); Console.WriteLine($"Credits: {credits.GetProperty("credits")}"); // 2) Place a voice call var res = await http.PostAsJsonAsync("/v1/call", new { deviceId = 12, phone = "919812345678", mode = "tts", ttsText = "Namaste! Aapka order ship ho gaya hai.", language = "hi-IN" }); res.EnsureSuccessStatusCode(); var call = await res.Content.ReadFromJsonAsync<JsonElement>(); Console.WriteLine($"dialId: {call.GetProperty("dialId")}"); // 3) Report summary var report = await http.GetStringAsync("/v1/reports/summary?from=2026-09-01&to=2026-09-30"); Console.WriteLine(report);
cURL recipes
Ready-to-run one-liners for the most common tasks. Replace hs_live_xxxx with your key.
Check your credit balance
curl "https://vapi.hisocial.in/api/v1/credits" \ -H "Authorization: Bearer hs_live_xxxx"
List connected devices (to get a deviceId)
curl "https://vapi.hisocial.in/api/v1/devices" \ -H "Authorization: Bearer hs_live_xxxx"
Place a text-to-speech voice call
curl -X POST "https://vapi.hisocial.in/api/v1/call" \ -H "Authorization: Bearer hs_live_xxxx" \ -H "Content-Type: application/json" \ -d '{"deviceId":12,"phone":"919812345678","mode":"tts","ttsText":"Namaste!","language":"hi-IN"}'
Poll a call's status, then hang up
# status curl "https://vapi.hisocial.in/api/v1/call/DIAL_ID/status" \ -H "Authorization: Bearer hs_live_xxxx" # hang up curl -X POST "https://vapi.hisocial.in/api/v1/call/DIAL_ID/hangup" \ -H "Authorization: Bearer hs_live_xxxx"
Create a campaign and start it
# create — capture the id from the JSON response curl -X POST "https://vapi.hisocial.in/api/v1/campaigns" \ -H "Authorization: Bearer hs_live_xxxx" \ -H "Content-Type: application/json" \ -d '{"name":"Diwali offer","deviceId":12,"groupId":7,"voiceType":"tts","ttsText":"Diwali par 20% off!","ttsLanguage":"hi-IN"}' # start campaign 31 curl -X POST "https://vapi.hisocial.in/api/v1/campaigns/31/start" \ -H "Authorization: Bearer hs_live_xxxx"
Monthly report summary (date range)
curl "https://vapi.hisocial.in/api/v1/reports/summary?from=2026-09-01&to=2026-09-30" \ -H "Authorization: Bearer hs_live_xxxx"
Download the full call report as Excel
curl "https://vapi.hisocial.in/api/v1/calls/export" \ -H "Authorization: Bearer hs_live_xxxx" \ -o reports.xlsx
Inspect rate-limit headers (-i shows response headers)
curl -i "https://vapi.hisocial.in/api/v1/credits" \ -H "Authorization: Bearer hs_live_xxxx" \ | grep -i "x-ratelimit"
X-API-Key: hs_live_xxxx header works everywhere the Authorization: Bearer header does — use whichever your tooling makes easier.Postman collection
Import the full API into Postman — every endpoint pre-built with example bodies, folders and collection-level auth.
https://app.hisocial.in/hisocial-api.postman_collection.json).apiKey to your hs_live_… key. Auth is already wired as Bearer {{apiKey}} on every request.baseUrl variable defaults to https://vapi.hisocial.in/api — change it only if instructed.OpenAPI / Swagger
Explore and test every endpoint interactively in Swagger UI ↗, or import the raw spec into your own tooling (Insomnia, Stoplight, code generators).
hs_live_… key, then Try it out.https://app.hisocial.in/openapi.json