Aller au contenu de la page
Documentation
Documentation de Make Agent Fast

Consultations

Lisez des fiches clients en temps réel grâce à des requêtes signées envoyées à votre système métier.

En un coup d’œil

Lisez des fiches clients en temps réel grâce à des requêtes signées envoyées à votre système métier.

Quand utiliser une consultation#

Utilisez une consultation pour obtenir l'état actuel d'une commande, une réservation existante ou la fiche de compte d'un client. Conservez les politiques stables et les informations produit dans les Sources. Une consultation lit votre système ; elle ne doit pas facturer, annuler, réserver ni modifier un enregistrement de quelque manière que ce soit. Les cartes génériques de choix et de confirmation envoient uniquement un message du visiteur. Pour les écritures confirmées, utilisez les Actions de modification ; pour les réservations de calendrier, utilisez la réservation avec Cal.com. Seules les cartes de confirmation adossées à une exécution autorisent ces opérations.

Configurer l'action#

Ouvrez Agent → Actions. Créez le secret dans Clients connectés, stockez-le sur votre serveur et mettez en œuvre l'identification des clients. Dans Consultations, ajoutez un nom tel que order_status, expliquez quand l'agent doit l'utiliser et saisissez votre endpoint HTTPS public. Ne déclarez que les entrées dont vous avez besoin, par exemple une chaîne order_id. L'agent voit cet outil sous le nom lookup_order_status.

Laissez activée l'option Client connecté requis pour les fiches privées (valeur par défaut). Si elle est désactivée, les requêtes peuvent contenir customer: null ; ne renvoyez alors que des informations adaptées à un visiteur anonyme. Un identifiant mentionné dans le chat ou extrait d'une photo est une entrée, et non une identité authentifiée.

Les champs existants sont enregistrés automatiquement ; attendez l'indicateur d'enregistrement avant de tester. Vous pouvez activer/désactiver, modifier ou supprimer une consultation. Le panneau nécessite qu'un secret soit configuré. Ces actions se configurent dans le tableau de bord ; la vague 1 n'expose pas la gestion des consultations via l'API publique.

La requête que vous recevez#

Make Agent Fast envoie une requête POST JSON à l'URL que vous avez configurée. Les exemples ci-dessous utilisent des valeurs de signature fictives :

POST /agent/order-status HTTP/1.1
Content-Type: application/json
x-maf-timestamp: <unix-seconds>
x-maf-signature: v1=<64-lowercase-hex-characters>
{
  "version": 1,
  "action": "order_status",
  "requestId": "c5c1d94b-e88f-4bf6-8023-2dcd1e7ac67b",
  "siteId": "YOUR_SITE_ID",
  "input": { "order_id": "A128" },
  "customer": { "id": "customer_123", "email": "customer@example.com" }
}

action correspond au nom configuré, sans le préfixe lookup_. requestId identifie cette tentative ; siteId identifie votre site. input ne contient que les paramètres de type chaîne déclarés. customer vaut soit null, soit l'objet { id, email?, name? } vérifié côté serveur ; les entrées du visiteur ou du modèle ne peuvent pas le remplacer. Le bouton Tester du tableau de bord utilise volontairement le client fictif saisi par un propriétaire autorisé.

Vérifier la signature#

La signature est un HMAC-SHA256 en hexadécimal minuscule, calculé avec votre secret d'agent et préfixé par v1=. Signez exactement "maf-webhook-v1:" + timestamp + "." + rawBody. Conservez les octets reçus : analyser puis resérialiser le JSON avant de vérifier la signature peut les modifier. Cette fonction utilitaire accepte une Request serveur standard, applique une fenêtre de validité de cinq minutes et verrouille le site :

import { createHmac, timingSafeEqual } from "node:crypto";

export async function verifyLookupRequest(request, expectedSiteId) {
  const secret = process.env.MAF_SECRET_KEY;
  if (!secret) throw new Error("MAF_SECRET_KEY is required");
  const timestamp = request.headers.get("x-maf-timestamp");
  const signature = request.headers.get("x-maf-signature");
  const now = Math.floor(Date.now() / 1000);
  if (!timestamp || !/^\d+$/.test(timestamp) ||
      !Number.isSafeInteger(Number(timestamp)) ||
      Math.abs(now - Number(timestamp)) > 300) {
    throw new Error("Invalid timestamp");
  }
  if (!signature || !/^v1=[a-f0-9]{64}$/.test(signature)) {
    throw new Error("Invalid signature");
  }
  const rawBody = Buffer.from(await request.arrayBuffer());
  const expected = createHmac("sha256", secret)
    .update(`maf-webhook-v1:${timestamp}.`)
    .update(rawBody)
    .digest();
  const actual = Buffer.from(signature.slice(3), "hex");
  if (actual.length !== expected.length || !timingSafeEqual(actual, expected)) {
    throw new Error("Invalid signature");
  }
  const body = JSON.parse(rawBody.toString("utf8"));
  if (body?.version !== 1 || body.siteId !== expectedSiteId) {
    throw new Error("Invalid lookup scope");
  }
  return body;
}

Appelez-la avant que votre analyseur de corps (body parser) ne consomme la requête. Votre gestionnaire doit rejeter les erreurs de vérification, valider l'action attendue et la forme des entrées, puis contrôler l'appartenance de l'enregistrement à body.customer.id avant de renvoyer des données privées. Par exemple, sélectionnez la commande A128 parmi les commandes de ce client, et non à partir de son seul identifiant de commande. N'utilisez jamais input.customer_id, un e-mail fourni dans le chat ou une photo comme autorisation. Exigez un client non null pour les endpoints privés. Limitez la taille du corps des requêtes entrantes sur votre serveur et suivez les requestId pendant la fenêtre de validité si vous souhaitez rejeter les rejeux ; la vérification de l'horodatage seule ne rejette pas un rejeu intervenant dans cette fenêtre.

Utilisez HTTPS et gardez cet endpoint en lecture seule, même si le transport se fait en POST. Après une rotation du secret d'agent, mettez à jour à la fois votre serveur de signature d'identité et votre vérificateur de consultations.

Renvoyer une réponse#

Répondez avec un statut 2xx et un JSON conforme à ce contrat. Le premier exemple correspond à un enregistrement trouvé ; le second à un résultat normal sans correspondance :

{
  "found": true,
  "card": {
    "title": "Order #A128",
    "status": { "label": "Shipped", "tone": "success" },
    "fields": [{ "label": "Carrier", "value": "DHL" }],
    "reference": "A128",
    "asOf": "2026-10-12T09:00:00Z",
    "link": { "label": "Track", "url": "https://shop.example.com/orders/A128" }
  },
  "facts": { "order_id": "A128", "status": "shipped", "carrier": "DHL" }
}
{ "found": false }

found est obligatoire. Pour found: true, incluez card, facts ou les deux. Une carte requiert title et fields (un tableau vide est autorisé). Les champs facultatifs sont status, reference, asOf et link. N'ajoutez pas kind à la carte de la réponse. Les tons de statut sont neutral, success, warning et danger. Utilisez un horodatage ISO pour asOf et un lien HTTPS sans identifiants intégrés. Les liens facultatifs invalides sont omis.

facts est un objet plat dont les valeurs sont des chaînes, des nombres finis, des booléens ou null ; les objets imbriqués et les tableaux sont rejetés. Les champs inconnus dans le schéma de réponse ou de carte sont rejetés. Ne renvoyez que les informations nécessaires pour répondre : le modèle reçoit des données échappées et bornées, signalées comme non fiables, et non des instructions. Le contenu de la carte est du texte brut, pas du HTML.

Limites et comportement en cas d'échec#

ÉlémentLimite
Consultations par agent5 ; noms et identifiants uniques
Nom^[a-z][a-z0-9_]{2,39}$ ; les noms d'action réservés ne sont pas disponibles
Description300 caractères
Entrées déclarées3 ; noms uniques correspondant à ^[a-z][a-z0-9_]{1,31}$
Descriptions / valeurs des entrées300 / 200 caractères ; les valeurs sont tronquées des espaces superflus
EndpointHTTPS public, jusqu'à 500 caractères, sans identifiants ; adresses privées/internes bloquées ; redirections non suivies
Délai d'attente / corps de la réponse8 secondes / 32 KiB (32 768 octets)
Données du modèle2 000 caractères, distinctes de la carte du visiteur
Titre / libellés / valeurs des champs de la carte80 / 40 / 200 caractères
Champs de la carte8 ; au maximum 3 cartes par tour de l'agent

L'absence d'identité client produit un avertissement de connexion sans appeler votre endpoint. Si des entrées requises manquent, l'agent les demande au visiteur. found: false affiche une carte neutre indiquant l'absence de résultat. Les délais dépassés, les statuts non 2xx, les JSON ou schémas invalides et les réponses trop volumineuses affichent un statut d'échec et indiquent au modèle de ne pas deviner. Pour un enregistrement simplement absent, renvoyez found: false avec un statut 2xx plutôt qu'un HTTP 404. Gardez les faits importants concis : les chaînes de carte et les données du modèle en excès sont tronquées.

Tester depuis le tableau de bord#

  1. Enregistrez la consultation et ouvrez Tester. Saisissez un identifiant client fictif, un e-mail facultatif et toutes les entrées requises. Utilisez un compte que vous contrôlez.
  2. Lancez Tester. Cela envoie une véritable requête signée, même si la consultation est désactivée pour les visiteurs ; le chat de répétition ordinaire n'appelle jamais l'endpoint. Le tableau de bord limite le nombre de tentatives de test par propriétaire.
  3. Examinez la carte/le résumé validé ou l'erreur, l'identifiant de requête, la durée et le statut HTTP lorsqu'ils sont disponibles. Consultez les journaux de votre endpoint sans y enregistrer de secrets ni de jetons client.
  4. Testez les cas suivants : trouvé, non trouvé, mauvais compte, entrée manquante et délai dépassé. Testez ensuite l'intégration réelle avec deux clients authentifiés ; un client fictif du tableau de bord ne prouve ni l'isolation de l'identité dans le navigateur, ni la sélection réelle de l'outil par le modèle.

Le widget affiche des cartes de statut ; les appuis sur les choix et confirmations génériques envoient leurs libellés sous forme de messages. Les confirmations de modification et de réservation adossées à une exécution utilisent à la place le flux d'exécution protégé. Les connecteurs adaptent les cartes en texte/cartes natifs et en boutons, réponses rapides ou listes, avec un repli en texte, dans la limite des contraintes de chaque canal. Testez chaque canal visé avant de vous appuyer sur la livraison.