Référence API

Tous les endpoints de l'API v1. Exemples en curl, JavaScript (fetch) et Python (requests) ; le langage choisi est conservé sur toute la page.

URL de basehttps://hubvocal.com/v1
AuthAuthorization: Bearer vt_live_…
Limite de débit120 requêtes/min par clé · 429 + Retry-After
Scopesread · write · calls
Chaque clé dispose de read, write et/ou calls. read couvre les requêtes GET, write les modifications, calls les appels sortants. Une requête hors des scopes de la clé reçoit 403.
Corps d'erreur{"detail": "..."}
OpenAPIGET /v1/openapi.json

Pour l'authentification, l'intégration et les codes d'erreur, voir Développeurs.

Agents

Les conversations se déroulent en mode texte : elles testent les instructions et l'utilisation des outils, pas la voix ni la latence. Les simulations se lancent depuis le tableau de bord ; il n'existe pas encore d'endpoint /v1 pour elles.

Lister les agents

GET /v1/agents

Renvoie tous les agents de votre organisation, dans l'ordre du tableau de bord.

Requête

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

Réponse · 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
  }
]

Créer un agent

POST /v1/agents

Crée un agent. Chaque champ est validé sur le serveur ; les valeurs qui dépassent les limites sont tronquées. Si vous passez un id qui existe déjà, la requête échoue avec 409. Utilisez PUT pour mettre à jour.

NomEmplacementTypeDescription
id body string Facultatif. Lettres minuscules, chiffres et tirets, jusqu'à 48 caractères. Généré à partir du nom s'il est omis.
name
obligatoire
body string Nom affiché, jusqu'à 60 caractères.
lang
obligatoire
body string Code de la langue de conversation, par ex. tr, en, de. La liste complète est dans GET /v1/voices.
engine
obligatoire
body "live" | "gemini" | "realtime" | "classic" live : GPT-Live 1, gemini : Gemini Live, realtime : OpenAI Realtime, classic : STT → LLM → TTS.
instructions body string Instructions système, jusqu'à 8000 caractères.
greeting body string Ce que l'agent dit en premier, jusqu'à 400 caractères.
voice body object voice (un nom issu de /v1/voices), speed (classic et realtime uniquement ; fixé à 1.0 pour live et gemini), tone (style d'élocution en texte libre, jusqu'à 600 caractères).
tools body object builtins (end_call, take_message) et webhooks (id d'outils) ; 16 outils au maximum au total. Vide ou absent : aucun outil. mcp: [{server_id, tools}] ajoute des outils de vos serveurs MCP ; ils comptent dans la même limite.
turn body object Réglages de prise de parole : sensitivity (low, balanced, high ; moteur classic uniquement), first_speaker (agent ou caller), silence_wait_s (1–5), idle_check_s (0 ou 10–120), agent_timeout_s (0 ou 10–60). Les champs vides prennent les valeurs par défaut.
recording body object recording : {enabled (false par défaut), announce (true par défaut), announce_text?}. Lorsqu'il est activé, l'agent annonce l'enregistrement avant le message d'accueil.
post_call body object post_call.summary : rédiger un résumé à la fin de l'appel (true par défaut). post_call.fields : jusqu'à 24 champs à remplir après l'appel ({name, type, description, enum?, required?}).
knowledge body object doc_ids (jusqu'à 50 documents de la base de connaissances) et mode ("tool"). L'agent reçoit alors l'outil search_knowledge.
calendar body object integration_id et calendar_id issus du tableau de bord, duration_min (15–240), buffer_min (0–60), timezone, working_hours, min_notice_h (0–72), max_days_ahead (1–90). Active les outils de rendez-vous.

Requête

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

Réponse · 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
}

Erreurs

  • 409 Un agent avec cet id existe déjà.

Récupérer un agent

GET /v1/agents/{id}

Renvoie un seul agent. published_version est le numéro de la version en production (null s'il n'a jamais été publié) et draft_changed indique si le brouillon en diffère.

NomEmplacementTypeDescription
id
obligatoire
path string Id de l'agent, par ex. front-desk.

Requête

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

Réponse · 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
}

Erreurs

  • 404 Aucun agent avec cet id.

Mettre à jour un agent

PUT /v1/agents/{id}

Remplace l'agent par l'objet envoyé. Envoyez l'objet complet : les champs omis reprennent leur valeur par défaut. L'id du chemin l'emporte sur tout id présent dans le corps.

NomEmplacementTypeDescription
id
obligatoire
path string Id de l'agent, par ex. front-desk.
name
obligatoire
body string Nom affiché, jusqu'à 60 caractères.
lang
obligatoire
body string Code de la langue de conversation, par ex. tr, en, de. La liste complète est dans GET /v1/voices.
engine
obligatoire
body "live" | "gemini" | "realtime" | "classic" live : GPT-Live 1, gemini : Gemini Live, realtime : OpenAI Realtime, classic : STT → LLM → TTS.
instructions body string Instructions système, jusqu'à 8000 caractères.
greeting body string Ce que l'agent dit en premier, jusqu'à 400 caractères.
voice body object voice (un nom issu de /v1/voices), speed (classic et realtime uniquement ; fixé à 1.0 pour live et gemini), tone (style d'élocution en texte libre, jusqu'à 600 caractères).
tools body object builtins (end_call, take_message) et webhooks (id d'outils) ; 16 outils au maximum au total. Vide ou absent : aucun outil. mcp: [{server_id, tools}] ajoute des outils de vos serveurs MCP ; ils comptent dans la même limite.
turn body object Réglages de prise de parole : sensitivity (low, balanced, high ; moteur classic uniquement), first_speaker (agent ou caller), silence_wait_s (1–5), idle_check_s (0 ou 10–120), agent_timeout_s (0 ou 10–60). Les champs vides prennent les valeurs par défaut.
recording body object recording : {enabled (false par défaut), announce (true par défaut), announce_text?}. Lorsqu'il est activé, l'agent annonce l'enregistrement avant le message d'accueil.
post_call body object post_call.summary : rédiger un résumé à la fin de l'appel (true par défaut). post_call.fields : jusqu'à 24 champs à remplir après l'appel ({name, type, description, enum?, required?}).
knowledge body object doc_ids (jusqu'à 50 documents de la base de connaissances) et mode ("tool"). L'agent reçoit alors l'outil search_knowledge.
calendar body object integration_id et calendar_id issus du tableau de bord, duration_min (15–240), buffer_min (0–60), timezone, working_hours, min_notice_h (0–72), max_days_ahead (1–90). Active les outils de rendez-vous.

Requête

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

Réponse · 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
}

Erreurs

  • 404 Aucun agent avec cet id. Créez-le d'abord avec POST.

Supprimer un agent

DELETE /v1/agents/{id}

Supprime l'agent. Une organisation conserve toujours au moins un agent : la suppression du dernier échoue donc.

NomEmplacementTypeDescription
id
obligatoire
path string Id de l'agent, par ex. front-desk.

Requête

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

Réponse · 200

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

Erreurs

  • 400 C'est le dernier agent de l'organisation.
  • 404 Aucun agent avec cet id.

Lister les versions

GET /v1/agents/{id}/versions

Les versions publiées de l'agent, de la plus récente à la plus ancienne. is_live signale celle qu'utilisent actuellement les appels.

NomEmplacementTypeDescription
id
obligatoire
path string Id de l'agent, par ex. front-desk.

Requête

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

Réponse · 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
  }
]

Erreurs

  • 404 Aucun agent avec cet id.

Récupérer une version

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

L'agent complet, tel qu'il était dans cette version.

NomEmplacementTypeDescription
id
obligatoire
path string Id de l'agent, par ex. front-desk.
n
obligatoire
path integer Numéro de version.

Requête

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

Réponse · 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
}

Erreurs

  • 404 Agent ou version introuvable.

Publier le brouillon

POST /v1/agents/{id}/publish

Enregistre le brouillon actuel comme nouvelle version et la met en production. Les appels déjà en cours conservent leur version.

NomEmplacementTypeDescription
id
obligatoire
path string Id de l'agent, par ex. front-desk.
note body string Une courte note sur ce qui a changé.

Requête

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

Réponse · 200

JSON
{
  "version": 4
}

Erreurs

  • 404 Aucun agent avec cet id.

Revenir à une version antérieure

POST /v1/agents/{id}/rollback

Copie une version antérieure dans le brouillon et la publie comme nouvelle version.

NomEmplacementTypeDescription
id
obligatoire
path string Id de l'agent, par ex. front-desk.
version
obligatoire
body integer La version à rétablir.

Requête

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

Réponse · 200

JSON
{
  "version": 5
}

Erreurs

  • 404 Agent ou version introuvable.

Base de connaissances

Lister les documents

GET /v1/knowledge

Les documents de votre organisation, avec leur statut de traitement, leur taille, leur nombre d'extraits et les agents qui les utilisent.

Requête

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

Réponse · 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"
    ]
  }
]

Ajouter un document

POST /v1/knowledge

Importez un fichier en multipart/form-data (champ file), envoyez du texte en JSON {title, text} ou une seule page web en JSON {url}. Renvoie 201 avec le statut processing ; interrogez le document jusqu'à ce qu'il soit ready ou failed.

NomEmplacementTypeDescription
file body file multipart/form-data : pdf, docx, txt, md ou html, 10 Mo maximum.
title body string Titre, avec text.
text body string Contenu en texte brut.
url body string Ou une seule page https à récupérer à la place.

Requête

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

Réponse · 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": []
}

Erreurs

  • 400 Type de fichier non pris en charge, fichier de plus de 10 Mo, URL non https ou pointant vers une adresse privée, ou limite de l'organisation atteinte (200 documents, 200 Mo).

Récupérer un document

GET /v1/knowledge/{id}

Le document, avec un aperçu de ses 2000 premiers caractères.

NomEmplacementTypeDescription
id
obligatoire
path string Id du document.

Requête

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

Réponse · 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…"
}

Erreurs

  • 404 Aucun document avec cet id.

Supprimer un document

DELETE /v1/knowledge/{id}

Supprime le document et le retire de tous les agents qui l'utilisaient.

NomEmplacementTypeDescription
id
obligatoire
path string Id du document.

Requête

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

Réponse · 200

JSON
{
  "deleted": "kb_7d21e4"
}

Erreurs

  • 404 Aucun document avec cet id.

Rechercher

POST /v1/knowledge/search

Exécute la même recherche que l'agent et renvoie les extraits les plus pertinents avec un score. Pratique pour vérifier vos documents avant la mise en production.

NomEmplacementTypeDescription
query
obligatoire
body string Ce que vous recherchez.
doc_ids body string[] Limiter la recherche à ces documents.

Requête

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

Réponse · 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
  }
]

Outils

Outils intégrés

Ces outils ne nécessitent aucune définition. Activez-les dans tools.builtins de l'agent. search_knowledge s'ajoute lorsque knowledge est défini. Les outils de rendez-vous s'ajoutent lorsque calendar est défini.

NomRôle
end_callL'agent dit au revoir et raccroche 0,75 s après avoir fini de parler. Si l'appelant reprend la parole entre-temps, le raccrochage est annulé. La fiche d'appel indique ended_by: "agent".
take_messageRecueille name, phone, message et callback_requested et les enregistre dans outcomes[] de la fiche d'appel. Aucune confirmation n'est demandée.
search_knowledgeAjouté automatiquement lorsque l'agent dispose de documents dans knowledge. Effectue la recherche et enregistre les sources dans la fiche d'appel.
check_availabilityLecture. Renvoie les créneaux libres entre date_from et date_to, dans les horaires de travail de l'agent. Ajouté lorsque calendar est défini.
book_appointmentÉcriture, soumise à l'étape de confirmation. Réserve start pour name et phone, avec une note facultative. La réservation est ajoutée à outcomes[].
cancel_appointmentÉcriture, soumise à l'étape de confirmation. Annule une réservation à partir de sa booking_ref.

Les intégrations d'agenda (Google Calendar) se connectent uniquement dans le tableau de bord ; il n'existe pas d'endpoint /v1 pour elles. Reprenez les id d'intégration et d'agenda affichés dans le tableau de bord dans le champ calendar de l'agent.

Lister les outils

GET /v1/tools

Les outils webhook de votre organisation. Le secret n'est jamais renvoyé ; has_secret indique s'il est défini.

Requête

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

Réponse · 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
  }
]

Récupérer un outil

GET /v1/tools/{id}

Un seul outil webhook. Le secret n'est jamais renvoyé.

NomEmplacementTypeDescription
id
obligatoire
path string Id de l'outil.

Requête

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

Réponse · 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
}

Erreurs

  • 404 Aucun outil avec cet id.

Créer un outil

POST /v1/tools

Définit un outil webhook pour l'organisation. Pour l'utiliser, ajoutez son id à tools.webhooks d'un agent. L'URL doit être en https et ne peut pas pointer vers une adresse locale ou privée.

NomEmplacementTypeDescription
name
obligatoire
body string Lettres minuscules, chiffres et tirets bas, commençant par une lettre (3–41 caractères). Unique dans l'organisation ; end_call et take_message sont réservés.
description
obligatoire
body string Indique au modèle quand et comment utiliser l'outil.
kind
obligatoire
body "read" | "write" read s'exécute immédiatement ; write demande d'abord confirmation à l'appelant.
url
obligatoire
body string Votre endpoint. https uniquement ; les adresses locales et privées sont refusées.
parameters body object Objet JSON Schema : jusqu'à 20 champs de type string, number, integer ou boolean (enum autorisé).
timeout_s body integer De 2 à 15 secondes.
enabled body boolean Les outils désactivés ne sont pas proposés au modèle.
secret body string Sert à signer les requêtes. En écriture seule ; lors d'une mise à jour, une valeur vide conserve le secret actuel et "-" le supprime.

Requête

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

Réponse · 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
}

Erreurs

  • 400 Un champ ne respecte pas les règles : format du nom, URL https, adresse privée, plus de 20 paramètres ou délai hors limites.
  • 409 Un outil portant ce nom existe déjà, ou ce nom est réservé.

Mettre à jour un outil

PUT /v1/tools/{id}

Remplace l'outil par l'objet envoyé. Laissez secret vide ou omettez-le pour conserver le secret actuel ; envoyez "-" pour le supprimer.

NomEmplacementTypeDescription
id
obligatoire
path string Id de l'outil.
name
obligatoire
body string Lettres minuscules, chiffres et tirets bas, commençant par une lettre (3–41 caractères). Unique dans l'organisation ; end_call et take_message sont réservés.
description
obligatoire
body string Indique au modèle quand et comment utiliser l'outil.
kind
obligatoire
body "read" | "write" read s'exécute immédiatement ; write demande d'abord confirmation à l'appelant.
url
obligatoire
body string Votre endpoint. https uniquement ; les adresses locales et privées sont refusées.
parameters body object Objet JSON Schema : jusqu'à 20 champs de type string, number, integer ou boolean (enum autorisé).
timeout_s body integer De 2 à 15 secondes.
enabled body boolean Les outils désactivés ne sont pas proposés au modèle.
secret body string Sert à signer les requêtes. En écriture seule ; lors d'une mise à jour, une valeur vide conserve le secret actuel et "-" le supprime.

Requête

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

Réponse · 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
}

Erreurs

  • 400 Un champ ne respecte pas les règles : format du nom, URL https, adresse privée, plus de 20 paramètres ou délai hors limites.
  • 404 Aucun outil avec cet id.

Supprimer un outil

DELETE /v1/tools/{id}

Supprime l'outil et le retire de tous les agents qui l'utilisaient.

NomEmplacementTypeDescription
id
obligatoire
path string Id de l'outil.

Requête

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

Réponse · 200

JSON
{
  "deleted": "tl_8f3a2c"
}

Erreurs

  • 404 Aucun outil avec cet id.

Tester un outil

POST /v1/tools/{id}/test

Envoie une vraie requête à l'URL de l'outil avec les arguments fournis et renvoie le statut, le temps de réponse et jusqu'à 4 Ko du corps de la réponse.

NomEmplacementTypeDescription
id
obligatoire
path string Id de l'outil.
arguments body object Arguments d'exemple, conformes à parameters.

Requête

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

Réponse · 200

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

Erreurs

  • 404 Aucun outil avec cet id.

Serveurs MCP

Lister les serveurs MCP

GET /v1/mcp-servers

Les serveurs MCP de votre organisation, avec leur état et les outils synchronisés. auth_set indique si un secret est enregistré ; le secret lui-même n'est jamais renvoyé.

Requête

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

Réponse · 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"
      }
    ]
  }
]

Ajouter un serveur MCP

POST /v1/mcp-servers

Enregistre le serveur et récupère sa liste d'outils. Les nouveaux outils sont désactivés. Jusqu'à 10 serveurs par organisation.

NomEmplacementTypeDescription
name
obligatoire
body string Nom court ; sert de préfixe aux noms d'outils (<name>.<tool>).
url
obligatoire
body string L'endpoint MCP du serveur. https uniquement ; les adresses locales et privées sont refusées.
transport body string streamable_http (par défaut) ou sse.
auth body string none, bearer ou header.
secret body string Jeton ou valeur d'en-tête. Stocké chiffré, jamais renvoyé ; "-" le supprime.
header_name body string Nom de l'en-tête quand auth vaut header.

Requête

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

Réponse · 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"
    }
  ]
}

Erreurs

  • 400 L'URL n'est pas en https ou pointe vers une adresse privée, ou la liste d'outils du serveur n'a pas pu être récupérée.
  • 409 L'organisation a déjà 10 serveurs MCP.

Modifier un serveur MCP

PUT /v1/mcp-servers/{id}

Modifie le nom, l'URL, l'authentification ou l'activation du serveur, ainsi que les outils activés et leur accès, read ou write. Envoyez secret: "-" pour supprimer le secret.

NomEmplacementTypeDescription
id
obligatoire
path string Id du serveur MCP.
name body string Nom court ; sert de préfixe aux noms d'outils (<name>.<tool>).
url body string L'endpoint MCP du serveur. https uniquement ; les adresses locales et privées sont refusées.
enabled body boolean Un serveur désactivé n'est pas proposé aux agents.
auth body string none, bearer ou header.
secret body string Jeton ou valeur d'en-tête. Stocké chiffré, jamais renvoyé ; "-" le supprime.
tools body object[] [{name, enabled, access}] pour chaque outil ; access vaut read ou write.

Requête

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

Réponse · 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"
    }
  ]
}

Erreurs

  • 400 L'URL n'est pas en https ou pointe vers une adresse privée, ou la liste d'outils du serveur n'a pas pu être récupérée.
  • 404 Aucun serveur MCP avec cet id.

Supprimer un serveur MCP

DELETE /v1/mcp-servers/{id}

Supprime le serveur et retire ses outils de tous les agents.

NomEmplacementTypeDescription
id
obligatoire
path string Id du serveur MCP.

Requête

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

Réponse · 200

JSON
{
  "deleted": "mcp_2b8e41"
}

Erreurs

  • 404 Aucun serveur MCP avec cet id.

Synchroniser les outils

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

Récupère à nouveau la liste d'outils. Les nouveaux outils arrivent désactivés, avec access à write.

NomEmplacementTypeDescription
id
obligatoire
path string Id du serveur MCP.

Requête

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

Réponse · 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"
    }
  ]
}

Erreurs

  • 400 L'URL n'est pas en https ou pointe vers une adresse privée, ou la liste d'outils du serveur n'a pas pu être récupérée.
  • 404 Aucun serveur MCP avec cet id.

Tester un outil

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

Appelle un outil du serveur avec les arguments fournis et renvoie la durée de l'appel, jusqu'à 4 Ko de contenu et l'indication d'une éventuelle erreur signalée par l'outil.

NomEmplacementTypeDescription
id
obligatoire
path string Id du serveur MCP.
tool
obligatoire
body string Nom de l'outil à appeler.
arguments body object Arguments de l'outil, conformes à son input_schema.

Requête

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

Réponse · 200

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

Erreurs

  • 404 Aucun serveur MCP avec cet id.

Webhooks

Lister les webhooks

GET /v1/webhooks

Les webhooks de votre organisation, avec le résultat de leur dernière livraison. Le secret n'est jamais renvoyé ici ; secret_set indique s'il est défini.

Requête

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

Réponse · 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
    }
  }
]

Créer un webhook

POST /v1/webhooks

Abonne une URL à des événements. Pour l'instant, le seul événement est call.ended. Jusqu'à 5 webhooks par organisation. Si vous omettez secret, il est généré et renvoyé uniquement dans cette réponse.

NomEmplacementTypeDescription
url
obligatoire
body string Votre endpoint. https uniquement ; les adresses locales et privées sont refusées.
events
obligatoire
body string[] Événements à recevoir. Pour l'instant ["call.ended"].
enabled body boolean Un webhook désactivé ne reçoit rien.
secret body string Secret de signature. Généré s'il est omis ; renvoyé une seule fois.

Requête

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

Réponse · 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…"
}

Erreurs

  • 400 L'URL n'est pas en https, pointe vers une adresse privée, ou un événement est inconnu.
  • 409 L'organisation a déjà 5 webhooks.

Mettre à jour un webhook

PUT /v1/webhooks/{id}

Modifie l'URL, les événements ou l'état d'activation. Envoyez secret: "-" pour générer un nouveau secret ; il est renvoyé dans la réponse.

NomEmplacementTypeDescription
id
obligatoire
path string Id du webhook.
url body string Votre endpoint. https uniquement ; les adresses locales et privées sont refusées.
events body string[] Événements à recevoir. Pour l'instant ["call.ended"].
enabled body boolean Un webhook désactivé ne reçoit rien.
secret body string "-" génère un nouveau secret. Omettez-le pour conserver le secret actuel.

Requête

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

Réponse · 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
  }
}

Erreurs

  • 400 L'URL n'est pas en https, pointe vers une adresse privée, ou un événement est inconnu.
  • 404 Aucun webhook avec cet id.

Supprimer un webhook

DELETE /v1/webhooks/{id}

Supprime le webhook. Les livraisons en attente sont abandonnées.

NomEmplacementTypeDescription
id
obligatoire
path string Id du webhook.

Requête

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

Réponse · 200

JSON
{
  "deleted": "wh_3c9d1e"
}

Erreurs

  • 404 Aucun webhook avec cet id.

Tester un webhook

POST /v1/webhooks/{id}/test

Envoie un exemple d'événement call.ended à l'URL et renvoie le statut, le temps de réponse et le corps de la réponse.

NomEmplacementTypeDescription
id
obligatoire
path string Id du webhook.

Requête

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

Réponse · 200

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

Erreurs

  • 404 Aucun webhook avec cet id.

Lister les livraisons

GET /v1/webhooks/{id}/deliveries

Les 50 dernières livraisons d'un webhook, de la plus récente à la plus ancienne, avec le statut (pending, ok, failed), le nombre de tentatives, le statut HTTP, l'erreur et l'heure de la prochaine tentative.

NomEmplacementTypeDescription
id
obligatoire
path string Id du webhook.

Requête

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

Réponse · 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
  }
]

Erreurs

  • 404 Aucun webhook avec cet id.

Relancer une livraison

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

Remet une livraison échouée dans la file d'attente.

NomEmplacementTypeDescription
id
obligatoire
path string Id de la livraison, issu de la liste des livraisons.

Requête

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

Réponse · 200

JSON
{
  "ok": true
}

Erreurs

  • 404 Aucune livraison avec cet id, ou elle n'a pas échoué.

Voix et moteurs

Lister les moteurs, voix et limites

GET /v1/voices

Tout ce qu'il faut pour construire un formulaire d'agent : noms des moteurs, voix valides par moteur, plages de vitesse, langues, préréglages de ton, modèle derrière chaque moteur et longueurs maximales des champs. L'exemple ci-dessous est abrégé.

Requête

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

Réponse · 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
  }
}

Appels

La durée de conservation se définit par organisation dans le tableau de bord : recordings_days (30 par défaut), transcripts_days (365 par défaut) et pii_redaction. Une tâche quotidienne supprime les enregistrements et transcriptions expirés ; la ligne de l'appel et son coût sont conservés.

Widget web : les clés publiques (pk_…) se créent par agent dans le tableau de bord. Le script du widget appelle POST /api/public/web-calls ; voir le guide sur la page Développeurs.

Lancer un appel web

POST /v1/web-calls

Ouvre une salle pour un appel depuis le navigateur et renvoie un jeton d'accès à durée de vie courte. Passez server_url et token à livekit-client dans le navigateur ; l'agent rejoint la salle de lui-même. Appelez cet endpoint depuis votre serveur pour que la clé API n'atteigne jamais le navigateur. À la place d'agent_id, vous pouvez envoyer un objet agent complet pour tester un brouillon sans l'enregistrer.

NomEmplacementTypeDescription
agent_id body string Id d'un agent enregistré. Obligatoire sauf si vous envoyez agent.
agent body object Un objet agent complet (mêmes champs que POST /v1/agents), utilisé pour cet appel uniquement.
version body string | integer Version à utiliser : "live" (par défaut), "draft" ou un numéro de version.

Requête

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

Réponse · 200

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

Erreurs

  • 400 Ni agent_id ni agent n'a été envoyé.
  • 402 L'organisation a atteint son plafond de dépenses mensuel.
  • 403 L'organisation est suspendue.
  • 404 Aucun agent avec cet id.

Passer un appel sortant

POST /v1/calls

Compose un numéro depuis l'un des numéros de votre organisation et connecte l'agent dès que l'on décroche. Le fournisseur (DIDWW, Twilio ou votre propre trunk SIP) est déterminé par le numéro from.

NomEmplacementTypeDescription
from
obligatoire
body string L'un des numéros de votre organisation, au format E.164 (+90…).
to
obligatoire
body string Le numéro à appeler, au format E.164.
agent_id body string Agent à utiliser. S'il est omis, c'est l'agent associé au numéro from qui répond.
version body string | integer Version à utiliser : "live" (par défaut), "draft" ou un numéro de version.

Requête

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

Réponse · 200

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

Erreurs

  • 400 Un numéro n'est pas au format international, ou from ne fait pas partie de vos numéros.
  • 402 L'organisation a atteint son plafond de dépenses mensuel.
  • 502 Le fournisseur de téléphonie a refusé l'appel.

Lister les appels

GET /v1/calls

Les appels du plus récent au plus ancien, web et téléphone. quality est la synthèse des mesures côté navigateur ; il vaut null pour les appels téléphoniques. ended_by vaut caller, agent, max_call_seconds, caller_unresponsive, agent_unresponsive, no_answer ou unknown. channel vaut web, phone_in ou phone_out. Chaque ligne contient aussi outcome et summary_text (les 160 premiers caractères du résumé). ended_by vaut supervisor lorsqu'un superviseur a mis fin à l'appel depuis la console en direct.

NomEmplacementTypeDescription
limit query integer 50 par défaut, 500 au maximum.
agent query string Uniquement les appels de cet agent (nom de l'agent).
outcome query string Uniquement les appels ayant cette issue.

Requête

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

Réponse · 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
    }
  }
]

Récupérer un appel

GET /v1/calls/{room}

La fiche d'appel complète : détail des coûts par fournisseur, transcription, délai du message d'accueil, coupures à la source côté agent et chronologie de qualité du navigateur par fenêtres de 2 secondes. Les champs de coût dépendent du moteur (live, llm, stt, tts, realtime…) ; chacun contient usd. source_gaps.events liste des paires [second, ms]. summary contient text, outcome (resolved, message_taken, transferred, unresolved, no_conversation, spam), sentiment, topics et action_items. supervisors indique qui a rejoint l'appel depuis la console en direct, et dans quels modes. recording contient available, duration_s et size_bytes. extracted contient les valeurs des post_call.fields de l'agent (null si elles n'ont pas été mentionnées).

NomEmplacementTypeDescription
room
obligatoire
path string Nom de la salle, issu de la liste des appels ou de POST /v1/web-calls.

Requête

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

Réponse · 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"
      }
    ]
  }
}

Erreurs

  • 404 Appel introuvable.

Télécharger l'enregistrement

GET /v1/calls/{room}/recording

L'audio de l'appel au format OGG/Opus. Prend en charge les requêtes Range. 404 si l'appel n'a pas été enregistré ou si l'enregistrement a expiré.

NomEmplacementTypeDescription
room
obligatoire
path string Nom de la salle, issu de la liste des appels ou de POST /v1/web-calls.

Requête

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

Réponse · 200

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

<OGG/Opus>

Erreurs

  • 404 L'appel n'a pas été enregistré ou l'enregistrement a expiré.

Supprimer un appel

DELETE /v1/calls/{room}

Supprime immédiatement l'enregistrement, la transcription et le résumé de l'appel, par exemple pour une demande au titre de la KVKK ou du GDPR. La ligne de l'appel et son coût sont conservés.

NomEmplacementTypeDescription
room
obligatoire
path string Nom de la salle, issu de la liste des appels ou de POST /v1/web-calls.

Requête

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

Réponse · 200

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

Erreurs

  • 404 Appel introuvable.

Exporter les appels (CSV)

GET /v1/calls/export

Les appels d'une période au format CSV, une ligne par appel, avec les champs structurés en colonnes supplémentaires.

NomEmplacementTypeDescription
format
obligatoire
query string csv uniquement.
from query date YYYY-MM-DD, inclus.
to query date YYYY-MM-DD, inclus.
agent_id query string Uniquement les appels de cet agent.

Requête

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

Réponse · 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

Numéros de téléphone

Lister les numéros de téléphone

GET /v1/numbers

Les numéros de votre organisation et l'agent qui répond sur chacun (profile_id), ainsi que l'état de préparation de chaque fournisseur de téléphonie. Les numéros sont ajoutés par l'équipe plateforme ; c'est vous qui associez les agents.

Requête

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

Réponse · 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
      }
    }
  }
}

Associer un agent à un numéro

PUT /v1/numbers/{number}

Choisit l'agent qui répond aux appels entrants sur ce numéro. Envoyez agent_id: null pour retirer l'association. Encodez le + du numéro en %2B dans le chemin (le préfixe 00 fonctionne aussi).

NomEmplacementTypeDescription
number
obligatoire
path string Le numéro au format E.164, encodé pour l'URL.
agent_id body string | null Agent qui répond aux appels entrants.
label body string Une note pour votre équipe, jusqu'à 60 caractères.

Requête

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

Réponse · 200

JSON
{
  "ok": true
}

Erreurs

  • 400 L'agent n'existe pas.
  • 404 Le numéro n'appartient pas à votre organisation.

Consommation

Consommation

GET /v1/usage

Appels, minutes et coût fournisseur de votre organisation, par fournisseur et par jour (Europe/Istanbul). Par défaut, le mois en cours. kind vaut llm, tts, stt ou voice (moteurs speech-to-speech).

NomEmplacementTypeDescription
from query date YYYY-MM-DD, inclus.
to query date YYYY-MM-DD, inclus.

Requête

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

Réponse · 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
    }
  ]
}

Spécification

Spécification OpenAPI

GET /v1/openapi.json Aucune clé requise

Le document OpenAPI 3.1 de cette API. Aucune clé requise. Importez-le dans Postman, Insomnia ou un générateur de client.

Requête

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

Réponse · 200

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