Saltar al contenido de la página
Documentación
Documentación de Make Agent Fast

Consultas

Lee registros de clientes en tiempo real mediante solicitudes firmadas a tu sistema de negocio.

De un vistazo

Lee registros de clientes en tiempo real mediante solicitudes firmadas a tu sistema de negocio.

Cuándo usar una consulta#

Usa una consulta para obtener el estado actual de un pedido, una reserva existente o el registro de la cuenta de un cliente. Mantén las políticas estables y la información de productos en Conocimiento. Una consulta lee tu sistema; no debe cobrar, cancelar, reservar ni modificar de ningún otro modo un registro. Las tarjetas genéricas de elección y confirmación solo envían un mensaje del visitante. Para escrituras confirmadas, usa Acciones de cambio; para reservas de calendario, usa Reservas con Cal.com. Solo las tarjetas de confirmación respaldadas por una ejecución autorizan esas operaciones.

Configura la acción#

Abre Agente → Acciones. Crea el secreto en Clientes con sesión iniciada, guárdalo en tu servidor e implementa la identificación de clientes. En Consultas, añade un nombre como order_status, explica cuándo debe usarla el agente e introduce tu endpoint HTTPS público. Declara solo las entradas que necesites, por ejemplo una cadena order_id. El agente ve la herramienta como lookup_order_status.

Mantén activada la opción Requiere cliente con sesión iniciada para registros privados (es el valor predeterminado). Si la desactivas, las solicitudes pueden contener customer: null; devuelve solo información apropiada para un visitante anónimo. Un ID mencionado en el chat o extraído de una foto es una entrada, no una identidad autenticada.

Los campos existentes se guardan automáticamente; espera al indicador de guardado antes de probar. Puedes activar o desactivar, editar o eliminar una consulta. El panel requiere un secreto configurado. Estas acciones se configuran en el panel; la primera fase no expone la gestión de consultas a través de la API pública.

La solicitud que recibes#

Make Agent Fast envía un POST JSON a la URL que configuraste. Los ejemplos siguientes usan valores de firma de marcador de posición:

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 es el nombre configurado sin el prefijo lookup_. requestId identifica ese intento; siteId identifica tu sitio. input contiene únicamente los parámetros de tipo cadena declarados. customer es null o el objeto { id, email?, name? } verificado por el servidor; las entradas del visitante o del modelo no pueden sustituirlo. La Prueba del panel usa deliberadamente el cliente de ejemplo introducido por un propietario autorizado.

Verifica la firma#

La firma es un HMAC-SHA256 en hexadecimal en minúsculas que usa tu secreto del agente, con el prefijo v1=. Firma exactamente "maf-webhook-v1:" + timestamp + "." + rawBody. Conserva los bytes recibidos; analizar y volver a serializar el JSON antes de comprobar la firma puede alterarlos. Esta función auxiliar acepta un Request estándar del lado del servidor, aplica una ventana de validez de cinco minutos y fija el sitio:

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;
}

Llámala antes de que tu analizador de cuerpo consuma la solicitud. Tu controlador debe rechazar los errores de verificación, validar la acción esperada y la forma de las entradas, y comprobar la propiedad del registro con body.customer.id antes de devolver cualquier dato privado. Por ejemplo, selecciona el pedido A128 dentro de los pedidos de ese cliente, no solo por el ID del pedido. Nunca uses input.customer_id, un correo electrónico proporcionado en el chat ni una foto como autorización. Exige un cliente no nulo en los endpoints privados. Limita el tamaño del cuerpo entrante en tu servidor y registra requestId dentro de la ventana de validez si necesitas rechazar repeticiones; la comprobación de la marca de tiempo por sí sola no rechaza una repetición dentro de esa ventana.

Usa HTTPS y mantén este endpoint en modo de solo lectura aunque el transporte sea POST. Tras rotar el secreto del agente, actualiza tanto el servidor que firma la identidad como el verificador de consultas.

Devuelve una respuesta#

Responde con un estado 2xx correcto y un JSON que cumpla este contrato. El primer ejemplo es un registro encontrado; el segundo es un resultado normal sin coincidencias:

{
  "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 es obligatorio. Con found: true, incluye card, facts o ambos. Una tarjeta requiere title y fields (se permite un array vacío). Los campos opcionales son status, reference, asOf y link. No añadas kind a la tarjeta de la respuesta. Los tonos de estado son neutral, success, warning y danger. Usa una marca de tiempo ISO para asOf y un enlace HTTPS sin credenciales incrustadas. Los enlaces opcionales no válidos se omiten.

facts es un objeto plano cuyos valores son cadenas, números finitos, booleanos o null; los objetos anidados y los arrays se rechazan. Los campos desconocidos en el esquema de la respuesta o de la tarjeta se rechazan. Devuelve solo la información necesaria para responder: el modelo recibe datos escapados y acotados, marcados como no confiables, no instrucciones. El contenido de la tarjeta es texto sin formato, no HTML.

Límites y comportamiento ante fallos#

ElementoLímite
Consultas por agente5; nombres e IDs únicos
Nombre^[a-z][a-z0-9_]{2,39}$; los nombres de acciones reservados no están disponibles
Descripción300 caracteres
Entradas declaradas3; nombres únicos que cumplan ^[a-z][a-z0-9_]{1,31}$
Descripciones / valores de entradas300 / 200 caracteres; los valores se recortan
EndpointHTTPS público, hasta 500 caracteres, sin credenciales; direcciones privadas/internas bloqueadas; no se siguen redirecciones
Tiempo de espera / cuerpo de la respuesta8 segundos / 32 KiB (32 768 bytes)
Datos para el modelo2000 caracteres, independientes de la tarjeta del visitante
Título / etiquetas / valores de campo de la tarjeta80 / 40 / 200 caracteres
Campos de la tarjeta8; como máximo 3 tarjetas por turno del agente

Si falta la identidad del cliente, se muestra un aviso para iniciar sesión sin llamar a tu endpoint. Si faltan entradas obligatorias, se las solicita al visitante. found: false muestra una tarjeta neutral de sin coincidencias. Los tiempos de espera agotados, los estados distintos de 2xx, el JSON o esquema no válido y las respuestas demasiado grandes muestran un estado de fallo e indican al modelo que no adivine. Devuelve found: false con un 2xx para un registro inexistente habitual, en lugar de un HTTP 404. Mantén concisos los datos importantes: las cadenas de la tarjeta y los datos del modelo que excedan el límite se recortan.

Prueba desde el panel#

  1. Guarda la consulta y abre Prueba. Introduce un ID de cliente de ejemplo, un correo electrónico opcional y todas las entradas obligatorias. Usa una cuenta que controles.
  2. Ejecuta la Prueba. Esto envía una solicitud firmada real, incluso si la consulta está desactivada para los visitantes; el chat de ensayo normal nunca llama al endpoint. El panel limita los intentos de prueba por owner.
  3. Revisa la tarjeta o el resumen validados, o el error, el ID de solicitud, la duración y el estado HTTP cuando estén disponibles. Revisa los registros de tu endpoint sin guardar secretos ni tokens de clientes.
  4. Prueba los casos de encontrado, no encontrado, cuenta incorrecta, entrada faltante y tiempo de espera agotado. Después, prueba el embed real con dos clientes autenticados; un ejemplo del panel no demuestra el aislamiento de identidad en el navegador ni la selección real de herramientas por parte del modelo.

El widget muestra tarjetas de estado; los toques en tarjetas genéricas de elección o confirmación envían sus etiquetas como mensajes. Las confirmaciones de cambios y reservas respaldadas por una ejecución usan en su lugar el flujo de ejecución protegido. Los conectores adaptan las tarjetas a texto o tarjetas nativos y a botones, respuestas rápidas o listas, con texto alternativo según los límites de cada canal. Prueba cada canal previsto antes de confiar en la entrega.