API Appels
Déclenchez des appels sortants, récupérez des enregistrements d'appels, et pollez les statuts d'appels, tout par programme.
Déclencher un appel sortant
Le déclenchement d'appels sortants n'est pas encore disponible de manière générale. L'endpoint ci-dessous décrit la requête et la réponse prévues ; il peut évoluer avant le lancement. La lecture des enregistrements et du statut des appels (plus bas) est disponible dès maintenant.
Crée un appel sortant et le met immédiatement en file pour composition. L'agent spécifié doit disposer d'une version en ligne pour traiter l'appel. Le caller ID (from_number) est optionnel, si omis, le numéro par défaut du trunk est utilisé. Utilisez un numéro appartenant à votre organisation comme caller ID.
POST /calls
Auth : session du dashboard
Cet endpoint utilise l'authentification de session (cookies + token CSRF du dashboard), et non les clés API la_. Les clés API ne fonctionnent que sur les endpoints en lecture seule /v1.
Corps de requête
{
"agent_id": "agt_01hx3k9z...",
"to_number": "+33612345678",
"from_number": "+33988292988",
"sip_headers": {
"X-Campaign-Id": "camp_01hx..."
}
}
| Champ | Requis | Type | Description |
|---|---|---|---|
agent_id | Oui | string | ID de l'agent à utiliser, il doit disposer d'une version en ligne pour traiter l'appel |
to_number | Oui | string | Numéro de destination au format E.164 (ex : +33612345678) |
from_number | Non | string | null | Caller ID affiché au destinataire, utilisez un numéro de votre organisation. Omettre pour utiliser le numéro par défaut du trunk. |
sip_headers | Non | object | null | En-têtes SIP personnalisés transmis au porteur. Les clés sont les noms d'en-têtes, les valeurs des strings. |
Réponse, 201 Created
{
"id": "cal_01hx9mzp...",
"agent_id": "agt_01hx3k9z...",
"call_sid": "pending-01hx9n...",
"direction": "OUTBOUND",
"status": "QUEUED",
"from_number": "+33988292988",
"to_number": "+33612345678",
"queued_at": "2026-05-26T14:30:00.000000Z",
"organization_id": "org_01hx..."
}
Après création, l'appel passe à RINGING en quelques centaines de millisecondes pendant l'établissement de la branche SIP. Pollez GET /calls/{id}/status pour suivre la progression.
Erreur, 429 Limite concurrente atteinte
{
"error": "Concurrent call limit reached",
"active_calls": 10,
"max_concurrent_calls": 10
}
Poller le statut d'un appel
Endpoint léger pour le polling. Retourne uniquement status et duration, utilisez-le dans une boucle de polling jusqu'à ce que l'appel atteigne un état terminal.
GET /calls/{call_id}/status
Auth : session du dashboard
Les endpoints à authentification de session de cette section vivent sous /api/... (authentification par cookie), et non sous /api/v1/... (qui est l'API à token Bearer la_). Par exemple, l'URL complète est https://www.manivox.ai/api/calls/{id}/status.
{
"status": "IN_PROGRESS",
"duration": null
}
// Une fois terminé :
{
"status": "COMPLETED",
"duration": 142
}
États terminaux, arrêtez le polling quand vous atteignez l'un d'eux :
| Statut | Signification |
|---|---|
COMPLETED | L'appel s'est terminé normalement |
FAILED | Erreur SIP ou crash d'agent |
NO_ANSWER | L'appel sortant n'a pas été décroché |
BUSY | Ligne de destination occupée |
CANCELED | Appel annulé avant la prise |
GET /calls/{id}/status utilise l'authentification de session (même que le dashboard). Pour une notification serveur-à-serveur en fin d'appel, configurez une Action de fin d'appel sur l'agent, la plateforme émet une requête HTTP vers votre endpoint après chaque appel terminé. Voir Actions de fin d'appel.
Exemple de polling (Python, contexte session navigateur)
import time, requests
BASE = "https://www.manivox.ai"
# Utilisez les cookies de session obtenus depuis le dashboard
COOKIES = {"laravel_session": "YOUR_SESSION_COOKIE"}
HEADERS = {"X-XSRF-TOKEN": "YOUR_XSRF_TOKEN"}
call_id = "cal_01hx9mzp..."
TERMINAL = {"COMPLETED", "FAILED", "NO_ANSWER", "BUSY", "CANCELED"}
while True:
r = requests.get(f"{BASE}/api/calls/{call_id}/status", cookies=COOKIES, headers=HEADERS)
data = r.json()
print(f"Status: {data['status']}")
if data["status"] in TERMINAL:
break
time.sleep(2)
print(f"Appel terminé : {data['status']} ({data['duration']}s)")
Récupérer les détails d'un appel
Retourne l'enregistrement de l'appel, incluant les variables collectées et l'historique des appels d'outils. La transcription tour par tour est disponible dans la vue détaillée de l'appel dans le dashboard.
GET /calls/{call_id}
Auth : session du dashboard
{
"id": "cal_01hx9mzp...",
"call_sid": "lk-room-01hx...",
"agent_id": "agt_01hx3k9z...",
"direction": "OUTBOUND",
"status": "COMPLETED",
"from_number": "+33988292988",
"to_number": "+33612345678",
"duration": 142,
"queued_at": "2026-05-26T14:30:00.000000Z",
"ringing_at": "2026-05-26T14:30:00.350000Z",
"answered_at": "2026-05-26T14:30:05.120000Z",
"ended_at": "2026-05-26T14:32:27.890000Z",
"recording_url": "/storage/recordings/cal_01hx9mzp.wav",
"call_variables": {
"caller_name": "Marie Dupont",
"account_number": "ACC-1234",
"intent": "balance_inquiry"
},
"tool_calls": [
{
"action": "get_balance",
"web_service": "CRM API",
"params": { "account_id": "ACC-1234" },
"response": { "balance": 1250.50, "currency": "EUR" },
"duration_ms": 312,
"ts": 18.4
}
],
"agent": {
"id": "agt_01hx3k9z...",
"name": "Customer Support FR"
}
}
Lister les appels
Retourne les appels paginés pour un compte donné, du plus récent au plus ancien. Plage de dates maximale : 30 jours.
GET /v1/accounts/{account_id}/calls
Auth : clé API (Bearer la_…)
| Paramètre | Type | Défaut | Description |
|---|---|---|---|
limit | integer | 100 | Nombre max d'enregistrements (max 100) |
offset | integer | 0 | Enregistrements à sauter |
agent_id | string | - | Filtrer par un agent spécifique |
from | ISO 8601 | - | Début de la plage de dates (ex : 2026-05-01T00:00:00) |
to | ISO 8601 | - | Fin de la plage de dates (max 30 jours après from) |
# Appels d'un agent spécifique en mai 2026
curl "https://www.manivox.ai/api/v1/accounts/acc_01hx.../calls?agent_id=agt_01hx...&from=2026-05-01T00:00:00&to=2026-05-31T23:59:59" \
-H "Authorization: Bearer la_YOUR_API_KEY"
Réponse, 200 OK
{
"data": [
{
"call_id": "cal_01hx9mzp...",
"agent_id": "agt_01hx3k9z...",
"direction": "OUTBOUND",
"status": "COMPLETED",
"from_number": "+33988292988",
"to_number": "+33612345678",
"duration": 142,
"recording_available": true,
"answered_at": "2026-05-26T14:30:05+00:00",
"ended_at": "2026-05-26T14:32:27+00:00",
"created_at": "2026-05-26T14:30:00+00:00"
}
],
"total": 247
}
| Champ | Type | Description |
|---|---|---|
call_id | string | Identifiant unique de l'appel (CUID2) |
agent_id | string | ID de l'agent ayant traité l'appel |
direction | enum | INBOUND ou OUTBOUND |
status | enum | Statut de l'appel (voir le tableau de statuts ci-dessus) |
from_number | string | null | Numéro de l'appelant (E.164) |
to_number | string | Numéro appelé (E.164) |
duration | integer | null | Durée en secondes (null jusqu'à la fin de l'appel) |
recording_available | boolean | Indique si un enregistrement a été effectué pour l'appel. Récupérez-le via l'endpoint d'enregistrement, qui renvoie 404 si l'audio a depuis été supprimé par la politique de rétention |
answered_at | ISO 8601 | null | Quand l'appel a été décroché |
ended_at | ISO 8601 | null | Quand l'appel s'est terminé |
created_at | ISO 8601 | Quand l'enregistrement d'appel a été créé |
Récupérer le résumé & les variables (handoff)
Récupère le résumé généré d'un appel et les variables collectées pendant l'appel, identifié par son call id. Son cas d'usage principal est le screen-pop CRM lors d'un transfert vers un humain : quand un agent IA transfère un appel à un humain et que le CRM destinataire a besoin de la conversation jusqu'ici. Mais il fonctionne pour n'importe quel appel de votre organisation, y compris les appels passés déjà terminés.
GET /v1/calls/{call_id}/handoff
Auth : clé API (Bearer la_…)
Lors d'un transfert, Manivox place un en-tête SIP X-Call-Id portant le call id sur l'INVITE sortant. Lisez-le depuis l'appel entrant dans votre CRM pour savoir quel call id récupérer.
Le résumé est généré de manière asynchrone. S'il n'est pas prêt au moment de l'appel, la requête bloque jusqu'à ~5 secondes (polling toutes les ~300 ms) en l'attendant, puis retourne status: "pending". Les appels terminés et passés retournent status: "ready" immédiatement. Lors d'un transfert, le téléphone de l'humain sonne généralement plus longtemps que la génération ne prend, donc le résumé est presque toujours ready au moment où vous le demandez ; si vous obtenez tout de même pending, réessayez après ~1 seconde (les variables sont déjà présentes).
Réponse, 200 OK
{
"call_id": "cal_01hx9mzp...",
"status": "ready",
"summary": {
"summary": "The caller wants to book a table for 4 on Friday at 8pm.",
"key_topics": ["reservation", "friday dinner"],
"action_items": ["Confirm availability for Friday 8pm"],
"sentiment": "positive"
},
"variables": {
"party_size": "4",
"customer_name": "Dupont",
"preferred_time": "20:00"
}
}
| Champ | Type | Description |
|---|---|---|
call_id | string | Répète le call id demandé |
status | enum | ready quand le résumé est disponible, pending s'il n'était pas prêt dans la fenêtre d'attente |
summary | object | null | Objet de résumé structuré (pas une simple chaîne). null tant que status vaut pending. Champs : summary (texte), key_topics (string[]), action_items (string[]), sentiment (positive / neutral / negative) |
variables | object | Dictionnaire clé/valeur des variables collectées pendant l'appel (définies par workflow). Toujours un objet, {} si aucune |
Erreur, 404 Not Found, l'appel n'existe pas pour l'organisation de cette clé API :
{ "error": "Call not found" }
Un appel peut être transféré plusieurs fois (par exemple, un premier transfert échoue et l'agent continue de parler). Chaque transfert réutilise le même call_id (le même enregistrement d'appel) et écrase l'instantané avec les variables les plus récentes et un résumé fraîchement régénéré : cet endpoint retourne donc toujours l'état le plus récent.
La charge utile est volontairement limitée au résumé et aux variables. Elle n'inclut ni la transcription complète ni l'enregistrement — récupérez-les séparément via Récupérer la transcription et Télécharger un enregistrement.
Outre le 404 ci-dessus, cet endpoint retourne les erreurs d'authentification et de limite de débit communes à toute l'API : 401 / 403 pour une clé absente, mal formée, invalide, inactive, expirée ou désactivée pour l'organisation, et 429 au-delà de la limite de 120 requêtes/minute par organisation. Voir Référence API → Codes de statut HTTP.
Récupérer la transcription
Retourne les tours utilisateur/assistant ordonnés d'un appel, identifié par son call id. Fonctionne en cours d'appel : la transcription reflète tout ce qui a été dit jusqu'ici et status indique que l'appel est toujours en cours, ainsi qu'après la fin de l'appel pour l'enregistrement final. Un cas d'usage courant est un système receveur qui récupère la conversation jusqu'ici juste après un transfert vers un humain, mais cela fonctionne pour n'importe quel appel de votre organisation.
GET /v1/calls/{call_id}/transcript
Auth : clé API (Bearer la_…)
| Paramètre | Type | Défaut | Description |
|---|---|---|---|
with_tools | boolean | false | Quand true, chaque tour assistant en ayant déclenché un porte aussi ses appels d'outils/API (tool_calls) et toute demande d'outil supprimée (suppressed_tools), le même niveau de détail que la vue de détail d'appel du dashboard, avec la même rédaction côté serveur, jamais plus que ce que l'UI révèle. |
curl "https://www.manivox.ai/api/v1/calls/cal_01hx9mzp.../transcript?with_tools=true" \
-H "Authorization: Bearer la_YOUR_API_KEY"
Réponse, 200 OK
{
"call_id": "cal_01hx9mzp...",
"status": "IN_PROGRESS",
"turn_count": 2,
"with_tools": true,
"transcript": [
{
"role": "assistant",
"content": "Un instant, je vérifie.",
"timestamp": "2026-07-05T09:00:00Z",
"tool_calls": [
{
"name": "create_case",
"method": "POST",
"url": "https://crm.example.com/cases",
"status": 200,
"request": { "phone": "+33612345678" },
"response": { "id": 42 },
"duration_ms": 142,
"error": null
}
]
},
{ "role": "user", "content": "Merci.", "timestamp": "2026-07-05T09:00:10Z" }
]
}
| Champ | Type | Description |
|---|---|---|
call_id | string | Répète le call id demandé |
status | enum | Le statut actuel de l'appel (voir le tableau du cycle de vie dans Vue d'ensemble des appels), indique si la transcription ci-dessous est partielle (appel encore en cours) ou définitive |
turn_count | integer | Nombre d'entrées dans transcript |
with_tools | boolean | Répète si ?with_tools=true a été demandé |
transcript | array | Tours ordonnés. Seuls les rôles user et assistant sont inclus, les lignes internes/système sont filtrées. Chaque entrée a role, content, timestamp et, uniquement avec with_tools=true, tool_calls / suppressed_tools en option |
Champs d'une entrée tool_calls (présents uniquement avec ?with_tools=true, et uniquement sur les tours assistant en ayant déclenché un) :
| Champ | Type | Description |
|---|---|---|
name | string | Nom de l'action ou de l'outil |
method | string | null | Méthode HTTP, pour les appels Web Service / Composio |
url | string | null | URL de la requête, le cas échéant |
status | integer | null | Code de statut HTTP retourné |
request | object | null | Corps/paramètres de la requête (rédigé côté serveur, comme dans le dashboard) |
response | object | null | Corps de la réponse (rédigé côté serveur, comme dans le dashboard) |
duration_ms | integer | null | Durée de l'appel en millisecondes |
error | string | null | Message d'erreur si l'appel a échoué |
Un appel d'outil qui ne se termine qu'après le début du tour utilisateur suivant reste rattaché au tour assistant qui l'a déclenché (le tour assistant précédent le plus proche), comme le fait le dashboard. Les entrées suppressed_tools (name, reason) listent les appels d'outils que le modèle a demandés mais qui n'ont volontairement jamais été exécutés car la conversation était déjà passée au nœud de flux suivant.
Erreur, 404 Not Found, l'appel n'existe pas pour l'organisation de cette clé API :
{ "error": "Call not found" }
Outre le 404 ci-dessus, cet endpoint retourne les erreurs d'authentification et de limite de débit communes à toute l'API : 401 / 403 pour une clé absente, mal formée, invalide, inactive, expirée ou désactivée pour l'organisation, et 429 au-delà de la limite de 120 requêtes/minute par organisation. Voir Référence API → Codes de statut HTTP.
Télécharger un enregistrement
Télécharge l'enregistrement audio d'un appel sous forme de fichier WAV.
GET /v1/calls/{call_id}/recording
Auth : clé API (Bearer la_…)
Retourne l'audio brut avec ces en-têtes de réponse :
| En-tête | Valeur |
|---|---|
Content-Type | audio/wav |
Content-Disposition | attachment; filename="recording-{call_id}.wav" (téléchargement de fichier). Avec ?stream, c'est inline à la place, pour une lecture dans le navigateur. |
Accept-Ranges | bytes, les requêtes HTTP Range sont supportées (seek / téléchargement partiel). |
L'endpoint d'enregistrement à authentification de session GET /api/calls/{id}/recording suit la convention inverse : il sert l'audio en inline par défaut et requiert ?download pour forcer le téléchargement en pièce jointe, alors que cet endpoint V1 sert attachment par défaut et utilise ?stream pour la lecture en ligne.
# Télécharger le WAV
curl "https://www.manivox.ai/api/v1/calls/cal_01hx.../recording" \
-H "Authorization: Bearer la_YOUR_API_KEY" \
-o recording.wav
Erreurs, 404 Not Found
// L'appel n'existe pas pour l'organisation de cette clé API
{ "error": "Call not found" }
// L'appel existe mais n'a pas d'enregistrement (ex : enregistrement non activé)
{ "error": "No recording available" }
Référence de l'objet appel
| Champ | Type | Description |
|---|---|---|
id | string | Identifiant unique de l'appel (CUID2) |
call_sid | string | Identifiant interne de room LiveKit |
direction | enum | INBOUND ou OUTBOUND |
status | enum | Statut courant de l'appel, voir le tableau de statuts ci-dessus |
from_number | string | null | Numéro de l'appelant (E.164) |
to_number | string | Numéro appelé (E.164) |
duration | integer | null | Durée en secondes (null jusqu'à la fin de l'appel) |
queued_at | ISO 8601 | Quand l'appel a été créé |
ringing_at | ISO 8601 | null | Quand le SIP INVITE a été envoyé |
answered_at | ISO 8601 | null | Quand l'appel a été décroché |
ended_at | ISO 8601 | null | Quand l'appel s'est terminé |
recording_url | string | null | Chemin de stockage interne vers l'enregistrement WAV (ex : /storage/recordings/…wav), ce n'est pas une URL publique. Pour récupérer l'audio via l'API, utilisez GET /v1/calls/{id}/recording. |
call_variables | object | null | Variables collectées et résolues pendant l'appel |
tool_calls | array | null | Appels API externes faits pendant l'appel avec paramètres, réponse et timing |
sip_headers | object | null | En-têtes SIP reçus sur les appels entrants |