Aller au contenu
Préproduction : l'API répond sur https://api.visiobank.com/v1, avec une clé de test. Les exemples gardent l'adresse de production, api.vizalia.ai, qui ouvrira à la mise en production.

Brancher un agent Retell

Ajoutez un MCP à l’agent avec l’adresse et deux en-têtes, Authorization et X-Call-Id rempli par {{call_id}}, car Retell n’envoie pas l’identifiant de l’appel de lui-même. Réglez son délai (timeout, en millisecondes) au-dessus de 90000, et donnez le numéro de l’appelant dans le prompt, {{user_number}}. Retell signe ses webhooks avec votre clé Retell, que Vizalia ne détient pas : votre serveur reçoit call_ended, vérifie la signature, puis relaie la fin d’appel à Vizalia.

Vizalia crée votre agent vocal dans son back-office et vous remet sa clé vz_<préfixe>_…, affichée une seule fois.

  1. Le numéro de l’appelant. Ajoutez au prompt de l’agent : « Le numéro de l’appelant est {{user_number}} : passe-le à start_session. »

  2. Le MCP. MCPs, Add MCP :

    Champ Valeur
    URL https://mcp.vizalia.ai/mcp
    Délai 130000 ms (au-dessus de 90000)
    En-tête Authorization Bearer vz_<préfixe>_…
    En-tête X-Call-Id {{call_id}} : Retell n’envoie pas l’identifiant de l’appel de lui-même
  3. Les outils. Ajoutez les outils dont votre agent se sert (start_session, session_status, analyze_frame, take_photo, record_video, submit_case, end_session), chacun en « Wait for completion », jamais en arrière-plan : Retell ne relance pas un outil échoué.

  4. La fin d’appel. Pointez le webhook de l’agent sur votre serveur, qui relaie la fin d’appel à Vizalia (ci-dessous).

Retell signe ses webhooks avec votre clé d’API Retell, que Vizalia ne détient pas. Votre serveur reçoit donc call_ended, vérifie sa signature, puis prévient Vizalia avec la clé de l’agent :

POST https://mcp.vizalia.ai/webhooks/generic
Authorization: Bearer vz_<préfixe>_…
Content-Type: application/json
{"event": "call_ended", "call_id": "<identifiant de l'appel>"}

L’en-tête x-retell-signature vaut v=<horodatage en millisecondes>,d=<signature>, où la signature est le HMAC-SHA256 hexadécimal du corps brut suivi de l’horodatage, avec la clé d’API Retell qui porte le badge webhook. Refusez un envoi décalé de plus de 5 minutes.

relais-retell.mjs
// Relais de fin d'appel Retell → Vizalia (Node.js 18 ou plus, npm install express).
// Retell signe ses webhooks avec votre clé d'API Retell (celle à badge webhook),
// que Vizalia ne détient pas : votre serveur vérifie la signature, puis prévient
// Vizalia avec la clé de votre agent vocal.
import { createHmac, timingSafeEqual } from 'node:crypto';
import express from 'express';
const CLE_RETELL = process.env.RETELL_API_KEY; // clé d'API Retell à badge webhook
const CLE_VIZALIA = process.env.VIZALIA_AGENT_KEY; // vz_<préfixe>_…, la clé de l'agent vocal
const TOLERANCE_MS = 5 * 60 * 1000;
// x-retell-signature: v=<horodatage en ms>,d=<HMAC-SHA256 hexadécimal du corps brut suivi de l'horodatage>
export function signatureRetellValide(corpsBrut, entete, cle = CLE_RETELL, maintenant = Date.now()) {
const morceaux = /^v=(\d+),d=([0-9a-f]+)$/.exec(entete ?? '');
if (!morceaux) return false;
const [, horodatage, recue] = morceaux;
if (Math.abs(maintenant - Number(horodatage)) > TOLERANCE_MS) return false;
const attendue = createHmac('sha256', cle).update(Buffer.concat([corpsBrut, Buffer.from(horodatage)])).digest('hex');
return recue.length === attendue.length && timingSafeEqual(Buffer.from(recue), Buffer.from(attendue));
}
const app = express();
app.post('/webhooks/retell', express.raw({ type: 'application/json' }), async (req, res) => {
if (!signatureRetellValide(req.body, req.get('x-retell-signature'))) return res.sendStatus(401);
res.sendStatus(204);
const evenement = JSON.parse(req.body);
if (evenement.event !== 'call_ended') return;
await fetch('https://mcp.vizalia.ai/webhooks/generic', {
method: 'POST',
headers: { Authorization: `Bearer ${CLE_VIZALIA}`, 'Content-Type': 'application/json' },
body: JSON.stringify({ event: 'call_ended', call_id: evenement.call.call_id }),
});
});
if (import.meta.url === `file://${process.argv[1]}`) app.listen(3000);

Sans ce relais, la session se ferme d’elle-même 16 minutes après la dernière requête de l’appel.

Testez par un vrai appel vers l’agent. Avec une clé vz_test_…, aucun SMS ne part : ouvrez vous-même le lien que renvoie start_session.