Arendajale
Hallake agente, numbreid ja kõnesid oma süsteemidest ning lisage häälkõne oma veebilehele.
Ülevaade
Tegemist on REST API-ga. Päringute ja vastuste sisu on JSON (UTF-8), ajatemplid on unix-sekundites ja summad USD-s. Baas-URL on:
https://hubvocal.com/v1
API-võti kuulub ühele organisatsioonile ja toimib selles administraatori õigustega. Kõike, mida saab teha juhtpaneelil, saab teha ka API-ga:
| Ressurss | Otspunktid |
|---|---|
| Agendid | /v1/agents, /v1/agents/{id} |
| Teadmusbaas | /v1/knowledge, /v1/knowledge/{id}, /v1/knowledge/search |
| Tööriistad | /v1/tools, /v1/tools/{id}, /v1/tools/{id}/test |
| MCP-serverid | /v1/mcp-servers, /v1/mcp-servers/{id}, /v1/mcp-servers/{id}/sync |
| Webhookid | /v1/webhooks, /v1/webhooks/{id}, /v1/webhooks/{id}/deliveries |
| Hääled ja mootorid | /v1/voices |
| Veebikõned | /v1/web-calls |
| Kõned ja väljuvad kõned | /v1/calls, /v1/calls/{room} |
| Numbrid | /v1/numbers, /v1/numbers/{number} |
| Kasutus | /v1/usage |
Masinloetav OpenAPI 3.1 dokument on saadaval aadressil GET /v1/openapi.json ja ei vaja võtit. Kõigi otspunktide üksikasjad leiate API viitest.
Kiirjuhend
-
Looge API-võti
Avage juhtpaneelil Seaded > API-võtmed ja andke võtmele nimi, mis ütleb, milleks see on. Võtmeid saavad luua ainult organisatsiooni omanikud ja administraatorid. Saladust (
vt_live_…) näidatakse ühe korra; salvestage see kohe saladuste haldurisse.export VT_API_KEY="vt_live_…" -
Kuvage oma agendid
Kiireim viis kontrollida, kas võti töötab. Vastuses olevat id-d läheb vaja järgmistes sammudes.
curlcurl "https://hubvocal.com/v1/agents" \ -H "Authorization: Bearer $VT_API_KEY"JavaScriptconst res = await fetch("https://hubvocal.com/v1/agents", { headers: { Authorization: `Bearer ${process.env.VT_API_KEY}`, }, }); const data = await res.json(); if (!res.ok) throw new Error(`${res.status}: ${data.detail}`); console.log(data);Pythonimport os import requests resp = requests.get( "https://hubvocal.com/v1/agents", headers={"Authorization": f"Bearer {os.environ['VT_API_KEY']}"}, timeout=30, ) if not resp.ok: raise RuntimeError(f"{resp.status_code}: {resp.json()['detail']}") print(resp.json()) -
Looge agent
Mootor, keel, hääl ja juhised ühes objektis. Lubatud häälenimed ja piirangud tagastab
GET /v1/voices.curlcurl -X POST "https://hubvocal.com/v1/agents" \ -H "Authorization: Bearer $VT_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "name": "Front desk", "lang": "en", "engine": "live", "instructions": "You are the front desk assistant for a dental clinic. Help callers book appointments and answer general questions briefly. Never make things up; offer a callback from the team instead.", "greeting": "Hello, thanks for calling the clinic. How can I help you today?", "voice": { "voice": "marin", "speed": 1 }, "tools": { "builtins": [ "end_call", "take_message" ], "webhooks": [ "tl_8f3a2c" ] }, "turn": { "first_speaker": "agent", "idle_check_s": 30 }, "recording": { "enabled": false, "announce": true }, "post_call": { "summary": true, "fields": [ { "name": "appointment_date", "type": "date", "description": "Requested appointment date, if any" }, { "name": "callback", "type": "boolean", "description": "Does the caller want a callback?" } ] }, "knowledge": { "doc_ids": [ "kb_7d21e4" ], "mode": "tool" } }'JavaScriptconst res = await fetch("https://hubvocal.com/v1/agents", { method: "POST", headers: { Authorization: `Bearer ${process.env.VT_API_KEY}`, "Content-Type": "application/json", }, body: JSON.stringify({ "name": "Front desk", "lang": "en", "engine": "live", "instructions": "You are the front desk assistant for a dental clinic. Help callers book appointments and answer general questions briefly. Never make things up; offer a callback from the team instead.", "greeting": "Hello, thanks for calling the clinic. How can I help you today?", "voice": { "voice": "marin", "speed": 1 }, "tools": { "builtins": [ "end_call", "take_message" ], "webhooks": [ "tl_8f3a2c" ] }, "turn": { "first_speaker": "agent", "idle_check_s": 30 }, "recording": { "enabled": false, "announce": true }, "post_call": { "summary": true, "fields": [ { "name": "appointment_date", "type": "date", "description": "Requested appointment date, if any" }, { "name": "callback", "type": "boolean", "description": "Does the caller want a callback?" } ] }, "knowledge": { "doc_ids": [ "kb_7d21e4" ], "mode": "tool" } }), }); const data = await res.json(); if (!res.ok) throw new Error(`${res.status}: ${data.detail}`); console.log(data);Pythonimport os import requests resp = requests.post( "https://hubvocal.com/v1/agents", headers={"Authorization": f"Bearer {os.environ['VT_API_KEY']}"}, json={ "name": "Front desk", "lang": "en", "engine": "live", "instructions": "You are the front desk assistant for a dental clinic. Help callers book appointments and answer general questions briefly. Never make things up; offer a callback from the team instead.", "greeting": "Hello, thanks for calling the clinic. How can I help you today?", "voice": { "voice": "marin", "speed": 1, }, "tools": { "builtins": [ "end_call", "take_message", ], "webhooks": [ "tl_8f3a2c", ], }, "turn": { "first_speaker": "agent", "idle_check_s": 30, }, "recording": { "enabled": False, "announce": True, }, "post_call": { "summary": True, "fields": [ { "name": "appointment_date", "type": "date", "description": "Requested appointment date, if any", }, { "name": "callback", "type": "boolean", "description": "Does the caller want a callback?", }, ], }, "knowledge": { "doc_ids": [ "kb_7d21e4", ], "mode": "tool", }, }, timeout=30, ) if not resp.ok: raise RuntimeError(f"{resp.status_code}: {resp.json()['detail']}") print(resp.json()) -
Alustage veebikõnet
Brauserist ühendute vastuses olevate väärtustega
server_urljatoken; üksikasjad allpool.curlcurl -X POST "https://hubvocal.com/v1/web-calls" \ -H "Authorization: Bearer $VT_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "agent_id": "front-desk" }'JavaScriptconst res = await fetch("https://hubvocal.com/v1/web-calls", { method: "POST", headers: { Authorization: `Bearer ${process.env.VT_API_KEY}`, "Content-Type": "application/json", }, body: JSON.stringify({ "agent_id": "front-desk" }), }); const data = await res.json(); if (!res.ok) throw new Error(`${res.status}: ${data.detail}`); console.log(data);Pythonimport os import requests resp = requests.post( "https://hubvocal.com/v1/web-calls", headers={"Authorization": f"Bearer {os.environ['VT_API_KEY']}"}, json={ "agent_id": "front-desk", }, timeout=30, ) if not resp.ok: raise RuntimeError(f"{resp.status_code}: {resp.json()['detail']}") print(resp.json())
Autentimine
Saatke võti igas päringus Bearer-tokenina päises Authorization:
Authorization: Bearer vt_live_… - Võti toimib teie organisatsioonis administraatori õigustega: loob agente, määrab numbreid ja teeb kõnesid. Hoidke seda nagu parooli.
- Ärge kunagi pange võtit brauseri koodi, mobiilirakendusse ega repositooriumi. Brauserikõnede jaoks hankige oma serveris lühiajaline token.
- Loendis Seaded > API-võtmed on näha, millal iga võtit viimati kasutati. Tühistatud võti lakkab kohe töötamast.
- Kasutage iga integratsiooni jaoks eraldi võtit, et ühe tühistamine teisi ei lõhuks.
Veebikõne lehele
Teie külastajad saavad agendiga rääkida otse teie lehel, brauseris. Selleks on kolm sammu:
- Külastaja vajutab nuppu ja teie leht pöördub teie enda serveri poole.
- Teie server kutsub API-võtmega välja
POST /v1/web-callsja edastab vastuse (server_url,token,room,max_seconds) lehele. - Leht ühendub ruumiga teegi
livekit-clientabil ja lülitab mikrofoni sisse. Agent liitub ise ja ütleb tervituse.
1. Server: hankige token
// server.js (Node 18+, Express)
import express from "express";
const app = express();
app.post("/voice/session", async (req, res) => {
// Lisage siia oma autentimine ja päringupiirang.
const r = await fetch("https://hubvocal.com/v1/web-calls", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.VT_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({ agent_id: "front-desk" }),
});
res.status(r.status).json(await r.json());
});
app.listen(3000); # app.py (Flask)
import os
import requests
from flask import Flask, jsonify
app = Flask(__name__)
@app.post("/voice/session")
def voice_session():
# Lisage siia oma autentimine ja päringupiirang.
r = requests.post(
"https://hubvocal.com/v1/web-calls",
headers={"Authorization": f"Bearer {os.environ['VT_API_KEY']}"},
json={"agent_id": "front-desk"},
timeout=15,
)
return jsonify(r.json()), r.status_code 2. Brauser: ühenduge
Kui kasutate komplekteerijat, paigaldage npm install livekit-client@2.23.0 ja importige samad nimed. Allolev näide laadib CDN-ist kindla versiooni.
<button id="talk" type="button">Alusta vestlust</button>
<script type="module">
import { Room, RoomEvent, Track } from "https://cdn.jsdelivr.net/npm/livekit-client@2.23.0/dist/livekit-client.esm.mjs";
const button = document.getElementById("talk");
let room;
button.addEventListener("click", async () => {
if (room) {
await room.disconnect();
return;
}
button.disabled = true;
// Teie server tagastab POST /v1/web-calls vastuse muutmata kujul.
const res = await fetch("/voice/session", { method: "POST" });
const session = await res.json();
if (!res.ok) {
button.disabled = false;
alert(session.detail);
return;
}
room = new Room();
// Kui agendi heli saabub, ühendage see <audio> elemendiga.
room.on(RoomEvent.TrackSubscribed, (track) => {
if (track.kind === Track.Kind.Audio) document.body.appendChild(track.attach());
});
room.on(RoomEvent.Disconnected, () => {
room?.remoteParticipants.forEach((p) =>
p.audioTrackPublications.forEach((pub) => pub.track?.detach().forEach((el) => el.remove())),
);
room = undefined;
button.textContent = "Alusta vestlust";
});
await room.connect(session.server_url, session.token);
await room.localParticipant.setMicrophoneEnabled(true);
button.disabled = false;
button.textContent = "Lõpeta kõne";
});
</script> Alustage ühendust kasutaja tegevuse (klõpsu) peale: brauserid seovad sellega mikrofoni loa ja heli automaatse esitamise. Leht peab olema avatud üle HTTPS-i.
Kõne kestab kõige rohkem max_seconds, seejärel agent lõpetab kõne. Kui kõne on lõppenud, hankige selle kirje päringuga GET /v1/calls/{room}.
Väljuvad kõned
Helistage numbrile mõnelt oma organisatsiooni numbrilt; agent räägib, kui kõnele vastatakse. Number from peab olema loendis GET /v1/numbers. Ilma väljata agent_id kasutatakse sellele numbrile määratud agenti. Numbrid on E.164 vormingus (+90…).
curl -X POST "https://hubvocal.com/v1/calls" \
-H "Authorization: Bearer $VT_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"from": "+908501234567",
"to": "+905321234567",
"agent_id": "front-desk"
}' const res = await fetch("https://hubvocal.com/v1/calls", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.VT_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
"from": "+908501234567",
"to": "+905321234567",
"agent_id": "front-desk"
}),
});
const data = await res.json();
if (!res.ok) throw new Error(`${res.status}: ${data.detail}`);
console.log(data); import os
import requests
resp = requests.post(
"https://hubvocal.com/v1/calls",
headers={"Authorization": f"Bearer {os.environ['VT_API_KEY']}"},
json={
"from": "+908501234567",
"to": "+905321234567",
"agent_id": "front-desk",
},
timeout=30,
)
if not resp.ok:
raise RuntimeError(f"{resp.status_code}: {resp.json()['detail']}")
print(resp.json()) Vastus
{
"room": "tel-out-9c41e0b7",
"provider": "didww",
"sip_call_id": "SCL_7mVt2kQb9xRa"
} Vastuses olev room tähistab kõnet. Kui kõne on lõppenud, on selle kirje (ärakiri, kulu, kes kõne lõpetas) saadaval päringuga GET /v1/calls/{room}. Vastamata kõned lõpevad nii, et ended_by väärtus on no_answer.
Sissetulevad kõned
Teie numbritele saabuvatele kõnedele vastab numbrile määratud agent. Numbrid tulevad DIDWW, Twilio või teie oma SIP-trungi kaudu (Asterisk jt) ja platvormi meeskond lisab need teie organisatsiooni. Teie valite, milline agent vastab:
curl -X PUT "https://hubvocal.com/v1/numbers/%2B908501234567" \
-H "Authorization: Bearer $VT_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"agent_id": "front-desk",
"label": "Main line"
}' const res = await fetch("https://hubvocal.com/v1/numbers/%2B908501234567", {
method: "PUT",
headers: {
Authorization: `Bearer ${process.env.VT_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
"agent_id": "front-desk",
"label": "Main line"
}),
});
const data = await res.json();
if (!res.ok) throw new Error(`${res.status}: ${data.detail}`);
console.log(data); import os
import requests
resp = requests.put(
"https://hubvocal.com/v1/numbers/%2B908501234567",
headers={"Authorization": f"Bearer {os.environ['VT_API_KEY']}"},
json={
"agent_id": "front-desk",
"label": "Main line",
},
timeout=30,
)
if not resp.ok:
raise RuntimeError(f"{resp.status_code}: {resp.json()['detail']}")
print(resp.json()) Versioonid ja turvaline avaldamine
Agendi muutmisel muutub selle mustand. Kõned teie numbritele, veebikõned ja väljuvad kõned kasutavad avaldatud versiooni, nii et saate mustandiga töötada ilma päris kõnesid mõjutamata.
- Muutke agenti päringuga
PUT /v1/agents/{id}. See muudab ainult mustandit;draft_changedsaab väärtuseks true. - Testige mustandit: alustage veebikõnet parameetriga
version: "draft". - Avaldage päringuga
POST /v1/agents/{id}/publish, soovi korral märkusega. Mustandist saab uus nummerdatud versioon, mida kõned hakkavad kasutama. - Kui midagi läks valesti, avaldab
POST /v1/agents/{id}/rollbackkoos varasema versiooni numbriga selle versiooni uuesti, uue versioonina.
curl -X POST "https://hubvocal.com/v1/agents/front-desk/publish" \
-H "Authorization: Bearer $VT_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"note": "Shorter greeting"
}' const res = await fetch("https://hubvocal.com/v1/agents/front-desk/publish", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.VT_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
"note": "Shorter greeting"
}),
});
const data = await res.json();
if (!res.ok) throw new Error(`${res.status}: ${data.detail}`);
console.log(data); import os
import requests
resp = requests.post(
"https://hubvocal.com/v1/agents/front-desk/publish",
headers={"Authorization": f"Bearer {os.environ['VT_API_KEY']}"},
json={
"note": "Shorter greeting",
},
timeout=30,
)
if not resp.ok:
raise RuntimeError(f"{resp.status_code}: {resp.json()['detail']}")
print(resp.json()) POST /v1/web-calls ja POST /v1/calls võtavad vastu välja version: "live" (vaikimisi), "draft" või versiooni number. Agent, mida pole kunagi avaldatud, kasutab oma mustandit.
curl -X POST "https://hubvocal.com/v1/web-calls" \
-H "Authorization: Bearer $VT_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"agent_id": "front-desk",
"version": "draft"
}' Testimine enne avaldamist
Testilabor viib läbi tekstivestlusi simuleeritud helistaja ja teie agendi vahel, et saaksite muudatust kontrollida enne, kui päris helistajad seda kuulevad.
- Kirjutage stsenaarium: kes helistab (
persona), mida ta soovib (goal) ja kuni 20 repliiki. - Lisage reeglid, millele hea kõne peab vastama (
expect), näiteks „küsib enne broneerimist helistaja nime“. - Andke tööriistadele näidistulemused (
mocks); päris tööriistu ega webhooke välja ei kutsuta. - Käivitage stsenaariumid mustandi peal. Eraldi mudel kontrollib iga reeglit ja selgitab, miks see täideti või jäi täitmata.
{
"scenarios": [
{
"name": "Booking without a name",
"persona": "A caller in a hurry who gives short answers",
"goal": "Book an appointment tomorrow afternoon",
"max_turns": 12,
"expect": [
"Asks for the caller's name before booking",
"Reads the time back and asks for confirmation"
],
"mocks": {
"check_availability": {
"ok": true,
"slots": [
"2026-11-06T14:00",
"2026-11-06T15:30"
]
}
}
}
],
"version": "draft"
} Vestlused toimuvad tekstirežiimis, seega testitakse juhiseid ja tööriistade kasutust, mitte häält ega viivitust. Simulatsioone käivitatakse juhtpaneelist; nende jaoks /v1 otspunkti veel pole.
Tööriistad
Tööriistad lasevad agendil kõne ajal tegutseda. Sama kirjeldus töötab kõigi nelja mootoriga; GPT-Live'is käivitab need taustamudel. Tööriistad lülitatakse sisse iga agendi jaoks eraldi väljal tools.
Sisseehitatud tööriistad
| Nimi | Mida see teeb |
|---|---|
end_call | Agent jätab hüvasti ja lõpetab kõne 0,75 s pärast seda, kui on rääkimise lõpetanud. Kui helistaja vahepeal räägib, kõne lõpetamine tühistatakse. Kõne kirjes on ended_by: "agent". |
take_message | Võtab vastu name, phone, message ja callback_requested ning kirjutab need kõne kirje välja outcomes[]. Kinnitust ei küsi. |
search_knowledge | Lisatakse automaatselt, kui agendil on väljal knowledge dokumendid. Otsib neist ja salvestab allikad kõne kirjesse. |
check_availability | Tüüp read. Tagastab vabad ajad vahemikus date_from kuni date_to agendi tööaja piires. Lisatakse, kui calendar on määratud. |
book_appointment | Tüüp write, läbib kinnitusetapi. Broneerib aja start nimele name ja numbrile phone, soovi korral märkusega note. Broneering lisatakse välja outcomes[]. |
cancel_appointment | Tüüp write, läbib kinnitusetapi. Tühistab broneeringu selle booking_ref järgi. |
Webhook-tööriistad
Webhook-tööriist on HTTPS-otspunkt teie poolel. Määrake see organisatsioonile üks kord juhtpaneeli jaotises Tööriistad või päringuga POST /v1/tools, seejärel lisage selle id agendi välja tools.webhooks (kuni 16 agendi kohta).
curl -X POST "https://hubvocal.com/v1/tools" \
-H "Authorization: Bearer $VT_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "check_order",
"description": "Looks up the shipping status of an order by its number.",
"kind": "read",
"url": "https://crm.example.com/hooks/order",
"parameters": {
"type": "object",
"properties": {
"order_id": {
"type": "string",
"description": "Order number"
}
},
"required": [
"order_id"
]
},
"timeout_s": 8,
"enabled": true,
"secret": "whsec_2b7f…"
}' const res = await fetch("https://hubvocal.com/v1/tools", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.VT_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
"name": "check_order",
"description": "Looks up the shipping status of an order by its number.",
"kind": "read",
"url": "https://crm.example.com/hooks/order",
"parameters": {
"type": "object",
"properties": {
"order_id": {
"type": "string",
"description": "Order number"
}
},
"required": [
"order_id"
]
},
"timeout_s": 8,
"enabled": true,
"secret": "whsec_2b7f…"
}),
});
const data = await res.json();
if (!res.ok) throw new Error(`${res.status}: ${data.detail}`);
console.log(data); import os
import requests
resp = requests.post(
"https://hubvocal.com/v1/tools",
headers={"Authorization": f"Bearer {os.environ['VT_API_KEY']}"},
json={
"name": "check_order",
"description": "Looks up the shipping status of an order by its number.",
"kind": "read",
"url": "https://crm.example.com/hooks/order",
"parameters": {
"type": "object",
"properties": {
"order_id": {
"type": "string",
"description": "Order number",
},
},
"required": [
"order_id",
],
},
"timeout_s": 8,
"enabled": True,
"secret": "whsec_2b7f…",
},
timeout=30,
)
if not resp.ok:
raise RuntimeError(f"{resp.status_code}: {resp.json()['detail']}")
print(resp.json()) name: väiketähed, numbrid ja alakriipsud, 3 kuni 41 märki, algab tähega ja on organisatsioonis unikaalne.end_calljatake_messageon reserveeritud.descriptionütleb mudelile, millal tööriista kasutada. Kirjutage see nagu juhis kolleegile.parameterson JSON Schema objekt kuni 20 väljaga, mille tüüp on string, number, integer või boolean (enum on lubatud).kindonreadvõiwrite;timeout_son 2 kuni 15 sekundit.
Päring, mille saadame
Kui mudel tööriista kutsub, saadab API teie URL-ile POST-päringu. Sisus on tööriista nimi, mudeli valitud argumendid ja veidi kõne konteksti:
POST /hooks/order HTTP/1.1
Host: crm.example.com
Content-Type: application/json
X-VT-Timestamp: 1793832421
X-VT-Signature: sha256=5f0c9a…
{
"tool": "check_order",
"arguments": {
"order_id": "A-10234"
},
"call": {
"room": "tel-6b1f04d2",
"org_id": "6f1c2a40-3b7e-4d0c-9a51-2f8e7c1d9b03",
"agent": "front-desk",
"channel": "phone_in",
"caller": "+905321234567",
"called": "+908501234567",
"lang": "en"
}
} Iga päring allkirjastatakse tööriista saladusega. X-VT-Timestamp on unix-aeg; X-VT-Signature on sha256=, millele järgneb timestamp + "." + body HMAC-SHA256 kuueteistkümnendkujul (hex). Kontrollige allkirja toorese sisu põhjal enne parsimist ja lükake tagasi ajatemplid, mis on vanemad kui paar minutit.
Allkirja kontrollimine
// server.js (Node 18+, Express)
import crypto from "node:crypto";
import express from "express";
const app = express();
const SECRET = process.env.VT_TOOL_SECRET;
// Allkiri katab täpsed baidid: lugege toorest sisu.
app.post("/hooks/order", express.raw({ type: "*/*" }), (req, res) => {
const ts = req.get("X-VT-Timestamp") ?? "";
const sig = req.get("X-VT-Signature") ?? "";
// Lükake vanad päringud tagasi (kaitse korduspäringute eest).
if (!/^\d+$/.test(ts) || Math.abs(Date.now() / 1000 - Number(ts)) > 300) return res.sendStatus(401);
const expected = "sha256=" + crypto.createHmac("sha256", SECRET).update(ts + ".").update(req.body).digest("hex");
const a = Buffer.from(sig);
const b = Buffer.from(expected);
if (a.length !== b.length || !crypto.timingSafeEqual(a, b)) return res.sendStatus(401);
const { tool, arguments: args, call } = JSON.parse(req.body.toString("utf8"));
// Hoidke vastus lühike: mudelini jõuavad ainult esimesed 4 KB.
res.json({ order_id: args.order_id, status: "shipped", eta: "2026-11-07" });
});
app.listen(3000); # app.py (Flask)
import hashlib
import hmac
import json
import os
import time
from flask import Flask, abort, jsonify, request
app = Flask(__name__)
SECRET = os.environ["VT_TOOL_SECRET"].encode()
@app.post("/hooks/order")
def order():
ts = request.headers.get("X-VT-Timestamp", "")
sig = request.headers.get("X-VT-Signature", "")
# Lükake vanad päringud tagasi (kaitse korduspäringute eest).
if not ts.isdigit() or abs(time.time() - int(ts)) > 300:
abort(401)
# Allkiri katab täpsed baidid: lugege toorest sisu.
body = request.get_data()
expected = "sha256=" + hmac.new(SECRET, ts.encode() + b"." + body, hashlib.sha256).hexdigest()
if not hmac.compare_digest(sig, expected):
abort(401)
payload = json.loads(body)
args = payload["arguments"]
# Hoidke vastus lühike: mudelini jõuavad ainult esimesed 4 KB.
return jsonify(order_id=args["order_id"], status="shipped", eta="2026-11-07") Teie vastus
Vastake 2xx olekukoodiga ning JSON-i või lihttekstiga. Mudelini jõuavad ainult esimesed 4 KB, seega tagastage ainult see, mida agent peab ütlema. Muu kui 2xx olek või aegumine annab mudelile teada, et tööriist ebaõnnestus, ja agent lahendab olukorra vestluses.
Lugemis- ja kirjutustööriistad
- read tööriistad käivituvad kohe, näiteks tellimuse oleku või lahtiolekuaegade päringuteks.
- write tööriistad läbivad kinnitusetapi. Esimest kutset ei täideta: agent loeb üksikasjad helistajale ette ja küsib jah- või ei-vastust. Tööriist käivitub ainult siis, kui helistaja järgmises repliigis on kõne keeles selge jah.
- Sama kutse (nimi ja argumendid) käivitub ühe vestluse jooksul kõige rohkem üks kord.
Turvalisus
- URL-id peavad kasutama
https://. Kohalikud ja privaatvõrgu aadressid lükatakse tagasi. - Saladus salvestatakse krüpteeritult ja API ei tagasta seda kunagi (
has_secretnäitab, kas see on määratud). Agent ei näe seda; päringu teeb API. - Argumente ja vastuseid ei salvestata. Kõne kirjes säilib
tools[]nime, tüübi, tulemuse ja kestusega ning ajateljel TOOL-rada.
Päringuga POST /v1/tools/{id}/test saate saata näidisargumentidega päris päringu ning näha olekut, kestust ja vastuse sisu.
curl -X POST "https://hubvocal.com/v1/tools/tl_8f3a2c/test" \
-H "Authorization: Bearer $VT_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"arguments": {
"order_id": "A-10234"
}
}' const res = await fetch("https://hubvocal.com/v1/tools/tl_8f3a2c/test", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.VT_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
"arguments": {
"order_id": "A-10234"
}
}),
});
const data = await res.json();
if (!res.ok) throw new Error(`${res.status}: ${data.detail}`);
console.log(data); import os
import requests
resp = requests.post(
"https://hubvocal.com/v1/tools/tl_8f3a2c/test",
headers={"Authorization": f"Bearer {os.environ['VT_API_KEY']}"},
json={
"arguments": {
"order_id": "A-10234",
},
},
timeout=30,
)
if not resp.ok:
raise RuntimeError(f"{resp.status_code}: {resp.json()['detail']}")
print(resp.json()) Teadmusbaas
Teadmusbaasis hoitakse teie organisatsiooni dokumente. Kui agendile on dokumendid valitud, saab ta tööriista search_knowledge ja vastab leitu põhjal. Agendile on antud juhis mitte välja mõelda seda, mida dokumentides pole.
Dokumendi lisamine
Saatke fail multipart-vormingus (file), lihttekst JSON-ina (title, text) või üks veebileht JSON-ina (url). Töötlemine toimub taustal: dokumendi olek on alguses processing ja muutub seejärel olekuks ready või failed.
curl -X POST "https://hubvocal.com/v1/knowledge" \
-H "Authorization: Bearer $VT_API_KEY" \
-F "file=@price-list-2026.pdf" import fs from "node:fs";
const form = new FormData();
form.append("file", new Blob([await fs.promises.readFile("price-list-2026.pdf")]), "price-list-2026.pdf");
const res = await fetch("https://hubvocal.com/v1/knowledge", {
method: "POST",
headers: { Authorization: `Bearer ${process.env.VT_API_KEY}` },
body: form,
});
console.log(await res.json()); import os
import requests
with open("price-list-2026.pdf", "rb") as f:
resp = requests.post(
"https://hubvocal.com/v1/knowledge",
headers={"Authorization": f"Bearer {os.environ['VT_API_KEY']}"},
files={"file": ("price-list-2026.pdf", f, "application/pdf")},
timeout=60,
)
print(resp.json()) - Failid: pdf, docx, txt, md või html, igaüks kuni 10 MB.
- Organisatsiooni kohta kuni 200 dokumenti ja kokku 200 MB.
- URL-id: üks leht, ainult https; kohalikud ja privaatvõrgu aadressid lükatakse tagasi.
Dokumentide andmine agendile
Loetlege dokumentide id-d agendi väljal knowledge.doc_ids (kuni 50). Enne kasutuselevõttu proovige otsingut päringuga POST /v1/knowledge/search.
curl -X POST "https://hubvocal.com/v1/knowledge/search" \
-H "Authorization: Bearer $VT_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"query": "how much is a scale and polish"
}' const res = await fetch("https://hubvocal.com/v1/knowledge/search", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.VT_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
"query": "how much is a scale and polish"
}),
});
const data = await res.json();
if (!res.ok) throw new Error(`${res.status}: ${data.detail}`);
console.log(data); import os
import requests
resp = requests.post(
"https://hubvocal.com/v1/knowledge/search",
headers={"Authorization": f"Bearer {os.environ['VT_API_KEY']}"},
json={
"query": "how much is a scale and polish",
},
timeout=30,
)
if not resp.ok:
raise RuntimeError(f"{resp.status_code}: {resp.json()['detail']}")
print(resp.json()) Kõne kirjes on iga otsing väljal tools[] nimega search_knowledge koos allikatega sources (dokument, pealkiri ja lõik).
Kalender ja broneeringud
Kui kalender on ühendatud, saab agent kõne ajal vabu aegu kontrollida ning aegu broneerida või tühistada.
Kalendrid ühendatakse juhtpaneeli jaotises Integratsioonid (Google Calendar). Integratsioonide jaoks /v1 otspunkti pole; API-s määrate agendile ainult, millist integratsiooni see kasutab.
Agendi seaded
Määrake agendi objekt calendar: integratsioon ja kalender, broneeringu pikkus (15–240 min), puhver (0–60 min), ajavöönd, tööaeg, minimaalne etteteatamisaeg (0–72 h) ja kui kaugele ette saab broneerida (1–90 päeva).
{
"calendar": {
"integration_id": "int_4a7c10",
"calendar_id": "primary",
"duration_min": 30,
"buffer_min": 10,
"timezone": "Europe/Istanbul",
"working_hours": {
"mon": [
[
"09:00",
"18:00"
]
],
"tue": [
[
"09:00",
"18:00"
]
],
"wed": [
[
"09:00",
"18:00"
]
],
"thu": [
[
"09:00",
"18:00"
]
],
"fri": [
[
"09:00",
"17:00"
]
]
},
"min_notice_h": 2,
"max_days_ahead": 30
}
} Seejärel saab agent kolm sisseehitatud tööriista: check_availability (read), book_appointment ja cancel_appointment (mõlemad write). Kirjutamised läbivad kinnitusetapi: agent loeb kellaaja, nime ja telefoninumbri üle ning broneerib alles pärast selget jah-vastust.
Iga broneering salvestatakse kõne kirjesse väljale outcomes[] kujul {kind: "appointment", start, name, phone, ref}.
MCP
HubVocal toetab protokolli Model Context Protocol kahel viisil: teie agendid saavad kasutada teie enda MCP-serverite tööriistu ja MCP-kliendid saavad platvormi hallata.
MCP-serveri ühendamine agentidega
Lisage server päringuga POST /v1/mcp-servers või juhtpaneelil. Me laadime selle tööriistade loendi (tools/list); uued tööriistad on alguses välja lülitatud. Lülitage vajalikud sisse, märkige igaüks kas read või write ja loetlege need agendi väljal tools.mcp.
curl -X POST "https://hubvocal.com/v1/mcp-servers" \
-H "Authorization: Bearer $VT_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "crm",
"url": "https://mcp.example.com/mcp",
"auth": "bearer",
"secret": "sk_live_…"
}' const res = await fetch("https://hubvocal.com/v1/mcp-servers", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.VT_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
"name": "crm",
"url": "https://mcp.example.com/mcp",
"auth": "bearer",
"secret": "sk_live_…"
}),
});
const data = await res.json();
if (!res.ok) throw new Error(`${res.status}: ${data.detail}`);
console.log(data); import os
import requests
resp = requests.post(
"https://hubvocal.com/v1/mcp-servers",
headers={"Authorization": f"Bearer {os.environ['VT_API_KEY']}"},
json={
"name": "crm",
"url": "https://mcp.example.com/mcp",
"auth": "bearer",
"secret": "sk_live_…",
},
timeout=30,
)
if not resp.ok:
raise RuntimeError(f"{resp.status_code}: {resp.json()['detail']}")
print(resp.json()) - Ühenduse loob API, mitte agent, seega ei näe agent kunagi teie serveri saladust.
- URL-id peavad olema https; kohalikud ja privaatsed aadressid lükatakse tagasi, ka ühendamise hetkel.
writetööriistad läbivad kinnitusetapi: agent loeb üksikasjad üle ja käivitab tööriista alles pärast selget jah-vastust, kõne jooksul kõige rohkem üks kord.- Iga kutse aegub 10 sekundiga; mudelini jõuab tulemusest kuni 4 KB.
- Organisatsiooni kohta kuni 10 serverit ja serveri kohta kuni 50 tööriista. MCP-tööriistad arvestatakse agendi 16 tööriista piirangu sisse.
Vestluses ja kõne kirjes on MCP-tööriista nimi kujul <server>.<tool>, näiteks crm.find_customer.
Platvormi haldamine MCP-kliendist
HubVocal on ka ise MCP-server aadressil https://hubvocal.com/mcp (streamable HTTP). Autentige organisatsiooni API-võtmega, saates selle Bearer-tokenina. Päringupiirang on ühine /v1-ga.
Kliendi ühendamine
Asendage vt_live_… oma võtmega. Andke kliendile võti, millel on ainult need õigused, mida klient vajab.
claude mcp add --transport http hubvocal https://hubvocal.com/mcp \
--header "Authorization: Bearer vt_live_…" {
"mcpServers": {
"hubvocal": {
"command": "npx",
"args": [
"-y",
"mcp-remote",
"https://hubvocal.com/mcp",
"--header",
"Authorization:${VT_AUTH}"
],
"env": {
"VT_AUTH": "Bearer vt_live_…"
}
}
}
} {
"mcpServers": {
"hubvocal": {
"url": "https://hubvocal.com/mcp",
"headers": {
"Authorization": "Bearer vt_live_…"
}
}
}
} from openai import OpenAI
client = OpenAI()
resp = client.responses.create(
model="gpt-5.6-luna",
tools=[{
"type": "mcp",
"server_label": "hubvocal",
"server_url": "https://hubvocal.com/mcp",
"headers": {"Authorization": "Bearer vt_live_…"},
"require_approval": "always",
}],
input="Summarise yesterday's calls.",
)
print(resp.output_text) ChatGPT rakenduses lisatakse kohandatud MCP-konnektorid arendajarežiimis; kas API-võtit saab päises kasutada, sõltub teie paketist ja konnektori seadetest. OpenAI API kaudu saate võtme otse kaasa anda, nagu allpool näidatud.
Tööriistad
| Tööriist | Õigus | Mida teeb |
|---|---|---|
list_agents | read | Loetleb teie agendid. |
get_agent | read | Tagastab ühe agendi. |
list_calls | read | Loetleb kõned, filtriga since, outcome või agent_id järgi (kuni 50). |
get_call | read | Tagastab kõne koos ärakirja ja kokkuvõttega. |
list_numbers | read | Loetleb teie telefoninumbrid. |
list_knowledge | read | Loetleb teadmusbaasi dokumendid. |
search_knowledge | read | Otsib teadmusbaasist. |
get_usage | read | Selle kuu kulu ja minutid. |
create_agent | write | Loob agendi. |
update_agent | write | Muudab agendi mustandit. |
publish_agent | write | Avaldab agendi mustandi. |
add_knowledge_text | write | Lisab teadmusbaasi tekstidokumendi. |
start_outbound_call | calls | Teeb väljuva kõne (agent_id, to). Kehtivad tavalised väljuvate kõnede reeglid ja piirangud. |
Ressursid ja viibad
agent://{id}: agendi seaded.call://{id}: kõne ärakiri tekstina.- Viip
daily_call_report: päeva kõnede kokkuvõte.
Õigused ja auditilogi
Igal API-võtmel on õigused, mille valite võtme loomisel juhtpaneelil:
read: ainult lugemiseks mõeldud tööriistad ja otspunktid.write: lisaks agentide ja dokumentide loomine ja muutmine.calls: lisaks väljuvad kõned.
Võtmetel, mis loodi enne õiguste kasutuselevõttu, on kõik kolm. Iga MCP-tööriista kutse kirjutatakse auditilogisse koos võtme, tööriista, aja ja tulemusega.
Veebividin
Vidin lisab teie veebisaidile kõnenupu. Külastajad räägivad teie agendiga otse brauseris; teie poolel pole serverikoodi vaja.
Looge avalik võti
Avage juhtpaneelis agent ja looge avalik võti (pk_…). Avalik võti kuulub ühele agendile ja selle võib turvaliselt lehele panna, sest see lubab ainult selle agendiga veebikõnesid ja ainult teie lubatud domeenidelt.
- Lubatud domeenid (
allowed_origins): teistelt saitidelt tulevad kõned lükatakse tagasi. - Iga kõne ajapiirang.
- Samalt IP-aadressilt kuni 10 kõnet tunnis.
Lisage skript
Kleepige see enne lõpetavat silti </body>:
<script src="https://hubvocal.com/widget.js" data-agent="pk_…" async></script> Nupu värv, asukoht ja tekst (külastaja keeles) tulevad agendi widget seadetest: color, position, label.
{
"widget": {
"color": "#2563eb",
"position": "bottom-right",
"label": "Talk to us"
}
} Vidin kutsub avaliku võtmega välja POST /api/public/web-calls; teie API-võtit see kunagi ei näe. Avalikke võtmeid hallatakse juhtpaneelis.
Struktureeritud väljad CRM-i
Struktureeritud väljad muudavad vestluse andmeteks, mida teie süsteemid saavad kasutada, näiteks broneeringu kuupäev, toode, mille kohta küsiti, või soov tagasihelistamiseks.
Määrake väljad
Lisage agendi väljale post_call.fields kuni 24 välja. Igal väljal on name (väiketähed, numbrid ja allkriipsud), type (string, number, boolean, enum või date), description, mis ütleb mudelile, mida otsida, ning soovi korral enum väärtused ja required.
{
"post_call": {
"summary": true,
"fields": [
{
"name": "appointment_date",
"type": "date",
"description": "Requested appointment date"
},
{
"name": "service",
"type": "enum",
"enum": [
"checkup",
"cleaning",
"whitening"
],
"description": "Service the caller asked about"
},
{
"name": "callback",
"type": "boolean",
"required": true,
"description": "Does the caller want a callback?"
}
]
}
} Pärast kõnet täidab väljad sama mudel, mis kirjutab kokkuvõtte. Väärtused, mida vestluses ei mainitud, on null. Saate need väljana extracted päringu GET /v1/calls/{room} vastuses ja kõnede loendis ning call.ended webhooki sisus.
{
"extracted": {
"appointment_date": "2026-11-12",
"service": "cleaning",
"callback": true
}
} CSV-ekspordis on iga väli eraldi veerus.
Kõne webhookid
Webhook saadab teie süsteemi sündmuse call.ended, kui kõne on lõppenud ja selle kirje koos kokkuvõttega on valmis. Selle abil saate luua pöördumise, uuendada CRM-i kontakti või saata kliendile järelsõnumi.
Kui kõnekvaliteedi hinded on sisse lülitatud, saate tellida ka sündmuse call.quality_low. See saadetakse iga kõne kohta üks kord, kui hinne langeb alla teie organisatsiooni läve.
Lisage organisatsioonile kuni 5 webhooki juhtpaneelis või päringuga POST /v1/webhooks. Kui te secret väärtust ei saada, luuakse see automaatselt ja tagastatakse ainult selles vastuses. URL peab olema https; kohalikud ja privaatsed aadressid lükatakse tagasi.
curl -X POST "https://hubvocal.com/v1/webhooks" \
-H "Authorization: Bearer $VT_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"url": "https://crm.example.com/hooks/voice",
"events": [
"call.ended"
]
}' const res = await fetch("https://hubvocal.com/v1/webhooks", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.VT_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
"url": "https://crm.example.com/hooks/voice",
"events": [
"call.ended"
]
}),
});
const data = await res.json();
if (!res.ok) throw new Error(`${res.status}: ${data.detail}`);
console.log(data); import os
import requests
resp = requests.post(
"https://hubvocal.com/v1/webhooks",
headers={"Authorization": f"Bearer {os.environ['VT_API_KEY']}"},
json={
"url": "https://crm.example.com/hooks/voice",
"events": [
"call.ended",
],
},
timeout=30,
)
if not resp.ok:
raise RuntimeError(f"{resp.status_code}: {resp.json()['detail']}")
print(resp.json()) Sündmus
data on sama kõneobjekt, mille tagastab GET /v1/calls/{room}, koos ärakirja ja kokkuvõttega:
POST /hooks/voice HTTP/1.1
Host: crm.example.com
Content-Type: application/json
X-VT-Event: call.ended
X-VT-Delivery: dl_51b7a9
X-VT-Timestamp: 1793832440
X-VT-Signature: sha256=9b1e44…
{
"id": "evt_8a41f0c2",
"type": "call.ended",
"created_at": "2026-11-05T09:47:20Z",
"data": {
"room": "demo-8585522d",
"org_id": "6f1c2a40-3b7e-4d0c-9a51-2f8e7c1d9b03",
"org_name": "Example Clinic",
"channel": "web",
"profile": "Front desk",
"engine": "live",
"lang": "en",
"voice": "marin",
"started_at": 1793832409.1,
"ended_at": 1793832434.2,
"duration_s": 25.1,
"total_usd": 0.021215,
"ended_by": "caller",
"outcome": "message_taken",
"summary_text": "The caller asked for an appointment on Thursday afternoon; a message was taken for a callback.",
"extracted": {
"appointment_date": "2026-11-12",
"callback": true
},
"first_audio_s": 2.43,
"turns": 4,
"source_gaps": {
"count": 2,
"total_ms": 230,
"max_ms": 141,
"agent_audio_s": 31.2,
"events": [
[
16.4,
141
],
[
40.1,
89
]
]
},
"quality": {
"verdict": "Clean: no loss, no gaps.",
"protocol": "UDP",
"loss_pct": 0,
"conceal_pct": 0,
"jitter_ms": 4,
"rtt_ms": 38
},
"cost": {
"live": {
"billed_s": 25.1,
"reported": true,
"voice_usd": 0.020917,
"backend": {
"in": 1840,
"cached": 1024,
"out": 96
},
"backend_usd": 0.000298
},
"llm": {
"input_tokens": 1840,
"cached_tokens": 1024,
"output_tokens": 96,
"usd": 0.000298
},
"tts": {
"input_tokens": 0,
"audio_tokens": 0,
"audio_s": 25.1,
"usd": 0.020917
},
"stt": {
"audio_s": 0,
"usd": 0
}
},
"tools": [
{
"t": 14.2,
"name": "check_order",
"kind": "read",
"ok": true,
"ms": 412,
"status": 200
}
],
"outcomes": [],
"summary": {
"text": "The caller asked for an appointment on Thursday afternoon; a message was taken for a callback.",
"language": "en",
"outcome": "message_taken",
"sentiment": "neutral",
"topics": [
"appointment"
],
"action_items": [
"Call the caller back on Thursday morning"
]
},
"recording": {
"available": true,
"duration_s": 25.1,
"size_bytes": 201344
},
"supervisors": [
{
"user": "ayse@example.com",
"joined_at": 1793832420.4,
"left_at": 1793832431,
"modes": [
"listen",
"whisper"
]
}
],
"greeting": {
"connect_s": 0.15,
"session_started_s": 0.05,
"reply_requested_s": 0.05,
"first_audio_s": 2.4,
"reply_done_s": 7.1
},
"transcript": [
{
"role": "assistant",
"text": "Hello, thanks for calling the clinic. How can I help you today?",
"t": 2.4,
"interrupted": false
},
{
"role": "user",
"text": "I would like an appointment on Thursday afternoon.",
"t": 9.8
}
]
}
} Päringud allkirjastatakse täpselt samamoodi nagu tööriistade päringud: X-VT-Timestamp ja X-VT-Signature. Lisaks on kaks päist: X-VT-Event (sündmuse tüüp) ja X-VT-Delivery (selle edastuse unikaalne id).
Korduskatsed
Edastus loetakse õnnestunuks, kui 10 sekundi jooksul tuleb mis tahes 2xx vastus. Muul juhul proovime uuesti:
- 1 minuti pärast
- 5 minuti pärast
- 30 minuti pärast
- 2 tunni pärast
Pärast kokku 5 katset märgitakse edastus olekuga failed. Kõiki katseid näete päringuga GET /v1/webhooks/{id}/deliveries ja ebaõnnestunud edastuse saate uuesti järjekorda panna päringuga POST /v1/webhooks/deliveries/{id}/retry.
Duplikaatide käsitlemine
Korduskatse võib saabuda ka siis, kui teie varasem vastus läks teel kaduma, nii et sama sündmus võib tulla mitu korda. Salvestage X-VT-Delivery id ja jätke juba töödeldud id-d vahele. Vastake kiiresti ja tehke aeganõudev töö taustal.
// Kõigepealt kontrollige allkirja (sama kood mis tööriistade puhul).
app.post("/hooks/voice", express.raw({ type: "*/*" }), async (req, res) => {
if (!verify(req)) return res.sendStatus(401);
// Kas see edastus on juba töödeldud? Kinnitage ja lõpetage.
const delivery = req.get("X-VT-Delivery");
if (await db.deliveries.exists(delivery)) return res.sendStatus(200);
await db.deliveries.insert(delivery);
// Vastake kiiresti; aeganõudev töö tehke taustal.
res.sendStatus(200);
const event = JSON.parse(req.body.toString("utf8"));
queue.add("call-ended", event.data);
}); # Kõigepealt kontrollige allkirja (sama kood mis tööriistade puhul).
@app.post("/hooks/voice")
def voice_hook():
if not verify(request):
abort(401)
# Kas see edastus on juba töödeldud? Kinnitage ja lõpetage.
delivery = request.headers["X-VT-Delivery"]
if db.deliveries.exists(delivery):
return "", 200
db.deliveries.insert(delivery)
# Vastake kiiresti; aeganõudev töö tehke taustal.
event = json.loads(request.get_data())
queue.enqueue("call_ended", event["data"])
return "", 200 POST /v1/webhooks/{id}/test saadab näidissündmuse call.ended ning tagastab oleku, ajakulu ja vastuse sisu.
Toetatud vestluskeeled
Millistes keeltes iga mootor vestlust pidada saab. Agendi keele määrate väljaga lang, kasutades allolevaid koode.
- Toetatud
- Katseline Mootor ei loetle seda keelt ametlikult. See töötab juhiste järgi, kuid kvaliteeti me mõõtnud ei ole.
| Keel | lang | GPT-Live 1 | Gemini Live | OpenAI Realtime | Klassikaline |
|---|---|---|---|---|---|
Türkçetr | tr | Katseline | Toetatud | Katseline | Toetatud |
Englishen | en | Toetatud | Toetatud | Katseline | Toetatud |
Deutschde | de | Toetatud | Toetatud | Katseline | Toetatud |
Françaisfr | fr | Toetatud | Toetatud | Katseline | Toetatud |
Españoles | es | Katseline | Toetatud | Katseline | Toetatud |
Italianoit | it | Katseline | Toetatud | Katseline | Toetatud |
Portuguêspt | pt | Toetatud | Toetatud | Katseline | Toetatud |
Nederlandsnl | nl | Katseline | Toetatud | Katseline | Toetatud |
Русскийru | ru | Katseline | Toetatud | Katseline | Toetatud |
Українськаuk | uk | Katseline | Toetatud | Katseline | Toetatud |
Polskipl | pl | Katseline | Toetatud | Katseline | Toetatud |
Românăro | ro | Katseline | Toetatud | Katseline | Toetatud |
Ελληνικάel | el | Katseline | Toetatud | Katseline | Toetatud |
Българскиbg | bg | Katseline | Toetatud | Katseline | Toetatud |
Češtinacs | cs | Katseline | Toetatud | Katseline | Toetatud |
Slovenčinask | sk | Katseline | Toetatud | Katseline | Toetatud |
Magyarhu | hu | Katseline | Toetatud | Katseline | Toetatud |
Hrvatskihr | hr | Katseline | Toetatud | Katseline | Toetatud |
Српскиsr | sr | Katseline | Toetatud | Katseline | Toetatud |
Bosanskibs | bs | Katseline | Toetatud | Katseline | Toetatud |
Slovenščinasl | sl | Katseline | Toetatud | Katseline | Toetatud |
Македонскиmk | mk | Katseline | Toetatud | Katseline | Toetatud |
Svenskasv | sv | Katseline | Toetatud | Katseline | Toetatud |
Danskda | da | Katseline | Toetatud | Katseline | Toetatud |
Norskno | no | Katseline | Toetatud | Katseline | Toetatud |
Suomifi | fi | Katseline | Toetatud | Katseline | Toetatud |
Eestiet | et | Katseline | Toetatud | Katseline | Toetatud |
Latviešulv | lv | Katseline | Toetatud | Katseline | Toetatud |
Lietuviųlt | lt | Katseline | Toetatud | Katseline | Toetatud |
Catalàca | ca | Katseline | Toetatud | Katseline | Toetatud |
Proovige katselisi keeli enne telefoniliinile panemist brauseris.
Piirangud ja vead
Päringupiirang on 120 päringut minutis võtme kohta. Selle ületamisel saate vastuse 429 koos päisega Retry-After sekundites. Vigadel on HTTP olekukood ja alati sama sisu; detail on inimloetav teade.
{
"detail": "Monthly spending limit reached"
} | Kood | Tähendus | Millal |
|---|---|---|
| 400 | Vigane päring | Päringu sisu ei õnnestunud lugeda, kohustuslik väli puudub või väärtus on vigane (näiteks number pole E.164 vormingus või püütakse kustutada viimast agenti). |
| 401 | Autentimata | Authorization päis puudub, võti ei alga eesliitega vt_live_ või see on tühistatud. |
| 402 | Limiit täis | Organisatsioon on jõudnud kuu kululimiidini; uusi kõnesid ei saa alustada. |
| 403 | Peatatud | Organisatsioon on peatatud; uusi kõnesid ei saa alustada. |
| 404 | Ei leitud | Sellist agenti, kõnet, numbrit või otspunkti pole. |
| 409 | Konflikt | POST /v1/agents saadeti juba olemasoleva id-ga. |
| 429 | Liiga palju päringuid | Üle 120 päringu minutis ühe võtmega. Oodake Retry-After päises toodud arv sekundeid. |
| 502 | Teenusepakkuja viga | Telefoniteenuse pakkuja lükkas väljuva kõne tagasi või ei vastanud. |
| 500 | Serveri viga | Juhtus midagi ootamatut. Proovige uuesti; kui viga püsib, kirjutage meile. |
Korrake ainult vastuseid 429 ja 5xx. 4xx tähendab, et viga on päringus endas; uuesti saatmine tulemust ei muuda.
async function vt(path, init = {}, attempt = 0) {
const res = await fetch(`https://hubvocal.com/v1${path}`, {
...init,
headers: {
Authorization: `Bearer ${process.env.VT_API_KEY}`,
"Content-Type": "application/json",
...init.headers,
},
});
if (res.status === 429 && attempt < 3) {
const wait = Number(res.headers.get("Retry-After") ?? 60);
await new Promise((r) => setTimeout(r, wait * 1000));
return vt(path, init, attempt + 1);
}
const data = await res.json();
if (!res.ok) throw new Error(`${res.status}: ${data.detail}`);
return data;
}