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

Bientôt disponible

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..."
  }
}
ChampRequisTypeDescription
agent_idOuistringID de l'agent à utiliser, il doit disposer d'une version en ligne pour traiter l'appel
to_numberOuistringNuméro de destination au format E.164 (ex : +33612345678)
from_numberNonstring | nullCaller ID affiché au destinataire, utilisez un numéro de votre organisation. Omettre pour utiliser le numéro par défaut du trunk.
sip_headersNonobject | nullEn-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 :

StatutSignification
COMPLETEDL'appel s'est terminé normalement
FAILEDErreur SIP ou crash d'agent
NO_ANSWERL'appel sortant n'a pas été décroché
BUSYLigne de destination occupée
CANCELEDAppel 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ètreTypeDéfautDescription
limitinteger100Nombre max d'enregistrements (max 100)
offsetinteger0Enregistrements à sauter
agent_idstring-Filtrer par un agent spécifique
fromISO 8601-Début de la plage de dates (ex : 2026-05-01T00:00:00)
toISO 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
}
ChampTypeDescription
call_idstringIdentifiant unique de l'appel (CUID2)
agent_idstringID de l'agent ayant traité l'appel
directionenumINBOUND ou OUTBOUND
statusenumStatut de l'appel (voir le tableau de statuts ci-dessus)
from_numberstring | nullNuméro de l'appelant (E.164)
to_numberstringNuméro appelé (E.164)
durationinteger | nullDurée en secondes (null jusqu'à la fin de l'appel)
recording_availablebooleanIndique 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_atISO 8601 | nullQuand l'appel a été décroché
ended_atISO 8601 | nullQuand l'appel s'est terminé
created_atISO 8601Quand 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"
  }
}
ChampTypeDescription
call_idstringRépète le call id demandé
statusenumready quand le résumé est disponible, pending s'il n'était pas prêt dans la fenêtre d'attente
summaryobject | nullObjet 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)
variablesobjectDictionnaire 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ètreTypeDéfautDescription
with_toolsbooleanfalseQuand 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" }
  ]
}
ChampTypeDescription
call_idstringRépète le call id demandé
statusenumLe 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_countintegerNombre d'entrées dans transcript
with_toolsbooleanRépète si ?with_tools=true a été demandé
transcriptarrayTours 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) :

ChampTypeDescription
namestringNom de l'action ou de l'outil
methodstring | nullMéthode HTTP, pour les appels Web Service / Composio
urlstring | nullURL de la requête, le cas échéant
statusinteger | nullCode de statut HTTP retourné
requestobject | nullCorps/paramètres de la requête (rédigé côté serveur, comme dans le dashboard)
responseobject | nullCorps de la réponse (rédigé côté serveur, comme dans le dashboard)
duration_msinteger | nullDurée de l'appel en millisecondes
errorstring | nullMessage 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êteValeur
Content-Typeaudio/wav
Content-Dispositionattachment; filename="recording-{call_id}.wav" (téléchargement de fichier). Avec ?stream, c'est inline à la place, pour une lecture dans le navigateur.
Accept-Rangesbytes, 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

ChampTypeDescription
idstringIdentifiant unique de l'appel (CUID2)
call_sidstringIdentifiant interne de room LiveKit
directionenumINBOUND ou OUTBOUND
statusenumStatut courant de l'appel, voir le tableau de statuts ci-dessus
from_numberstring | nullNuméro de l'appelant (E.164)
to_numberstringNuméro appelé (E.164)
durationinteger | nullDurée en secondes (null jusqu'à la fin de l'appel)
queued_atISO 8601Quand l'appel a été créé
ringing_atISO 8601 | nullQuand le SIP INVITE a été envoyé
answered_atISO 8601 | nullQuand l'appel a été décroché
ended_atISO 8601 | nullQuand l'appel s'est terminé
recording_urlstring | nullChemin 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_variablesobject | nullVariables collectées et résolues pendant l'appel
tool_callsarray | nullAppels API externes faits pendant l'appel avec paramètres, réponse et timing
sip_headersobject | nullEn-têtes SIP reçus sur les appels entrants