Référence API
L'API REST Manivox.ai vous permet de lire les données d'agents et d'appels par programme. Tous les endpoints retournent du JSON et requièrent une clé API.
URL de base
https://www.manivox.ai/api/v1
Tous les chemins de cette référence sont relatifs à l'URL de base. Une URL de requête complète ressemble à :
https://www.manivox.ai/api/v1/accounts/{id}/calls
Endpoints
L'API publique /v1 lit vos données et passe des appels sortants. Chaque endpoint s'authentifie avec une clé API (Bearer la_…), et ce qu'une clé peut faire dépend des permissions choisies à sa création — une clé est en lecture seule tant que vous ne lui accordez pas une permission d'appel.
| Méthode et chemin | Description | Documenté dans |
|---|---|---|
GET /v1/ping | Health check, vérifie votre clé API | Health check |
GET /v1/accounts | Liste les comptes | Cette page |
GET /v1/accounts/{id} | Détail d'un compte | Cette page |
GET /v1/accounts/{id}/agents | Liste les agents du compte | API Agents |
GET /v1/accounts/{id}/calls | Liste les appels du compte | API Appels |
GET /v1/accounts/{id}/connections | Liste les connexions du compte | Cette page |
GET /v1/accounts/{id}/connections/{connectionId} | Détail d'une connexion | Cette page |
GET /v1/calls/{id}/handoff | Résumé de transfert et variables collectées | API Appels |
GET /v1/calls/{id}/transcript | Transcription tour par tour, avec les appels d'outils/API en option | API Appels |
GET /v1/calls/{id}/recording | Télécharge l'enregistrement de l'appel (WAV) | API Appels |
POST /v1/calls | Passer un appel sortant | API Appels |
GET /v1/calls/{id}/status | Statut, durée et résultat d'un appel | API Appels |
GET|POST /v1/campaigns | Lister ou créer des campagnes | API Campagnes |
GET|PATCH|DELETE /v1/campaigns/{id} | Lire, modifier ou supprimer une campagne | API Campagnes |
POST /v1/campaigns/{id}/start|pause|resume|cancel | Piloter une campagne | API Campagnes |
GET|POST /v1/campaigns/{id}/contacts | Lire ou ajouter des contacts | API Campagnes |
GET|POST /v1/campaigns/{id}/exclusions | Numéros que cette campagne ne doit pas appeler | API Campagnes |
POST /v1/action-tokens | Créer un jeton à usage unique pour une action | Déclenchement sans backend |
POST /v1/actions/{token} | Consommer un jeton — sans clé API | Déclenchement sans backend |
L'automatisation des campagnes sortantes — création, ajout de contacts, démarrage et pause, lecture de l'avancement, gestion des exclusions — est disponible sur /v1 avec une clé API et la permission campaigns:write. Voir la page API Campagnes. Les mêmes opérations existent aussi sous /api avec l'authentification de session ; c'est ce que le dashboard lui-même utilise, et c'est la plus ancienne des deux.
Authentification
Chaque requête doit inclure votre clé API comme Bearer token dans l'en-tête Authorization :
curl https://www.manivox.ai/api/v1/ping \
-H "Authorization: Bearer la_YOUR_API_KEY"
Les clés API commencent par le préfixe la_. Une clé au format invalide, ou qui n'existe pas (supprimée ou faute de frappe), retourne 401 ; une clé révoquée ou désactivée (inactive) retourne 403 avec API key is inactive.
Activer l'accès à l'API
L'accès à l'API s'active par organisation. Demandez à votre interlocuteur Manivox d'activer l'accès API pour votre organisation. Lorsque l'accès est activé et que l'organisation n'a encore aucune clé active, une première clé est générée automatiquement et affichée une seule fois : copiez-la immédiatement. Tant que l'accès n'est pas activé, chaque requête /v1 retourne 403.
Une clé API donne un accès en lecture à toute la surface /v1 de votre organisation, elle n'est restreinte à aucun endpoint en particulier. Quiconque détient la clé peut interroger les comptes, connexions, données de handoff d'appel, transcriptions et enregistrements de votre organisation : traitez-la comme un secret.
Gérer vos clés API
Une fois l'accès activé, les admins de l'organisation gèrent eux-mêmes les clés depuis le dashboard :
- Connectez-vous au dashboard Manivox.ai avec un compte admin de l'organisation (la gestion des clés est réservée aux admins)
- Allez dans Paramètres → API
- Générez une nouvelle clé et donnez-lui un nom descriptif (ex :
production-server) - Copiez la valeur complète
la_…depuis le bandeau de copie immédiatement : elle n'est affichée qu'une fois et n'est jamais stockée en clair
Gardez votre clé API secrète. Ne la commitez jamais dans un dépôt de versions et ne l'exposez pas dans du code côté client. Stockez-la dans une variable d'environnement ou un gestionnaire de secrets (Vault, AWS Secrets Manager, etc.).
Cycle de vie d'une clé
Depuis Paramètres → API, vous pouvez révoquer une clé (elle devient inactive et retourne immédiatement 403) ou la supprimer entièrement. Il n'y a pas de bouton de rotation : pour faire tourner une clé, générez-en une nouvelle et supprimez l'ancienne. Une organisation peut détenir plusieurs clés à la fois.
| Réponse d'erreur | Cause |
|---|---|
401 Authentication required | Aucun en-tête Authorization envoyé |
401 Invalid API key format | La clé ne commence pas par la_ |
401 Invalid API key | Clé introuvable (supprimée ou faute de frappe) |
403 API key is inactive | Clé révoquée, désactivée ou inactive |
403 API key has expired | La clé a dépassé sa date d'expiration |
403 API access is not enabled for this organization | L'API est désactivée pour cette organisation |
Permissions (scopes)
Chaque clé API porte un ensemble de permissions, choisies à sa création dans Paramètres → Clés API. Une requête vers un endpoint pour lequel votre clé n'est pas habilitée renvoie 403 en nommant la permission manquante.
| Permission | Autorise |
|---|---|
read | Lister les comptes, agents, appels et campagnes ; lire les transcriptions, les résumés de transfert et les enregistrements. |
calls:write | Passer des appels sortants individuels. Peut engendrer des frais. |
campaigns:write | Créer, modifier et piloter des campagnes ; ajouter des contacts ; gérer les exclusions. Compose en masse. |
Les nouvelles clés sont en lecture seule par défaut, et toute clé créée avant l'existence des permissions est en lecture seule — accorder à une clé le droit de consommer votre solde est toujours un acte délibéré. calls:write et campaigns:write sont séparées volontairement : une clé confiée à un formulaire pour demander un rappel ne doit pas pouvoir lancer mille appels.
Ne mettez jamais une clé API dans du JavaScript navigateur. Quiconque ouvre la page peut la lire et s'en servir pour passer des appels sur votre compte, à vos frais, vers les numéros de son choix. Les limites de débit encadrent la vitesse, pas la possibilité.
Gardez la clé sur votre serveur. Le bouton ou le formulaire de votre page appelle votre backend ; c'est lui qui détient la clé, décide qui a le droit de déclencher un appel et quel numéro peut être composé. En particulier, ne laissez jamais le navigateur choisir le numéro de destination d'une requête porteuse d'une clé.
Réessayer sans risque
Les requêtes d'écriture acceptent un en-tête Idempotency-Key : n'importe quelle chaîne que vous générez par action, par exemple un identifiant de commande ou de ticket.
curl -X POST https://www.manivox.ai/api/v1/calls \
-H "Authorization: Bearer la_YOUR_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: commande-4821-rappel" \
-d '{"agent_id": "...", "to_number": "+33612345678"}'
Un nouvel essai portant la même clé renvoie la première réponse au lieu d'agir de nouveau, avec un en-tête Idempotent-Replay: true. C'est ce qui rend inoffensifs un double-clic, un timeout réseau ou un webhook renvoyé : sans cela, chacun de ces cas passe un second appel réel. Les clés sont mémorisées 24 heures et sont propres à votre organisation.
Deux cas à connaître : réutiliser une clé pour un corps de requête différent renvoie 422 (c'est un bug côté appelant, et renvoyer le résultat antérieur le masquerait), et une requête en échec ne consomme pas sa clé — vous pouvez réessayer la requête corrigée avec la même.
Déclencher depuis une page sans backend
La règle ci-dessus — ne jamais mettre une clé dans du JavaScript navigateur — suppose que vous avez un serveur pour la garder. Quand ce n'est pas le cas (site statique, formulaire no-code, widget embarqué), un jeton d'action est la façon sûre de laisser la page déclencher elle-même un appel.
Votre serveur crée un jeton pour une action, tous paramètres figés :
curl -X POST https://www.manivox.ai/api/v1/action-tokens \
-H "Authorization: Bearer la_YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"action": "calls.create",
"params": { "agent_id": "...", "to_number": "+33612345678" },
"ttl_seconds": 300,
"origin": "https://app.example.com"
}'
La page le consomme ensuite, sans clé et sans corps de requête :
await fetch(spendUrl, { method: 'POST' });
// → { "id": "clx7...", "status": "RINGING" }
La création exige la même permission que l'appel direct — calls.create demande calls:write — car c'est la moitié privilégiée. La consommation ne porte aucun justificatif, et c'est tout l'intérêt.
Ce qui rend un jeton exposable
- Le navigateur ne peut pas changer ce qu'il fait. Les paramètres sont figés à la création, et tout ce que la page envoie dans le corps est ignoré. C'est la propriété sur laquelle repose tout le reste : si la page pouvait choisir le numéro, vous auriez publié un automate d'appel.
- Il fonctionne une fois. Le jeton est réservé avant l'exécution, donc deux requêtes simultanées ne peuvent pas composer deux fois. Une seconde consommation renvoie le premier résultat avec
Idempotent-Replay: trueplutôt qu'un refus — une requête navigateur qui meurt après être arrivée est un cas ordinaire, et « déjà utilisé » laisserait votre visiteur dans le doute. - Il expire. Cinq minutes par défaut, quinze au maximum. Un jeton consommé cesse aussi de rejouer passée son expiration.
- Il peut être lié à votre origine. Renseignez
originet le jeton ne fonctionne que depuis ce site ; la réponse porte le CORS de cette seule origine, jamais un joker. - Il ne lit rien. La réponse est l'identifiant de l'appel et son statut. Un jeton n'est jamais un moyen de lire vos données.
- Il est tracé. Quelle clé l'a créé, quand il a été consommé, depuis quelle origine et quelle IP.
Au pire, un jeton volé permet donc cet appel-là, vers ce numéro, une fois, dans les minutes qui suivent — ce que le visiteur allait faire de toute façon. À comparer à une clé API fuitée, qui appelle n'importe qui, autant de fois qu'on veut, jusqu'à révocation.
Ce qu'il ne fait pas
Il n'authentifie pas votre visiteur. Ne créez un jeton que pour quelqu'un dont vous avez déjà décidé qu'il y a droit — utilisateur connecté, session de formulaire valide, numéro vérifié. Le jeton sort la capacité du navigateur en sécurité ; il ne vous dit pas qui le détient.
Les conditions sont revérifiées à la consommation, pas à la création : organisation suspendue, solde épuisé, agent supprimé ou numéro présenté non possédé échouent à ce moment-là. Un jeton est une permission d'essayer, pas la promesse que l'appel partira.
Une conséquence de la réservation du jeton avant l'exécution : un jeton est consommé même quand l'action échoue. Si le solde était épuisé ou l'agent supprimé, le visiteur voit l'erreur et votre serveur doit créer un nouveau jeton pour réessayer. C'est le compromis assumé : autoriser un nouvel essai avec le même jeton supposerait de trancher quelles erreurs sont transitoires, et se tromper là-dessus appelle quelqu'un deux fois.
Si vous avez déjà un serveur dans le circuit, rien de tout cela n'est nécessaire — gardez-y la clé et appelez POST /v1/calls. Les jetons d'action existent pour le cas où ce serveur n'existe pas.
Pagination
Les endpoints de liste utilisent une pagination basée sur l'offset avec les paramètres de requête limit et offset. La limit maximale est de 100.
# Récupérer les appels 51-100
GET /v1/accounts/{id}/calls?limit=50&offset=50
La réponse inclut toujours un champ total avec le nombre total d'enregistrements correspondants.
Format d'erreur
Les erreurs retournent un objet JSON avec un champ error décrivant ce qui a mal tourné. La seule exception est un rejet par le limiteur de requêtes de la plateforme, qui retourne le corps standard du framework { "message": "Too Many Attempts." } : considérez le statut HTTP comme la référence et le corps comme une simple indication.
// 401, clé API absente ou invalide
{ "error": "Invalid API key" }
// 404, ressource introuvable
{ "error": "Account not found" }
// 422, paramètre de requête invalide
{ "error": "Invalid \"from\" datetime format. Use ISO 8601 (e.g. 2026-01-15T10:00:00)" }
// 403, la clé n'a pas la permission requise par cet endpoint
{
"error": "This API key does not have the required scope",
"required_scope": "calls:write",
"key_scopes": ["read"]
}
// 409, une écriture avec la même Idempotency-Key est encore en cours
{ "error": "A request with this Idempotency-Key is still in progress" }
// 429, limite d'appels concurrents
{
"error": "Concurrent call limit reached",
"active_calls": 10,
"max_concurrent_calls": 10
}
Codes de statut HTTP
| Code | Signification |
|---|---|
200 OK | Requête réussie |
401 Unauthorized | Clé API absente ou invalide |
402 Payment Required | Limite de facturation dépassée : l'appel ou l'écriture de campagne a été refusé parce que votre solde ou la limite de votre compte ne le permet pas |
403 Forbidden | Clé inactive, expirée, API désactivée pour l'org, clé sans la permission requise, ou jeton d'action dépensé depuis une origine différente de celle pour laquelle il a été émis |
404 Not Found | La ressource n'existe pas ou n'est pas dans votre org |
409 Conflict | Une écriture portant la même Idempotency-Key est encore en cours, ou un jeton d'action est dépensé deux fois au même instant |
422 Unprocessable | Valeur de paramètre de requête ou de corps invalide, numéro présenté non rattaché à l'agent, ou Idempotency-Key réutilisée avec une requête différente |
429 Too Many Requests | Limite de débit dépassée, s'applique à tous les endpoints /v1 (voir Limites de débit) |
500 Server Error | Quelque chose a mal tourné de notre côté, réessayez avec backoff |
Limites de débit
Trois compteurs s'appliquent, et dépasser l'un d'eux retourne 429 Too Many Requests : appliquez un backoff puis réessayez.
- Lectures (chaque
GETsous/v1) : 120 requêtes par minute. Ce compteur est indexé sur l'adresse IP cliente qui atteint la plateforme, donc tout le trafic derrière une même adresse de sortie le partage, quelle que soit la clé ou l'organisation dont il provient. - Écritures (
POST /v1/calls,POST /v1/action-tokenset chaque écriture de campagne) : 20 requêtes par minute et par clé API. Volontairement bas : ces endpoints composent de vrais numéros et dépensent votre solde ; mettez votre travail en file plutôt que de l'envoyer en rafale. - Dépenser un jeton d'action (
POST /v1/actions/{token}, sans clé) : 30 requêtes par minute et par IP cliente.
Journalisation des requêtes
Chaque requête /v1 est journalisée, y compris les appels réussis et les rejets 401 / 403 / 429. Chaque entrée enregistre l'horodatage, la méthode HTTP, le chemin, le statut de réponse, l'IP cliente, le user agent et la durée en millisecondes. Les journaux sont purgés automatiquement au bout d'environ 90 jours.
Vous pouvez consulter cette activité dans le dashboard sous Paramètres → API → Activité API récente (les requêtes les plus récentes, avec l'heure, la requête, le statut et l'IP). Les opérateurs Manivox.ai voient la même activité récente dans la carte API Access de l'organisation. Un type de requête manque dans cette vue : dépenser un jeton d'action (POST /v1/actions/{token}) ne porte aucune clé API, il est donc journalisé sans organisation et n'apparaît pas dans votre Activité API récente ; les champs d'audit du jeton lui-même (quelle clé l'a émis, quand et d'où il a été dépensé) sont la trace à privilégier.
Comptes et connexions
Un compte est l'un des clients finaux de votre organisation (l'entité pour laquelle un agent agit). Une connexion est un toolkit tiers (CRM, agenda, etc.) lié à un compte pour que les agents puissent appeler ses outils. Les quatre endpoints ci-dessous sont en lecture seule et s'authentifient avec une clé API.
Lister les comptes
Retourne les comptes de l'organisation, triés par nom.
GET /v1/accounts
Auth : clé API (Bearer la_…)
| Paramètre | Type | Défaut | Description |
|---|---|---|---|
limit | entier | 100 | Nombre max d'enregistrements à retourner (max 100) |
offset | entier | 0 | Enregistrements à ignorer |
curl "https://www.manivox.ai/api/v1/accounts?limit=50" \
-H "Authorization: Bearer la_YOUR_API_KEY"
Réponse, 200 OK
{
"data": [
{
"id": "acc_01hx...",
"name": "Acme Corp",
"city": "Paris",
"country": "FR",
"created_at": "2026-05-26T14:30:00+00:00"
}
],
"total": 12
}
| Champ | Type | Description |
|---|---|---|
id | string | Identifiant unique du compte |
name | string | Nom du compte |
city | string | null | Ville |
country | string | null | Code pays |
created_at | ISO 8601 | Date de création du compte |
Détail d'un compte
Retourne un seul compte avec son adresse complète, son représentant et son statut KYC.
GET /v1/accounts/{id}
Auth : clé API (Bearer la_…)
Réponse, 200 OK
{
"id": "acc_01hx...",
"name": "Acme Corp",
"country": "FR",
"address": {
"street_number": "10",
"street": "Rue de la Paix",
"postal_code": "75002",
"city": "Paris"
},
"representative": {
"first_name": "Marie",
"last_name": "Dupont",
"role": "CEO",
"email": "marie@acme.example",
"phone": "+33612345678"
},
"kyc_status": "VALIDATED",
"created_at": "2026-05-26T14:30:00+00:00"
}
| Champ | Type | Description |
|---|---|---|
id | string | Identifiant unique du compte |
name | string | Nom du compte |
country | string | null | Code pays |
address | object | Adresse postale : street_number, street, postal_code, city |
representative | object | Représentant légal : first_name, last_name, role, email, phone |
kyc_status | enum | DRAFT, PENDING, VALIDATED ou REJECTED |
created_at | ISO 8601 | Date de création du compte |
Erreur, 404 Not Found : le compte n'existe pas pour l'organisation de cette clé API :
{ "error": "Account not found" }
Lister les connexions
Retourne les connexions tierces liées à un compte, les plus récentes d'abord.
GET /v1/accounts/{id}/connections
Auth : clé API (Bearer la_…)
| Paramètre | Type | Défaut | Description |
|---|---|---|---|
limit | entier | 100 | Nombre max d'enregistrements à retourner (max 100) |
offset | entier | 0 | Enregistrements à ignorer |
status | string | - | Filtre par statut : PENDING, ACTIVE, EXPIRED ou ERROR (insensible à la casse) |
# Uniquement les connexions actives
curl "https://www.manivox.ai/api/v1/accounts/acc_01hx.../connections?status=active" \
-H "Authorization: Bearer la_YOUR_API_KEY"
Réponse, 200 OK
{
"data": [
{
"id": "con_01hx...",
"reference": "acme-hubspot",
"toolkit_slug": "hubspot",
"toolkit_name": "HubSpot",
"status": "ACTIVE",
"created_at": "2026-05-26T14:30:00+00:00",
"updated_at": "2026-05-26T14:35:00+00:00"
}
],
"total": 3
}
| Champ | Type | Description |
|---|---|---|
id | string | Identifiant unique de la connexion |
reference | string | null | Votre référence pour la connexion |
toolkit_slug | string | null | Slug du toolkit (ex : hubspot) |
toolkit_name | string | null | Nom lisible du toolkit |
status | enum | PENDING, ACTIVE, EXPIRED ou ERROR |
oauth_redirect_url | string | Présent uniquement lorsque status vaut PENDING : l'URL pour terminer le flux OAuth |
created_at | ISO 8601 | Date de création de la connexion |
updated_at | ISO 8601 | Date de dernière mise à jour de la connexion |
Détail d'une connexion
Retourne une seule connexion par son id. L'objet a la même forme qu'une entrée de la liste ci-dessus.
GET /v1/accounts/{id}/connections/{connectionId}
Auth : clé API (Bearer la_…)
{
"id": "con_01hx...",
"reference": "acme-hubspot",
"toolkit_slug": "hubspot",
"toolkit_name": "HubSpot",
"status": "ACTIVE",
"created_at": "2026-05-26T14:30:00+00:00",
"updated_at": "2026-05-26T14:35:00+00:00"
}
Erreurs, 404 Not Found
// Le compte n'existe pas pour l'organisation de cette clé API
{ "error": "Account not found" }
// Le compte existe mais l'id de connexion est inconnu
{ "error": "Connection not found" }
Explorateur d'API interactif
Le dashboard intègre une référence API sous Paramètres → API → Documentation API : chaque endpoint /v1 est présenté sous forme de carte dépliable avec ses paramètres, un exemple curl prêt à copier et un exemple de réponse. Chaque carte dispose aussi d'un testeur Essayer en direct — collez votre clé API (et un identifiant d'appel lorsque l'endpoint en a besoin) et lancez une vraie requête sans quitter le navigateur. L'URL de base et le format de l'en-tête Authorization sont affichés en haut.
Health check
Utilisez l'endpoint ping pour vérifier votre clé API et la connectivité :
curl https://www.manivox.ai/api/v1/ping \
-H "Authorization: Bearer la_YOUR_API_KEY"
# 200 OK
{ "status": "ok", "organization_id": "org_01hx...", "timestamp": "2026-06-29T10:00:00+00:00" }