Auto Call

Runs an announcement, IVR or survey call to a list of numbers; returns the result and keypresses. Integration key (bt_…, scope autocall).

Endpoint: https://api.buluthat.com/api/autocall.php?action=<işlem>

Typical flow:

1. media          -> anons id'sini al (ya da tts_template kullan)
2. trunks         -> çıkış hattının slug'ını al
3. create_campaign -> status "draft", digit_labels ile anket seçenekleri
4. add_leads      -> numaraları partiler hâlinde gönder
5. start          -> kampanyayı kuyruğa al
6. webhook        -> sonuçlar size gelsin (ya da results ile çekin)
7. summary        -> tuş dağılımı

GETping · media · trunks · caller_ids

GET https://api.buluthat.com/api/autocall.php?action=ping
GET https://api.buluthat.com/api/autocall.php?action=media       → [{ "id": 12, "name": "Hatırlatma anonsu" }]
GET https://api.buluthat.com/api/autocall.php?action=trunks      → çıkış hatları (slug)
GET https://api.buluthat.com/api/autocall.php?action=caller_ids  → kullanılabilir arayan numaralar

POSTcreate_campaign

curl -X POST "https://api.buluthat.com/api/autocall.php?action=create_campaign" \
  -H "Authorization: Bearer bt_xxx" -H "Content-Type: application/json" \
  -d '{
    "name": "Randevu hatırlatma",
    "campaign_type": "survey",
    "trunk_slug": "hat-1",
    "caller_id": "02124119610",
    "tts_enabled": true,
    "tts_template": "Merhaba {sayin}, {randevu} randevunuzu hatırlatmak için aradık. Geliyorsanız 1, iptal için 2.",
    "digit_labels": { "1": "Geliyorum", "2": "İptal" },
    "digit_destinations": { "9": "queue:4" },
    "start_time": "09:00", "end_time": "18:00",
    "weekdays": ["mon","tue","wed","thu","fri"],
    "max_channels": 3, "ring_timeout_seconds": 30,
    "retry_count": 1, "retry_delay_minutes": 30,
    "amd_enabled": true, "amd_action": "hangup",
    "webhook_url": "https://ornek.com/buluthat/sonuc",
    "webhook_secret": "gizli",
    "webhook_events": "call_finished,dtmf",
    "status": "draft",
    "leads": [ { "phone": "05551112233", "name": "Ahmet Yılmaz", "external_id": "CRM-1", "fields": { "randevu": "12 Eylül 14:00" } } ]
  }'

Required: name, trunk_slug and media_file_id or tts_template. If both are given, the personalized voice plays first, then the ready-made announcement.

FieldValuesNote
campaign_typeannouncement, ivr, surveyannouncement plays the announcement and hangs up, doesn't wait for a key
digit_labels{"1":"Evet"}Fill in for the survey. A key with a label is recorded even if it has no destination
digit_destinations{"9":"queue:4"}Transfers whoever presses a key: ext:1001, queue:4, ivr:2, flow:3, repeat, hangup
amd_actionhangup, play, continueWhat to do when it reaches an answering machine
tts_template"Sayın {ad}, …"Variables: {sayin}, {unvan}, {adi}, {ad}, {telefon} and fields fields
statusdraft, queuedqueued if you give it, the campaign enters the queue immediately
retry_count / retry_delay_minutesnumberRedial for unanswered/busy
thanks_tts_texttextThank-you message after the survey keypress

Response: { "ok": true, "data": { "id": 7, "status": "draft", … } }

POSTupdate_campaign

Partial update; only the fields sent change. status do not send (it drops a running campaign); for status start/pause/cancel use.

{ "campaign_id": 7, "max_channels": 5, "retry_count": 2 }

POSTadd_leads

At most 5.000 records per request. The same number is not added a second time in the same campaign (duplicate).

{ "campaign_id": 7, "leads": [ { "phone": "05551112233", "name": "Ahmet Yılmaz", "external_id": "CRM-1", "fields": { "borc": "1.240 TL" } } ] }

Short form: { "campaign_id": 7, "phones": ["05551112233", "05551112234"] }

Response: { "inserted": 2, "duplicate": 0, "invalid": 0 }

POSTrequeue_leads

Requeues previously called numbers (calls is reset, keypress cleared). A number already waiting is not touched (skipped). For payment reminders, use it to call again based on your own records rather than trusting the "I paid" key.

{ "campaign_id": 7, "phones": ["05551112233"] }

POSTstart · pause · cancel

{ "campaign_id": 7 }

start queues the campaign; calls start within the day/time window. If you add numbers to a completed campaign, the campaign reopens automatically.

GETresults

Result per number. limit (default 200, at most 1000), offset; filters status, dtmf, phone.

GET https://api.buluthat.com/api/autocall.php?action=results&campaign_id=7&dtmf=1
{
  "ok": true, "total": 512, "limit": 200, "offset": 0,
  "data": [ {
    "campaign_id": 7, "lead_id": 91, "external_id": "CRM-1",
    "phone": "05551112233", "name": "Ahmet Yılmaz",
    "status": "answered", "attempts": 1,
    "dtmf": "1", "dtmf_label": "Geliyorum", "dtmf_all": ["1"],
    "amd_result": "HUMAN", "duration_seconds": 34, "talk_seconds": 22,
    "hangup_cause": "ANSWERED",
    "started_at": "2026-09-04 10:12:03", "answered_at": "2026-09-04 10:12:11", "ended_at": "2026-09-04 10:12:33",
    "custom_fields": { "randevu": "12 Eylül 14:00" }
  } ]
}

Statuses: pending, calling, answered, machine, no_answer, busy, failed, cancelled.

GETsummary

{ "ok": true, "data": {
  "total": 512, "answered": 388, "pressed": 301, "machine": 44,
  "answer_rate": 75.8, "press_rate": 77.6, "talk_seconds": 8624, "avg_talk_seconds": 22,
  "digits": [ { "digit": "1", "label": "Geliyorum", "total": 214, "percent": 55.2 }, { "digit": "2", "label": "İptal", "total": 87, "percent": 22.4 } ]
} }

GETevents

Campaign event log (originate, answered, amd, dtmf, cdr, error) — for diagnostics.

Webhook

webhook_url if defined, Buluthat POSTs the result to you. Events: call_finished (once per number), dtmf (the moment a key is pressed), campaign_finished. Headers X-Buluthat-Event, X-Buluthat-Delivery, X-Buluthat-Signature: sha256=… (webhook_secret if given). Body results carries the same fields as. For signature verification and retry policy see Webhooks.

Personalized announcements and cost

The template is split into fixed and variable parts; the fixed sentence is voiced once in a list of a thousand people, the same {tutar} the value is not synthesized a second time (measured saving 97,9%). Send variable values in the standard format ("1.000 TL" always typed the same). The Mr./Ms. distinction is automatic from the name; for unisex names the title is left blank.

PHP client

Downloaded from Panel > Auto Call > API tab buluthat-autocall-client.php:

require_once 'buluthat-autocall-client.php';
$bt = new BuluthatAutoCall('https://api.buluthat.com', 'bt_xxx');
$k = $bt->createCampaign(['name' => 'Ödeme hatırlatma', 'campaign_type' => 'survey', 'trunk_slug' => 'hat-1',
    'tts_enabled' => true, 'tts_template' => 'Merhaba {sayin}, {tutar} tutarındaki ödemenizi hatırlatmak için aradık. Ödediyseniz 1, ödemediyseniz 2.',
    'digit_labels' => ['1' => 'Ödedim', '2' => 'Ödemedim'], 'webhook_url' => 'https://crm.example.com/buluthat-sonuc.php']);
$bt->addLeads($k['id'], [['phone' => '05551112233', 'name' => 'Burak Yılmaz', 'external_id' => 'CARI-451', 'fields' => ['tutar' => '1.000 TL']]]);
$bt->start($k['id']);

// webhook tarafı
$olay = BuluthatAutoCall::readWebhook($secret);   // imzayı doğrular
if ($olay['event'] === 'call_finished' && $olay['data']['dtmf'] === '1') { /* ödedim dedi */ }