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.

API keys and endpoint reference

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 cheminDescriptionDocumenté dans
GET /v1/pingHealth check, vérifie votre clé APIHealth check
GET /v1/accountsListe les comptesCette page
GET /v1/accounts/{id}Détail d'un compteCette page
GET /v1/accounts/{id}/agentsListe les agents du compteAPI Agents
GET /v1/accounts/{id}/callsListe les appels du compteAPI Appels
GET /v1/accounts/{id}/connectionsListe les connexions du compteCette page
GET /v1/accounts/{id}/connections/{connectionId}Détail d'une connexionCette page
GET /v1/calls/{id}/handoffRésumé de transfert et variables collectéesAPI Appels
GET /v1/calls/{id}/transcriptTranscription tour par tour, avec les appels d'outils/API en optionAPI Appels
GET /v1/calls/{id}/recordingTélécharge l'enregistrement de l'appel (WAV)API Appels
POST /v1/callsPasser un appel sortantAPI Appels
GET /v1/calls/{id}/statusStatut, durée et résultat d'un appelAPI Appels
GET|POST /v1/campaignsLister ou créer des campagnesAPI Campagnes
GET|PATCH|DELETE /v1/campaigns/{id}Lire, modifier ou supprimer une campagneAPI Campagnes
POST /v1/campaigns/{id}/start|pause|resume|cancelPiloter une campagneAPI Campagnes
GET|POST /v1/campaigns/{id}/contactsLire ou ajouter des contactsAPI Campagnes
GET|POST /v1/campaigns/{id}/exclusionsNuméros que cette campagne ne doit pas appelerAPI Campagnes
POST /v1/action-tokensCréer un jeton à usage unique pour une actionDéclenchement sans backend
POST /v1/actions/{token}Consommer un jeton — sans clé APIDé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 :

  1. Connectez-vous au dashboard Manivox.ai avec un compte admin de l'organisation (la gestion des clés est réservée aux admins)
  2. Allez dans Paramètres → API
  3. Générez une nouvelle clé et donnez-lui un nom descriptif (ex : production-server)
  4. 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'erreurCause
401 Authentication requiredAucun en-tête Authorization envoyé
401 Invalid API key formatLa clé ne commence pas par la_
401 Invalid API keyClé introuvable (supprimée ou faute de frappe)
403 API key is inactiveClé révoquée, désactivée ou inactive
403 API key has expiredLa clé a dépassé sa date d'expiration
403 API access is not enabled for this organizationL'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.

PermissionAutorise
readLister les comptes, agents, appels et campagnes ; lire les transcriptions, les résumés de transfert et les enregistrements.
calls:writePasser des appels sortants individuels. Peut engendrer des frais.
campaigns:writeCré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: true plutô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 origin et 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

CodeSignification
200 OKRequête réussie
401 UnauthorizedClé API absente ou invalide
402 Payment RequiredLimite 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 ForbiddenClé 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 FoundLa ressource n'existe pas ou n'est pas dans votre org
409 ConflictUne é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 UnprocessableValeur 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 RequestsLimite de débit dépassée, s'applique à tous les endpoints /v1 (voir Limites de débit)
500 Server ErrorQuelque 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 GET sous /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-tokens et 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ètreTypeDéfautDescription
limitentier100Nombre max d'enregistrements à retourner (max 100)
offsetentier0Enregistrements à 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
}
ChampTypeDescription
idstringIdentifiant unique du compte
namestringNom du compte
citystring | nullVille
countrystring | nullCode pays
created_atISO 8601Date 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"
}
ChampTypeDescription
idstringIdentifiant unique du compte
namestringNom du compte
countrystring | nullCode pays
addressobjectAdresse postale : street_number, street, postal_code, city
representativeobjectReprésentant légal : first_name, last_name, role, email, phone
kyc_statusenumDRAFT, PENDING, VALIDATED ou REJECTED
created_atISO 8601Date 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ètreTypeDéfautDescription
limitentier100Nombre max d'enregistrements à retourner (max 100)
offsetentier0Enregistrements à ignorer
statusstring-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
}
ChampTypeDescription
idstringIdentifiant unique de la connexion
referencestring | nullVotre référence pour la connexion
toolkit_slugstring | nullSlug du toolkit (ex : hubspot)
toolkit_namestring | nullNom lisible du toolkit
statusenumPENDING, ACTIVE, EXPIRED ou ERROR
oauth_redirect_urlstringPrésent uniquement lorsque status vaut PENDING : l'URL pour terminer le flux OAuth
created_atISO 8601Date de création de la connexion
updated_atISO 8601Date 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" }