Riferimento API

Tutti gli endpoint dell'API v1. Esempi in curl, JavaScript (fetch) e Python (requests); il linguaggio che scegli resta selezionato in tutta la pagina.

URL di basehttps://hubvocal.com/v1
AutenticazioneAuthorization: Bearer vt_live_…
Limite di richieste120 richieste/min per chiave · 429 + Retry-After
Scoperead · write · calls
Ogni chiave ha read, write e/o calls. read copre le richieste GET, write le modifiche, calls le chiamate in uscita. Una richiesta al di fuori degli scope della chiave riceve 403.
Corpo dell'errore{"detail": "..."}
OpenAPIGET /v1/openapi.json

Per autenticazione, integrazione e codici di errore, consulta Sviluppatori.

Agenti

Le conversazioni si svolgono in modalità testo, quindi verificano le istruzioni e l'uso degli strumenti, non la voce né la latenza. Le simulazioni si avviano dalla dashboard; per ora non esiste un endpoint /v1 dedicato.

Elenca gli agenti

GET /v1/agents

Restituisce tutti gli agenti della tua organizzazione, nell'ordine in cui compaiono nella dashboard.

Richiesta

curl
curl "https://hubvocal.com/v1/agents" \
  -H "Authorization: Bearer $VT_API_KEY"

Risposta · 200

JSON
[
  {
    "id": "front-desk",
    "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"
    },
    "published_version": 3,
    "draft_changed": false
  }
]

Crea un agente

POST /v1/agents

Crea un agente. Ogni campo viene validato sul server; i valori oltre i limiti vengono troncati. Se passi un id già esistente, la richiesta fallisce con 409. Per aggiornare usa PUT.

NomeInTipoDescrizione
id body string Facoltativo. Lettere minuscole, cifre e trattini, fino a 48 caratteri. Se omesso, viene generato dal nome.
name
obbligatorio
body string Nome visualizzato, fino a 60 caratteri.
lang
obbligatorio
body string Codice della lingua di conversazione, ad es. tr, en, de. L'elenco completo è in GET /v1/voices.
engine
obbligatorio
body "live" | "gemini" | "realtime" | "classic" live: GPT-Live 1, gemini: Gemini Live, realtime: OpenAI Realtime, classic: STT → LLM → TTS.
instructions body string Istruzioni di sistema, fino a 8000 caratteri.
greeting body string La prima cosa che dice l'agente, fino a 400 caratteri.
voice body object voice (un nome da /v1/voices), speed (solo classic e realtime; fissa a 1.0 per live e gemini), tone (stile di parlato in testo libero, fino a 600 caratteri).
tools body object builtins (end_call, take_message) e webhooks (id degli strumenti); fino a 16 strumenti in totale. Se vuoto o assente, l'agente non ha strumenti. mcp: [{server_id, tools}] aggiunge strumenti dai tuoi server MCP; contano nello stesso limite.
turn body object Impostazioni dei turni di parola: sensitivity (low, balanced, high; solo motore classic), first_speaker (agent o caller), silence_wait_s (1–5), idle_check_s (0 o 10–120), agent_timeout_s (0 o 10–60). I campi vuoti usano i valori predefiniti.
recording body object recording: {enabled (predefinito false), announce (predefinito true), announce_text?}. Se attiva, l'agente annuncia la registrazione prima del saluto.
post_call body object post_call.summary: scrive un riepilogo alla fine della chiamata (predefinito true). post_call.fields: fino a 24 campi da compilare dopo la chiamata ({name, type, description, enum?, required?}).
knowledge body object doc_ids (fino a 50 documenti della knowledge base) e mode ("tool"). L'agente riceve così lo strumento search_knowledge.
calendar body object integration_id e calendar_id dalla dashboard, duration_min (15–240), buffer_min (0–60), timezone, working_hours, min_notice_h (0–72), max_days_ahead (1–90). Attiva gli strumenti per gli appuntamenti.

Richiesta

curl
curl -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"
  }
}'

Risposta · 201

JSON
{
  "id": "front-desk",
  "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"
  },
  "published_version": null,
  "draft_changed": true
}

Errori

  • 409 Esiste già un agente con questo id.

Recupera un agente

GET /v1/agents/{id}

Restituisce un singolo agente. published_version è il numero della versione attiva (null se non è mai stato pubblicato) e draft_changed indica se la bozza è diversa da quella versione.

NomeInTipoDescrizione
id
obbligatorio
path string Id dell'agente, ad es. front-desk.

Richiesta

curl
curl "https://hubvocal.com/v1/agents/front-desk" \
  -H "Authorization: Bearer $VT_API_KEY"

Risposta · 200

JSON
{
  "id": "front-desk",
  "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"
  },
  "published_version": 3,
  "draft_changed": false
}

Errori

  • 404 Nessun agente con questo id.

Aggiorna un agente

PUT /v1/agents/{id}

Sostituisce l'agente con l'oggetto che invii. Invia l'oggetto completo: i campi omessi tornano ai valori predefiniti. L'id nel percorso prevale su qualsiasi id nel corpo.

NomeInTipoDescrizione
id
obbligatorio
path string Id dell'agente, ad es. front-desk.
name
obbligatorio
body string Nome visualizzato, fino a 60 caratteri.
lang
obbligatorio
body string Codice della lingua di conversazione, ad es. tr, en, de. L'elenco completo è in GET /v1/voices.
engine
obbligatorio
body "live" | "gemini" | "realtime" | "classic" live: GPT-Live 1, gemini: Gemini Live, realtime: OpenAI Realtime, classic: STT → LLM → TTS.
instructions body string Istruzioni di sistema, fino a 8000 caratteri.
greeting body string La prima cosa che dice l'agente, fino a 400 caratteri.
voice body object voice (un nome da /v1/voices), speed (solo classic e realtime; fissa a 1.0 per live e gemini), tone (stile di parlato in testo libero, fino a 600 caratteri).
tools body object builtins (end_call, take_message) e webhooks (id degli strumenti); fino a 16 strumenti in totale. Se vuoto o assente, l'agente non ha strumenti. mcp: [{server_id, tools}] aggiunge strumenti dai tuoi server MCP; contano nello stesso limite.
turn body object Impostazioni dei turni di parola: sensitivity (low, balanced, high; solo motore classic), first_speaker (agent o caller), silence_wait_s (1–5), idle_check_s (0 o 10–120), agent_timeout_s (0 o 10–60). I campi vuoti usano i valori predefiniti.
recording body object recording: {enabled (predefinito false), announce (predefinito true), announce_text?}. Se attiva, l'agente annuncia la registrazione prima del saluto.
post_call body object post_call.summary: scrive un riepilogo alla fine della chiamata (predefinito true). post_call.fields: fino a 24 campi da compilare dopo la chiamata ({name, type, description, enum?, required?}).
knowledge body object doc_ids (fino a 50 documenti della knowledge base) e mode ("tool"). L'agente riceve così lo strumento search_knowledge.
calendar body object integration_id e calendar_id dalla dashboard, duration_min (15–240), buffer_min (0–60), timezone, working_hours, min_notice_h (0–72), max_days_ahead (1–90). Attiva gli strumenti per gli appuntamenti.

Richiesta

curl
curl -X PUT "https://hubvocal.com/v1/agents/front-desk" \
  -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": "cedar",
    "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"
  }
}'

Risposta · 200

JSON
{
  "id": "front-desk",
  "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": "cedar",
    "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"
  },
  "published_version": 3,
  "draft_changed": true
}

Errori

  • 404 Nessun agente con questo id. Crealo prima con POST.

Elimina un agente

DELETE /v1/agents/{id}

Elimina l'agente. Un'organizzazione mantiene sempre almeno un agente, quindi non è possibile eliminare l'ultimo.

NomeInTipoDescrizione
id
obbligatorio
path string Id dell'agente, ad es. front-desk.

Richiesta

curl
curl -X DELETE "https://hubvocal.com/v1/agents/front-desk" \
  -H "Authorization: Bearer $VT_API_KEY"

Risposta · 200

JSON
{
  "deleted": "front-desk"
}

Errori

  • 400 È l'ultimo agente dell'organizzazione.
  • 404 Nessun agente con questo id.

Elenca le versioni

GET /v1/agents/{id}/versions

Le versioni pubblicate dell'agente, dalla più recente. is_live indica quella usata ora dalle chiamate.

NomeInTipoDescrizione
id
obbligatorio
path string Id dell'agente, ad es. front-desk.

Richiesta

curl
curl "https://hubvocal.com/v1/agents/front-desk/versions" \
  -H "Authorization: Bearer $VT_API_KEY"

Risposta · 200

JSON
[
  {
    "version": 3,
    "note": "Shorter greeting",
    "published_at": 1793829000,
    "published_by": "ayse@example.com",
    "is_live": true
  },
  {
    "version": 2,
    "note": "Added price list",
    "published_at": 1793740000,
    "published_by": "ayse@example.com",
    "is_live": false
  }
]

Errori

  • 404 Nessun agente con questo id.

Recupera una versione

GET /v1/agents/{id}/versions/{n}

L'agente completo così com'era in quella versione.

NomeInTipoDescrizione
id
obbligatorio
path string Id dell'agente, ad es. front-desk.
n
obbligatorio
path integer Numero di versione.

Richiesta

curl
curl "https://hubvocal.com/v1/agents/front-desk/versions/2" \
  -H "Authorization: Bearer $VT_API_KEY"

Risposta · 200

JSON
{
  "id": "front-desk",
  "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"
  },
  "version": 2
}

Errori

  • 404 L'agente o la versione non esiste.

Pubblica la bozza

POST /v1/agents/{id}/publish

Salva la bozza attuale come nuova versione e la rende attiva. Le chiamate già in corso mantengono la loro versione.

NomeInTipoDescrizione
id
obbligatorio
path string Id dell'agente, ad es. front-desk.
note body string Una breve nota su cosa è cambiato.

Richiesta

curl
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"
}'

Risposta · 200

JSON
{
  "version": 4
}

Errori

  • 404 Nessun agente con questo id.

Ripristina

POST /v1/agents/{id}/rollback

Copia una versione precedente nella bozza e la pubblica come nuova versione.

NomeInTipoDescrizione
id
obbligatorio
path string Id dell'agente, ad es. front-desk.
version
obbligatorio
body integer La versione da ripristinare.

Richiesta

curl
curl -X POST "https://hubvocal.com/v1/agents/front-desk/rollback" \
  -H "Authorization: Bearer $VT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "version": 2
}'

Risposta · 200

JSON
{
  "version": 5
}

Errori

  • 404 L'agente o la versione non esiste.

Knowledge base

Elenca i documenti

GET /v1/knowledge

I documenti della tua organizzazione con stato di elaborazione, dimensione, numero di frammenti e gli agenti che li usano.

Richiesta

curl
curl "https://hubvocal.com/v1/knowledge" \
  -H "Authorization: Bearer $VT_API_KEY"

Risposta · 200

JSON
[
  {
    "id": "kb_7d21e4",
    "title": "Price list 2026",
    "kind": "file",
    "filename": "price-list-2026.pdf",
    "url": null,
    "size_bytes": 248113,
    "chunks": 42,
    "status": "ready",
    "error": null,
    "created_at": 1793740000,
    "used_by": [
      "front-desk"
    ]
  }
]

Aggiungi un documento

POST /v1/knowledge

Carica un file come multipart/form-data (campo file), invia testo come JSON {title, text} o una singola pagina web come JSON {url}. Restituisce 201 con stato processing; interroga il documento finché non diventa ready o failed.

NomeInTipoDescrizione
file body file multipart/form-data: pdf, docx, txt, md o html, fino a 10 MB.
title body string Titolo, da inviare insieme a text.
text body string Contenuto in testo semplice.
url body string In alternativa, una singola pagina https da scaricare.

Richiesta

curl
curl -X POST "https://hubvocal.com/v1/knowledge" \
  -H "Authorization: Bearer $VT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "title": "Opening hours",
  "text": "We are open 09:00–18:00 on weekdays and 10:00–14:00 on Saturdays. Closed on Sundays."
}'

Risposta · 201

JSON
{
  "id": "kb_9f03b1",
  "title": "Opening hours",
  "kind": "text",
  "filename": null,
  "url": null,
  "size_bytes": 96,
  "chunks": 0,
  "status": "processing",
  "error": null,
  "created_at": 1793740000,
  "used_by": []
}

Errori

  • 400 Tipo di file non supportato, file oltre i 10 MB, URL non https o che punta a un indirizzo privato, oppure è stato raggiunto il limite dell'organizzazione (200 documenti, 200 MB).

Recupera un documento

GET /v1/knowledge/{id}

Il documento con un'anteprima dei primi 2000 caratteri.

NomeInTipoDescrizione
id
obbligatorio
path string Id del documento.

Richiesta

curl
curl "https://hubvocal.com/v1/knowledge/kb_7d21e4" \
  -H "Authorization: Bearer $VT_API_KEY"

Risposta · 200

JSON
{
  "id": "kb_7d21e4",
  "title": "Price list 2026",
  "kind": "file",
  "filename": "price-list-2026.pdf",
  "url": null,
  "size_bytes": 248113,
  "chunks": 42,
  "status": "ready",
  "error": null,
  "created_at": 1793740000,
  "used_by": [
    "front-desk"
  ],
  "preview": "Price list 2026. Check-up 1,500 TRY, scale and polish 2,000 TRY…"
}

Errori

  • 404 Nessun documento con questo id.

Elimina un documento

DELETE /v1/knowledge/{id}

Elimina il documento e lo rimuove da tutti gli agenti che lo usavano.

NomeInTipoDescrizione
id
obbligatorio
path string Id del documento.

Richiesta

curl
curl -X DELETE "https://hubvocal.com/v1/knowledge/kb_7d21e4" \
  -H "Authorization: Bearer $VT_API_KEY"

Risposta · 200

JSON
{
  "deleted": "kb_7d21e4"
}

Errori

  • 404 Nessun documento con questo id.

Cerca

POST /v1/knowledge/search

Esegue la stessa ricerca usata dall'agente e restituisce i frammenti più pertinenti con un punteggio. Utile per verificare i documenti prima di andare in produzione.

NomeInTipoDescrizione
query
obbligatorio
body string Cosa cercare.
doc_ids body string[] Limita la ricerca a questi documenti.

Richiesta

curl
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"
}'

Risposta · 200

JSON
[
  {
    "doc_id": "kb_7d21e4",
    "title": "Price list 2026",
    "chunk_index": 3,
    "text": "Scale and polish: 2,000 TRY, about 30 minutes.",
    "score": 0.82
  }
]

Strumenti

Strumenti integrati

Questi strumenti non richiedono una definizione. Attivali in tools.builtins dell'agente. search_knowledge viene aggiunto quando knowledge è impostato. Gli strumenti per gli appuntamenti vengono aggiunti quando calendar è impostato.

NomeCosa fa
end_callL'agente saluta e riaggancia 0,75 s dopo aver finito di parlare. Se nel frattempo il chiamante parla, non riaggancia. Il registro della chiamata riporta ended_by: "agent".
take_messageRaccoglie name, phone, message e callback_requested e li scrive in outcomes[] nel registro della chiamata. Non chiede conferma.
search_knowledgeAggiunto automaticamente quando l'agente ha documenti in knowledge. Cerca al loro interno e salva le fonti nel registro della chiamata.
check_availabilityLettura. Restituisce gli slot liberi tra date_from e date_to, nell'orario di lavoro dell'agente. Aggiunto quando calendar è impostato.
book_appointmentScrittura, con passaggio di conferma. Prenota start a nome di name con phone, più una note facoltativa. La prenotazione finisce in outcomes[].
cancel_appointmentScrittura, con passaggio di conferma. Annulla una prenotazione tramite il suo booking_ref.

Le integrazioni di calendario (Google Calendar) si collegano solo dalla dashboard; non esiste un endpoint /v1 per gestirle. Nel campo calendar dell'agente usa gli id di integrazione e calendario che trovi nella dashboard.

Elenca gli strumenti

GET /v1/tools

Gli strumenti webhook della tua organizzazione. Il segreto non viene mai restituito; has_secret indica se è impostato.

Richiesta

curl
curl "https://hubvocal.com/v1/tools" \
  -H "Authorization: Bearer $VT_API_KEY"

Risposta · 200

JSON
[
  {
    "id": "tl_8f3a2c",
    "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,
    "has_secret": true,
    "created_at": 1793830000,
    "updated_at": 1793830000
  }
]

Recupera uno strumento

GET /v1/tools/{id}

Un singolo strumento webhook. Il segreto non viene mai restituito.

NomeInTipoDescrizione
id
obbligatorio
path string Id dello strumento.

Richiesta

curl
curl "https://hubvocal.com/v1/tools/tl_8f3a2c" \
  -H "Authorization: Bearer $VT_API_KEY"

Risposta · 200

JSON
{
  "id": "tl_8f3a2c",
  "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,
  "has_secret": true,
  "created_at": 1793830000,
  "updated_at": 1793830000
}

Errori

  • 404 Nessuno strumento con questo id.

Crea uno strumento

POST /v1/tools

Definisce uno strumento webhook per l'organizzazione. Per usarlo, aggiungi il suo id a tools.webhooks di un agente. L'URL deve essere https e non può puntare a un indirizzo locale o privato.

NomeInTipoDescrizione
name
obbligatorio
body string Lettere minuscole, cifre e trattini bassi, a partire da una lettera (3–41 caratteri). Unico nell'organizzazione; end_call e take_message sono riservati.
description
obbligatorio
body string Dice al modello quando e come usare lo strumento.
kind
obbligatorio
body "read" | "write" read viene eseguito subito; write chiede prima conferma al chiamante.
url
obbligatorio
body string Il tuo endpoint. Solo https; gli indirizzi locali e privati vengono rifiutati.
parameters body object Oggetto JSON Schema: fino a 20 campi di tipo string, number, integer o boolean (enum consentito).
timeout_s body integer Da 2 a 15 secondi.
enabled body boolean Gli strumenti disattivati non vengono proposti al modello.
secret body string Serve a firmare le richieste. Solo scrittura; in aggiornamento, un valore vuoto mantiene il segreto attuale e "-" lo rimuove.

Richiesta

curl
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…"
}'

Risposta · 201

JSON
{
  "id": "tl_8f3a2c",
  "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,
  "has_secret": true,
  "created_at": 1793830000,
  "updated_at": 1793830000
}

Errori

  • 400 Un campo non rispetta le regole: formato del nome, URL https, indirizzo privato, più di 20 parametri o timeout fuori intervallo.
  • 409 Esiste già uno strumento con questo nome, oppure il nome è riservato.

Aggiorna uno strumento

PUT /v1/tools/{id}

Sostituisce lo strumento con l'oggetto che invii. Lascia secret vuoto o omettilo per mantenere quello attuale; invia "-" per rimuoverlo.

NomeInTipoDescrizione
id
obbligatorio
path string Id dello strumento.
name
obbligatorio
body string Lettere minuscole, cifre e trattini bassi, a partire da una lettera (3–41 caratteri). Unico nell'organizzazione; end_call e take_message sono riservati.
description
obbligatorio
body string Dice al modello quando e come usare lo strumento.
kind
obbligatorio
body "read" | "write" read viene eseguito subito; write chiede prima conferma al chiamante.
url
obbligatorio
body string Il tuo endpoint. Solo https; gli indirizzi locali e privati vengono rifiutati.
parameters body object Oggetto JSON Schema: fino a 20 campi di tipo string, number, integer o boolean (enum consentito).
timeout_s body integer Da 2 a 15 secondi.
enabled body boolean Gli strumenti disattivati non vengono proposti al modello.
secret body string Serve a firmare le richieste. Solo scrittura; in aggiornamento, un valore vuoto mantiene il segreto attuale e "-" lo rimuove.

Richiesta

curl
curl -X PUT "https://hubvocal.com/v1/tools/tl_8f3a2c" \
  -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": 10,
  "enabled": true,
  "secret": ""
}'

Risposta · 200

JSON
{
  "id": "tl_8f3a2c",
  "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": 10,
  "enabled": true,
  "has_secret": true,
  "created_at": 1793830000,
  "updated_at": 1793833600
}

Errori

  • 400 Un campo non rispetta le regole: formato del nome, URL https, indirizzo privato, più di 20 parametri o timeout fuori intervallo.
  • 404 Nessuno strumento con questo id.

Elimina uno strumento

DELETE /v1/tools/{id}

Elimina lo strumento e lo rimuove da tutti gli agenti che lo usavano.

NomeInTipoDescrizione
id
obbligatorio
path string Id dello strumento.

Richiesta

curl
curl -X DELETE "https://hubvocal.com/v1/tools/tl_8f3a2c" \
  -H "Authorization: Bearer $VT_API_KEY"

Risposta · 200

JSON
{
  "deleted": "tl_8f3a2c"
}

Errori

  • 404 Nessuno strumento con questo id.

Prova uno strumento

POST /v1/tools/{id}/test

Invia una richiesta reale all'URL dello strumento con gli argomenti che indichi e restituisce lo stato, il tempo impiegato e fino a 4 KB del corpo della risposta.

NomeInTipoDescrizione
id
obbligatorio
path string Id dello strumento.
arguments body object Argomenti di esempio, conformi a parameters.

Richiesta

curl
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"
  }
}'

Risposta · 200

JSON
{
  "ok": true,
  "status": 200,
  "ms": 412,
  "body": "{\"order_id\":\"A-10234\",\"status\":\"shipped\",\"eta\":\"2026-11-07\"}"
}

Errori

  • 404 Nessuno strumento con questo id.

Server MCP

Elenca i server MCP

GET /v1/mcp-servers

I server MCP della tua organizzazione con il loro stato e gli strumenti sincronizzati. auth_set indica se è salvato un segreto, che non viene mai restituito.

Richiesta

curl
curl "https://hubvocal.com/v1/mcp-servers" \
  -H "Authorization: Bearer $VT_API_KEY"

Risposta · 200

JSON
[
  {
    "id": "mcp_2b8e41",
    "name": "crm",
    "url": "https://mcp.example.com/mcp",
    "transport": "streamable_http",
    "auth": "bearer",
    "auth_set": true,
    "enabled": true,
    "status": "ok",
    "error": null,
    "tools_synced_at": 1793831000,
    "tools": [
      {
        "name": "find_customer",
        "description": "Find a customer by phone number.",
        "input_schema": {
          "type": "object",
          "properties": {
            "phone": {
              "type": "string"
            }
          },
          "required": [
            "phone"
          ]
        },
        "enabled": true,
        "access": "read"
      },
      {
        "name": "create_ticket",
        "description": "Open a support ticket.",
        "input_schema": {
          "type": "object",
          "properties": {
            "subject": {
              "type": "string"
            },
            "body": {
              "type": "string"
            }
          },
          "required": [
            "subject"
          ]
        },
        "enabled": false,
        "access": "write"
      }
    ]
  }
]

Aggiungi un server MCP

POST /v1/mcp-servers

Salva il server e ne recupera l'elenco degli strumenti. I nuovi strumenti sono disattivati. Fino a 10 server per organizzazione.

NomeInTipoDescrizione
name
obbligatorio
body string Nome breve; usato come prefisso nei nomi degli strumenti (<name>.<tool>).
url
obbligatorio
body string L'endpoint MCP del server. Solo https; gli indirizzi locali e privati vengono rifiutati.
transport body string streamable_http (predefinito) o sse.
auth body string none, bearer o header.
secret body string Token o valore dell'header. Salvato cifrato, mai restituito; "-" lo rimuove.
header_name body string Nome dell'header quando auth è header.

Richiesta

curl
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_…"
}'

Risposta · 201

JSON
{
  "id": "mcp_2b8e41",
  "name": "crm",
  "url": "https://mcp.example.com/mcp",
  "transport": "streamable_http",
  "auth": "bearer",
  "auth_set": true,
  "enabled": true,
  "status": "ok",
  "error": null,
  "tools_synced_at": 1793831000,
  "tools": [
    {
      "name": "find_customer",
      "description": "Find a customer by phone number.",
      "input_schema": {
        "type": "object",
        "properties": {
          "phone": {
            "type": "string"
          }
        },
        "required": [
          "phone"
        ]
      },
      "enabled": false,
      "access": "write"
    },
    {
      "name": "create_ticket",
      "description": "Open a support ticket.",
      "input_schema": {
        "type": "object",
        "properties": {
          "subject": {
            "type": "string"
          },
          "body": {
            "type": "string"
          }
        },
        "required": [
          "subject"
        ]
      },
      "enabled": false,
      "access": "write"
    }
  ]
}

Errori

  • 400 L'URL non è https o punta a un indirizzo privato, oppure non è stato possibile recuperare l'elenco degli strumenti del server.
  • 409 L'organizzazione ha già 10 server MCP.

Aggiorna un server MCP

PUT /v1/mcp-servers/{id}

Modifica nome, URL, autenticazione o stato di attivazione, oltre a quali strumenti sono attivi e se sono di lettura o di scrittura. Invia secret: "-" per rimuovere il segreto.

NomeInTipoDescrizione
id
obbligatorio
path string Id del server MCP.
name body string Nome breve; usato come prefisso nei nomi degli strumenti (<name>.<tool>).
url body string L'endpoint MCP del server. Solo https; gli indirizzi locali e privati vengono rifiutati.
enabled body boolean Un server disattivato non viene offerto agli agenti.
auth body string none, bearer o header.
secret body string Token o valore dell'header. Salvato cifrato, mai restituito; "-" lo rimuove.
tools body object[] [{name, enabled, access}] per strumento; access è read o write.

Richiesta

curl
curl -X PUT "https://hubvocal.com/v1/mcp-servers/mcp_2b8e41" \
  -H "Authorization: Bearer $VT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "tools": [
    {
      "name": "find_customer",
      "enabled": true,
      "access": "read"
    },
    {
      "name": "create_ticket",
      "enabled": true,
      "access": "write"
    }
  ]
}'

Risposta · 200

JSON
{
  "id": "mcp_2b8e41",
  "name": "crm",
  "url": "https://mcp.example.com/mcp",
  "transport": "streamable_http",
  "auth": "bearer",
  "auth_set": true,
  "enabled": true,
  "status": "ok",
  "error": null,
  "tools_synced_at": 1793831000,
  "tools": [
    {
      "name": "find_customer",
      "description": "Find a customer by phone number.",
      "input_schema": {
        "type": "object",
        "properties": {
          "phone": {
            "type": "string"
          }
        },
        "required": [
          "phone"
        ]
      },
      "enabled": true,
      "access": "read"
    },
    {
      "name": "create_ticket",
      "description": "Open a support ticket.",
      "input_schema": {
        "type": "object",
        "properties": {
          "subject": {
            "type": "string"
          },
          "body": {
            "type": "string"
          }
        },
        "required": [
          "subject"
        ]
      },
      "enabled": true,
      "access": "write"
    }
  ]
}

Errori

  • 400 L'URL non è https o punta a un indirizzo privato, oppure non è stato possibile recuperare l'elenco degli strumenti del server.
  • 404 Nessun server MCP con questo id.

Elimina un server MCP

DELETE /v1/mcp-servers/{id}

Elimina il server e rimuove i suoi strumenti da tutti gli agenti.

NomeInTipoDescrizione
id
obbligatorio
path string Id del server MCP.

Richiesta

curl
curl -X DELETE "https://hubvocal.com/v1/mcp-servers/mcp_2b8e41" \
  -H "Authorization: Bearer $VT_API_KEY"

Risposta · 200

JSON
{
  "deleted": "mcp_2b8e41"
}

Errori

  • 404 Nessun server MCP con questo id.

Sincronizza gli strumenti

POST /v1/mcp-servers/{id}/sync

Recupera di nuovo l'elenco degli strumenti. Quelli nuovi arrivano disattivati, con accesso impostato su write.

NomeInTipoDescrizione
id
obbligatorio
path string Id del server MCP.

Richiesta

curl
curl -X POST "https://hubvocal.com/v1/mcp-servers/mcp_2b8e41/sync" \
  -H "Authorization: Bearer $VT_API_KEY"

Risposta · 200

JSON
{
  "id": "mcp_2b8e41",
  "name": "crm",
  "url": "https://mcp.example.com/mcp",
  "transport": "streamable_http",
  "auth": "bearer",
  "auth_set": true,
  "enabled": true,
  "status": "ok",
  "error": null,
  "tools_synced_at": 1793831000,
  "tools": [
    {
      "name": "find_customer",
      "description": "Find a customer by phone number.",
      "input_schema": {
        "type": "object",
        "properties": {
          "phone": {
            "type": "string"
          }
        },
        "required": [
          "phone"
        ]
      },
      "enabled": true,
      "access": "read"
    },
    {
      "name": "create_ticket",
      "description": "Open a support ticket.",
      "input_schema": {
        "type": "object",
        "properties": {
          "subject": {
            "type": "string"
          },
          "body": {
            "type": "string"
          }
        },
        "required": [
          "subject"
        ]
      },
      "enabled": false,
      "access": "write"
    }
  ]
}

Errori

  • 400 L'URL non è https o punta a un indirizzo privato, oppure non è stato possibile recuperare l'elenco degli strumenti del server.
  • 404 Nessun server MCP con questo id.

Testa uno strumento

POST /v1/mcp-servers/{id}/test

Chiama uno strumento del server con gli argomenti indicati e restituisce il tempo impiegato, fino a 4 KB di contenuto e se lo strumento ha segnalato un errore.

NomeInTipoDescrizione
id
obbligatorio
path string Id del server MCP.
tool
obbligatorio
body string Nome dello strumento da chiamare.
arguments body object Argomenti per lo strumento, conformi al suo input_schema.

Richiesta

curl
curl -X POST "https://hubvocal.com/v1/mcp-servers/mcp_2b8e41/test" \
  -H "Authorization: Bearer $VT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "tool": "find_customer",
  "arguments": {
    "phone": "+905321234567"
  }
}'

Risposta · 200

JSON
{
  "ok": true,
  "ms": 236,
  "content": "{\"customer_id\":\"C-1042\",\"name\":\"Ayşe Yılmaz\",\"open_tickets\":0}",
  "is_error": false
}

Errori

  • 404 Nessun server MCP con questo id.

Webhook

Elenca i webhook

GET /v1/webhooks

I webhook della tua organizzazione con l'esito della loro ultima consegna. Il segreto non viene mai restituito qui; secret_set indica se è impostato.

Richiesta

curl
curl "https://hubvocal.com/v1/webhooks" \
  -H "Authorization: Bearer $VT_API_KEY"

Risposta · 200

JSON
[
  {
    "id": "wh_3c9d1e",
    "url": "https://crm.example.com/hooks/voice",
    "events": [
      "call.ended"
    ],
    "enabled": true,
    "secret_set": true,
    "created_at": 1793830000,
    "last_delivery": {
      "status": "ok",
      "at": 1793832440.2,
      "http_status": 200
    }
  }
]

Crea un webhook

POST /v1/webhooks

Iscrive un URL agli eventi. Al momento l'unico evento è call.ended. Fino a 5 webhook per organizzazione. Se ometti secret, ne viene generato uno, restituito solo in questa risposta.

NomeInTipoDescrizione
url
obbligatorio
body string Il tuo endpoint. Solo https; gli indirizzi locali e privati vengono rifiutati.
events
obbligatorio
body string[] Eventi da ricevere. Al momento ["call.ended"].
enabled body boolean I webhook disattivati non ricevono nulla.
secret body string Segreto di firma. Generato se omesso; restituito una sola volta.

Richiesta

curl
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"
  ]
}'

Risposta · 201

JSON
{
  "id": "wh_3c9d1e",
  "url": "https://crm.example.com/hooks/voice",
  "events": [
    "call.ended"
  ],
  "enabled": true,
  "secret_set": true,
  "created_at": 1793830000,
  "last_delivery": null,
  "secret": "whsec_9QmZ…"
}

Errori

  • 400 L'URL non è https, punta a un indirizzo privato oppure un evento è sconosciuto.
  • 409 L'organizzazione ha già 5 webhook.

Aggiorna un webhook

PUT /v1/webhooks/{id}

Modifica l'URL, gli eventi o lo stato di attivazione. Invia secret: "-" per generare un nuovo segreto, che viene restituito nella risposta.

NomeInTipoDescrizione
id
obbligatorio
path string Id del webhook.
url body string Il tuo endpoint. Solo https; gli indirizzi locali e privati vengono rifiutati.
events body string[] Eventi da ricevere. Al momento ["call.ended"].
enabled body boolean I webhook disattivati non ricevono nulla.
secret body string "-" genera un nuovo segreto. Omettilo per mantenere quello attuale.

Richiesta

curl
curl -X PUT "https://hubvocal.com/v1/webhooks/wh_3c9d1e" \
  -H "Authorization: Bearer $VT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "enabled": false
}'

Risposta · 200

JSON
{
  "id": "wh_3c9d1e",
  "url": "https://crm.example.com/hooks/voice",
  "events": [
    "call.ended"
  ],
  "enabled": false,
  "secret_set": true,
  "created_at": 1793830000,
  "last_delivery": {
    "status": "ok",
    "at": 1793832440.2,
    "http_status": 200
  }
}

Errori

  • 400 L'URL non è https, punta a un indirizzo privato oppure un evento è sconosciuto.
  • 404 Nessun webhook con questo id.

Elimina un webhook

DELETE /v1/webhooks/{id}

Elimina il webhook. Le consegne in attesa vengono scartate.

NomeInTipoDescrizione
id
obbligatorio
path string Id del webhook.

Richiesta

curl
curl -X DELETE "https://hubvocal.com/v1/webhooks/wh_3c9d1e" \
  -H "Authorization: Bearer $VT_API_KEY"

Risposta · 200

JSON
{
  "deleted": "wh_3c9d1e"
}

Errori

  • 404 Nessun webhook con questo id.

Prova un webhook

POST /v1/webhooks/{id}/test

Invia all'URL un evento call.ended di esempio e restituisce lo stato, il tempo impiegato e il corpo della risposta.

NomeInTipoDescrizione
id
obbligatorio
path string Id del webhook.

Richiesta

curl
curl -X POST "https://hubvocal.com/v1/webhooks/wh_3c9d1e/test" \
  -H "Authorization: Bearer $VT_API_KEY"

Risposta · 200

JSON
{
  "ok": true,
  "http_status": 200,
  "ms": 184,
  "body": "{\"received\":true}"
}

Errori

  • 404 Nessun webhook con questo id.

Elenca le consegne

GET /v1/webhooks/{id}/deliveries

Le ultime 50 consegne di un webhook, dalla più recente, con stato (pending, ok, failed), numero di tentativi, stato HTTP, errore e orario del prossimo tentativo.

NomeInTipoDescrizione
id
obbligatorio
path string Id del webhook.

Richiesta

curl
curl "https://hubvocal.com/v1/webhooks/wh_3c9d1e/deliveries" \
  -H "Authorization: Bearer $VT_API_KEY"

Risposta · 200

JSON
[
  {
    "id": "dl_51b7a9",
    "event": "call.ended",
    "call_id": "demo-8585522d",
    "status": "ok",
    "attempts": 1,
    "http_status": 200,
    "error": null,
    "created_at": 1793832440.2,
    "next_attempt_at": null
  },
  {
    "id": "dl_51a3c4",
    "event": "call.ended",
    "call_id": "tel-6b1f04d2",
    "status": "pending",
    "attempts": 2,
    "http_status": 503,
    "error": "HTTP 503",
    "created_at": 1793832101.7,
    "next_attempt_at": 1793833901.7
  }
]

Errori

  • 404 Nessun webhook con questo id.

Ritenta una consegna

POST /v1/webhooks/deliveries/{id}/retry

Rimette in coda una consegna non riuscita.

NomeInTipoDescrizione
id
obbligatorio
path string Id della consegna, dall'elenco delle consegne.

Richiesta

curl
curl -X POST "https://hubvocal.com/v1/webhooks/deliveries/dl_51a3c4/retry" \
  -H "Authorization: Bearer $VT_API_KEY"

Risposta · 200

JSON
{
  "ok": true
}

Errori

  • 404 Nessuna consegna con questo id, oppure non è fallita.

Voci e motori

Elenca motori, voci e limiti

GET /v1/voices

Tutto ciò che serve per costruire un modulo per gli agenti: nomi dei motori, voci valide per ogni motore, intervalli di velocità, lingue, toni predefiniti, il modello dietro ogni motore e i limiti di lunghezza dei campi. L'esempio qui sotto è abbreviato.

Richiesta

curl
curl "https://hubvocal.com/v1/voices" \
  -H "Authorization: Bearer $VT_API_KEY"

Risposta · 200

JSON
{
  "engines": {
    "live": "GPT-Live 1 (OpenAI full-duplex ses modeli)",
    "gemini": "Gemini Live (Google ses-sese model)",
    "realtime": "Realtime (OpenAI ses-sese model)",
    "classic": "Klasik (Deepgram + OpenAI LLM + OpenAI TTS)"
  },
  "voices": {
    "live": [
      "marin",
      "cedar",
      "gleam",
      "meridian"
    ],
    "gemini": [
      "Kore",
      "Aoede",
      "Charon",
      "Puck"
    ],
    "realtime": [
      "marin",
      "cedar",
      "alloy"
    ],
    "classic": [
      "alloy",
      "coral",
      "sage"
    ]
  },
  "speed": {
    "live": {
      "min": 1,
      "max": 1
    },
    "gemini": {
      "min": 1,
      "max": 1
    },
    "realtime": {
      "min": 0.25,
      "max": 1.5
    },
    "classic": {
      "min": 0.25,
      "max": 4
    }
  },
  "langs": {
    "tr": "Türkçe",
    "en": "English"
  },
  "presets": [
    {
      "id": "calm",
      "label": "Sakin ve güven veren",
      "text": "Sakin, yumuşak ve güven veren bir tonla konuş."
    }
  ],
  "models": {
    "live": {
      "model": "gpt-live-1",
      "backend": "gpt-5.6-luna"
    },
    "gemini": {
      "model": "gemini-3.8-live",
      "ready": true
    },
    "realtime": {
      "model": "gpt-realtime-2.1-mini"
    },
    "classic": {
      "stt": "nova-3",
      "llm": "gpt-4.1-mini",
      "tts": "gpt-4o-mini-tts"
    }
  },
  "limits": {
    "tone": 600,
    "instructions": 8000,
    "greeting": 400
  }
}

Chiamate

La conservazione si imposta per organizzazione nella dashboard: recordings_days (predefinito 30), transcripts_days (predefinito 365) e pii_redaction. Un processo giornaliero elimina registrazioni e trascrizioni scadute; la riga della chiamata e il suo costo restano.

Widget web: le chiavi pubbliche (pk_…) si creano per agente nella dashboard. Lo script del widget chiama POST /api/public/web-calls; consulta la guida nella pagina Sviluppatori.

Avvia una chiamata web

POST /v1/web-calls

Apre una stanza per una chiamata dal browser e restituisce un token di accesso a breve durata. Passa server_url e token a livekit-client nel browser; l'agente entra nella stanza da solo. Chiama questo endpoint dal tuo server, così la chiave API non arriva mai al browser. Al posto di agent_id puoi inviare un oggetto agente completo per provare una bozza senza salvarla.

NomeInTipoDescrizione
agent_id body string Id di un agente salvato. Obbligatorio se non invii agent.
agent body object Un oggetto agente completo (stessi campi di POST /v1/agents) usato solo per questa chiamata.
version body string | integer Quale versione usare: "live" (predefinito), "draft" o un numero di versione.

Richiesta

curl
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"
}'

Risposta · 200

JSON
{
  "server_url": "wss://hubvocal.com",
  "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9…",
  "room": "demo-3f9a1c2e",
  "max_seconds": 300
}

Errori

  • 400 Non è stato inviato né agent_id né agent.
  • 402 L'organizzazione ha raggiunto il limite di spesa mensile.
  • 403 L'organizzazione è sospesa.
  • 404 Nessun agente con questo id.

Effettua una chiamata in uscita

POST /v1/calls

Chiama un numero di telefono da uno dei numeri della tua organizzazione e collega l'agente quando la chiamata riceve risposta. Il fornitore (DIDWW, Twilio o il tuo SIP trunk) viene scelto in base al numero from.

NomeInTipoDescrizione
from
obbligatorio
body string Uno dei numeri della tua organizzazione, in formato E.164 (+90…).
to
obbligatorio
body string Il numero da chiamare, in formato E.164.
agent_id body string Agente da usare. Se omesso, risponde l'agente assegnato al numero from.
version body string | integer Quale versione usare: "live" (predefinito), "draft" o un numero di versione.

Richiesta

curl
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"
}'

Risposta · 200

JSON
{
  "room": "tel-out-9c41e0b7",
  "provider": "didww",
  "sip_call_id": "SCL_7mVt2kQb9xRa"
}

Errori

  • 400 Un numero non è in formato internazionale, oppure from non è uno dei tuoi numeri.
  • 402 L'organizzazione ha raggiunto il limite di spesa mensile.
  • 502 Il fornitore di telefonia ha rifiutato la chiamata.

Elenca le chiamate

GET /v1/calls

Chiamate dalla più recente alla meno recente, web e telefoniche. quality è il riepilogo delle misurazioni lato browser ed è null per le chiamate telefoniche. ended_by è caller, agent, max_call_seconds, caller_unresponsive, agent_unresponsive, no_answer o unknown. channel è web, phone_in o phone_out. Ogni riga contiene anche outcome e summary_text (i primi 160 caratteri del riepilogo). ended_by è supervisor quando un supervisore ha chiuso la chiamata dalla console live.

NomeInTipoDescrizione
limit query integer Predefinito 50, massimo 500.
agent query string Solo le chiamate di questo agente (nome dell'agente).
outcome query string Solo le chiamate con questo esito.

Richiesta

curl
curl "https://hubvocal.com/v1/calls?limit=20" \
  -H "Authorization: Bearer $VT_API_KEY"

Risposta · 200

JSON
[
  {
    "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": 0,
      "total_ms": 0,
      "max_ms": 0
    },
    "quality": {
      "verdict": "Clean: no loss, no gaps.",
      "protocol": "UDP",
      "loss_pct": 0,
      "conceal_pct": 0,
      "jitter_ms": 4,
      "rtt_ms": 38
    }
  }
]

Recupera una chiamata

GET /v1/calls/{room}

Il registro completo della chiamata: dettaglio dei costi per fornitore, trascrizione, tempi del saluto, interruzioni alla sorgente lato agente e la timeline di qualità del browser in finestre di 2 secondi. I campi di costo dipendono dal motore (live, llm, stt, tts, realtime…); ognuno contiene usd. source_gaps.events elenca coppie [secondo, ms]. summary contiene text, outcome (resolved, message_taken, transferred, unresolved, no_conversation, spam), sentiment, topics e action_items. supervisors indica chi si è unito alla chiamata dalla console live e in quali modalità. recording contiene available, duration_s e size_bytes. extracted contiene i valori dei post_call.fields dell'agente (null se non menzionati).

NomeInTipoDescrizione
room
obbligatorio
path string Nome della stanza, dall'elenco delle chiamate o da POST /v1/web-calls.

Richiesta

curl
curl "https://hubvocal.com/v1/calls/demo-8585522d" \
  -H "Authorization: Bearer $VT_API_KEY"

Risposta · 200

JSON
{
  "call": {
    "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
      }
    ]
  },
  "quality": {
    "summary": {
      "verdict": "Clean: no loss, no gaps.",
      "protocol": "UDP",
      "rtt_ms": 38,
      "protocols_seen": [
        "UDP"
      ],
      "loss_pct": 0,
      "conceal_pct": 0,
      "jitter_ms": 4,
      "buffer_ms": 62
    },
    "timeline": [
      {
        "t": 2,
        "loss": 0,
        "conceal": 0,
        "jitter": 3,
        "buffer": 60,
        "proto": "UDP"
      },
      {
        "t": 4,
        "loss": 0,
        "conceal": 0,
        "jitter": 4,
        "buffer": 62,
        "proto": "UDP"
      }
    ]
  }
}

Errori

  • 404 Chiamata non trovata.

Scarica la registrazione

GET /v1/calls/{room}/recording

L'audio della chiamata in OGG/Opus. Supporta le richieste Range. 404 se la chiamata non è stata registrata o la registrazione è scaduta.

NomeInTipoDescrizione
room
obbligatorio
path string Nome della stanza, dall'elenco delle chiamate o da POST /v1/web-calls.

Richiesta

curl
curl "https://hubvocal.com/v1/calls/demo-8585522d/recording" \
  -H "Authorization: Bearer $VT_API_KEY" \
  -o call.ogg

Risposta · 200

audio/ogg
HTTP/1.1 200 OK
Content-Type: audio/ogg
Accept-Ranges: bytes
Content-Length: 201344

<OGG/Opus>

Errori

  • 404 La chiamata non è stata registrata o la registrazione è scaduta.

Elimina una chiamata

DELETE /v1/calls/{room}

Elimina subito la registrazione, la trascrizione e il riepilogo della chiamata, ad esempio per una richiesta ai sensi della KVKK o del GDPR. La riga della chiamata e il suo costo restano.

NomeInTipoDescrizione
room
obbligatorio
path string Nome della stanza, dall'elenco delle chiamate o da POST /v1/web-calls.

Richiesta

curl
curl -X DELETE "https://hubvocal.com/v1/calls/demo-8585522d" \
  -H "Authorization: Bearer $VT_API_KEY"

Risposta · 200

JSON
{
  "deleted": "demo-8585522d"
}

Errori

  • 404 Chiamata non trovata.

Esporta le chiamate (CSV)

GET /v1/calls/export

Le chiamate di un intervallo di date in CSV, una riga per chiamata, con i campi strutturati come colonne aggiuntive.

NomeInTipoDescrizione
format
obbligatorio
query string Solo csv.
from query date YYYY-MM-DD, incluso.
to query date YYYY-MM-DD, incluso.
agent_id query string Solo le chiamate di questo agente.

Richiesta

curl
curl "https://hubvocal.com/v1/calls/export?format=csv&from=2026-11-01&to=2026-11-05" \
  -H "Authorization: Bearer $VT_API_KEY" \
  -o calls.csv

Risposta · 200

text/csv
room,started_at,agent,channel,duration_s,total_usd,outcome,appointment_date,callback
demo-8585522d,2026-11-05T09:46:49Z,front-desk,web,25.1,0.021215,message_taken,2026-11-12,true

Numeri di telefono

Elenca i numeri di telefono

GET /v1/numbers

I numeri di telefono della tua organizzazione e l'agente che risponde su ciascuno (profile_id), oltre allo stato di ogni fornitore di telefonia. I numeri vengono aggiunti dal team della piattaforma; tu assegni gli agenti.

Richiesta

curl
curl "https://hubvocal.com/v1/numbers" \
  -H "Authorization: Bearer $VT_API_KEY"

Risposta · 200

JSON
{
  "numbers": [
    {
      "number": "+908501234567",
      "provider": "didww",
      "org_id": "6f1c2a40-3b7e-4d0c-9a51-2f8e7c1d9b03",
      "org_name": "Example Clinic",
      "profile_id": "front-desk",
      "label": "Main line"
    }
  ],
  "sip": {
    "enabled": true,
    "room_prefix": "tel-",
    "providers": {
      "didww": {
        "inbound_ips": "46.19.209.14,46.19.210.14",
        "inbound_auth": false,
        "outbound_host": "trunk.example.com",
        "outbound_auth": true,
        "outbound_ready": true,
        "inbound_ready": true
      }
    }
  }
}

Assegna un agente a un numero

PUT /v1/numbers/{number}

Sceglie l'agente che risponde alle chiamate in entrata su questo numero. Invia agent_id: null per rimuovere l'assegnazione. Codifica il + del numero come %2B nel percorso (funziona anche il prefisso 00).

NomeInTipoDescrizione
number
obbligatorio
path string Il numero in E.164, codificato per URL.
agent_id body string | null Agente che risponde alle chiamate in entrata.
label body string Una nota per il tuo team, fino a 60 caratteri.

Richiesta

curl
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"
}'

Risposta · 200

JSON
{
  "ok": true
}

Errori

  • 400 L'agente non esiste.
  • 404 Il numero non appartiene alla tua organizzazione.

Utilizzo

Utilizzo

GET /v1/usage

Chiamate, minuti e costi dei fornitori della tua organizzazione, per fornitore e per giorno (Europe/Istanbul). Per impostazione predefinita, il mese corrente. kind è llm, tts, stt o voice (motori speech-to-speech).

NomeInTipoDescrizione
from query date YYYY-MM-DD, incluso.
to query date YYYY-MM-DD, incluso.

Richiesta

curl
curl "https://hubvocal.com/v1/usage?from=2026-11-01&to=2026-11-05" \
  -H "Authorization: Bearer $VT_API_KEY"

Risposta · 200

JSON
{
  "from": "2026-11-01",
  "to": "2026-11-05",
  "totals": {
    "calls": 42,
    "minutes": 81.2,
    "usd": 3.94
  },
  "by_provider": [
    {
      "provider": "openai",
      "model": "gpt-live-1",
      "kind": "voice",
      "calls": 30,
      "input_tokens": 0,
      "cached_tokens": 0,
      "output_tokens": 0,
      "audio_s": 2900.1,
      "usd": 2.41
    }
  ],
  "by_day": [
    {
      "date": "2026-11-05",
      "usd": 1.2,
      "minutes": 20.5,
      "calls": 9
    }
  ],
  "by_org": [
    {
      "org_id": "6f1c2a40-3b7e-4d0c-9a51-2f8e7c1d9b03",
      "org_name": "Example Clinic",
      "usd": 3.94,
      "minutes": 81.2,
      "calls": 42
    }
  ]
}

Specifica

Specifica OpenAPI

GET /v1/openapi.json Nessuna chiave richiesta

Il documento OpenAPI 3.1 di questa API. Nessuna chiave richiesta. Importalo in Postman, Insomnia o in un generatore di client.

Richiesta

curl
curl "https://hubvocal.com/v1/openapi.json"

Risposta · 200

JSON
{
  "openapi": "3.1.0",
  "info": {
    "title": "HubVocal API",
    "version": "1.0.0"
  },
  "servers": [
    {
      "url": "https://hubvocal.com/v1"
    }
  ],
  "paths": {}
}