CallwiseDocs

Ses hizmeti sözleşmesi

Ses hizmetinin arama oluşturmak, transkript turları eklemek ve aramaları kapatmak için çağırdığı imzalı webhook.

Yalnızca sözleşme

Bu bir sözleşmedir. Python ses hizmeti (WebRTC ve SIP üzerinde konuşmadan metne, dil modeli ve metinden konuşmaya) henüz yazılmamıştır. Webhook'un Callwise tarafı yazılmış ve test edilmiştir; üretimde onu çağıran bir şey yoktur.

Arama kayıtlarını yazan tek taraf ses hizmetidir. Her aramayı uygulamaya bir dizi olay olarak bildirir. Yükün kaynağı, apps/web/lib/callwise/voice-events.ts içindeki zod şeması voiceEventSchema değeridir.

Uç nokta

POST /api/voice/events
Content-Type: application/json
x-callwise-timestamp: 1760530212
x-callwise-signature: 5f0c2e…(64 hex characters)

İmzalama

ÜstbilgiDeğer
x-callwise-timestampİsteğin imzalandığı andaki Unix zamanı, saniye cinsinden
x-callwise-signature`${timestamp}.${rawBody}` ifadesinin, paylaşılan gizli anahtar CALLWISE_VOICE_SECRET ile alınmış onaltılık HMAC-SHA256 değeri

Gönderdiğiniz baytların aynısını imzalayın. Uygulama, gövdeyi ayrıştırmadan önce imzayı ham gövde üzerinden yeniden hesaplar.

import { createHmac } from 'node:crypto';

const timestamp = Math.floor(Date.now() / 1000).toString();
const rawBody = JSON.stringify(event);
const signature = createHmac('sha256', process.env.CALLWISE_VOICE_SECRET!)
  .update(`${timestamp}.${rawBody}`)
  .digest('hex');
import hmac, hashlib, json, os, time

timestamp = str(int(time.time()))
raw_body = json.dumps(event, separators=(",", ":"))
signature = hmac.new(
    os.environ["CALLWISE_VOICE_SECRET"].encode(),
    f"{timestamp}.{raw_body}".encode(),
    hashlib.sha256,
).hexdigest()

Zaman damgası sunucu saatinden 5 dakikadan fazla sapan istekler reddedilir; bu, eski isteklerin yeniden oynatılmasını engeller.

Yanıtlar

DurumNe zaman
200 { "ok": true, "duplicate": false }Olay uygulandı
200 { "ok": true, "duplicate": true }Bu id ile bir olay zaten uygulanmıştı; hiçbir şey değişmedi
400Gövde geçerli bir JSON değil veya şemayla eşleşmiyor (örneğin bilinmeyen bir olay türü)
401İmza eksik veya yanlış ya da zaman damgası 5 dakikalık pencerenin dışında

Yineleme güvenliği

Her olayın kendi id değeri vardır. Aynı olayı iki kez göndermek güvenlidir: ikincisi duplicate: true ile onaylanır ve yok sayılır. Ağ hatalarında ve 5xx yanıtlarında aynı id ile yeniden deneyin.

Olayın biçimi

Her olayın zarfı aynıdır:

AlanTürNotlar
idstring, 1–200 karakterOlay kimliği; olay başına benzersiz
typecall.started | call.turn | call.ended
accountIduuidÇalışma alanı (ekip hesabı)
callnesnecall.id (uuid) zorunludur. Onu ses hizmeti seçer ve o aramanın her olayında aynı kimliği kullanır.
turnnesneYalnızca call.turn üzerinde

call.started

Canlı bir arama oluşturur. Arayan, telefon numarasıyla eşleştirilir veya yeni oluşturulur. agentId verilmezse ajan, aranan numaradan seçilir.

{
  "id": "evt_01JA8S0K6Q2M3",
  "type": "call.started",
  "accountId": "3c1d6c1e-5c55-4f3e-9d0b-6b1f6f2a7a10",
  "call": {
    "id": "9b2f7d4e-1a7c-4e0f-8f5e-2d6c4b9a1e33",
    "to": "+15552108842",
    "callerPhone": "+15551237890",
    "callerName": "Emily Johnson",
    "direction": "inbound",
    "startedAt": "2026-10-15T13:41:02Z",
    "isTest": false,
    "afterHours": false
  }
}

İsteğe bağlı call alanları şunlardır: numberId (uuid) veya to (E.164), agentId, locationId, callerPhone, callerName, direction (inbound veya outbound), startedAt (ISO 8601), isTest, afterHours.

call.turn

Transkripte bir satır ekler. call yalnızca kimliği taşır. Turlar (call id, seq) ile saklanır; bu yüzden bir turu yeniden göndermek onun yerini alır.

{
  "id": "evt_01JA8S0M1T7Z4",
  "type": "call.turn",
  "accountId": "3c1d6c1e-5c55-4f3e-9d0b-6b1f6f2a7a10",
  "call": { "id": "9b2f7d4e-1a7c-4e0f-8f5e-2d6c4b9a1e33" },
  "turn": {
    "seq": 1,
    "atMs": 4200,
    "speaker": "caller",
    "text": "Hi, I need a cleaning next week."
  }
}
turn alanıTür
seq0 veya daha büyük tamsayı; arama içindeki sıra
atMs0 veya daha büyük tamsayı; arama başladığından beri geçen milisaniye
speakeragent | caller | staff | system
textstring

call.ended

Aramayı kapatır. Faturalanan dakikalar ceil(durationS / 60) değeridir ve günün kullanımına eklenir. Uygulama ardından arama için kredi tahsil eder: faturalanan dakikalar çarpı ajanın model yığını oranı, artı bir özet (bkz. Yapay zeka modelleri ve krediler). Tutar, paylaşılan kredi havuzundan alınır. summary verilmezse bir şablon özeti doldurulur.

call.started yanıtı, ses hizmetine aramanın nasıl yönlendirileceğini söyler: route: "agent" veya kredi havuzu, eşzamanlılık sınırı ya da saatlik sınır izin vermediğinde bir reason ile birlikte route: "fallback". Aramalar asla düşürülmez.

{
  "id": "evt_01JA8S2B9W0K8",
  "type": "call.ended",
  "accountId": "3c1d6c1e-5c55-4f3e-9d0b-6b1f6f2a7a10",
  "call": {
    "id": "9b2f7d4e-1a7c-4e0f-8f5e-2d6c4b9a1e33",
    "endedAt": "2026-10-15T13:42:26Z",
    "durationS": 84,
    "intent": "booking",
    "topic": "Dental cleaning",
    "outcome": "booked",
    "sentiment": "positive",
    "confidence": 0.96,
    "summary": "New caller booked a dental cleaning for Tuesday at 10:00.",
    "recordingPath": "3c1d6c1e-5c55-4f3e-9d0b-6b1f6f2a7a10/9b2f7d4e-1a7c-4e0f-8f5e-2d6c4b9a1e33.mp3"
  }
}
call alanıDeğerler
endedAtISO 8601
durationSsaniye cinsinden tamsayı
intentbooking reschedule cancel pricing insurance billing hours emergency general spam
topicserbest metin
outcomebooked rescheduled cancelled info transferred voicemail missed spam
sentimentpositive neutral negative
confidence0–1
summaryserbest metin
handoffReasonserbest metin; sonuç transferred olduğunda
recordingPathözel cw-recordings kovasında <accountId>/<callId>.mp3

Nasıl uygulanır

Rota, imzayı ve şemayı denetler; ardından hizmet rolüyle Postgres işlevi cw_apply_voice_event(jsonb) çağrısını yapar. Bu işlevi yalnızca hizmet rolü çalıştırabilir. Oturum açmış kullanıcıların aramalarda veya turlarda ekleme izni yoktur; bu yüzden arama kayıtlarının oluşturulmasının tek yolu webhook'tur.

Yayından önce

Gecikme, araya girmenin ele alınması ve gizli anahtarın döndürülmesi konusunda doğrulanması gerekenler için Bağlantılar altındaki ses hizmeti maddesine bakın.

On this page