Hacer hablar a un agente de DaleVoz desde su código, integrarlo en su sitio, probar quién habla, darle herramientas y pilotarlo desde una IA. Cada ruta descrita aquí es la que sirve la producción.
Todas las superficies de DaleVoz (el widget de su sitio, las aplicaciones móviles, sus servidores) hablan con el agente por la misma ruta: POST https://dalevoz.ai/api/v1/interact. Entra una acción (un mensaje, un clic en un botón), salen trazas (texto, botones, tarjetas), y la conversación vive en nuestros servidores.
Cada llamada lleva una clave en el encabezado Authorization: Bearer …. Una clave pertenece a un espacio, no a un agente: abre todos los agentes de ese espacio, y ningún otro. El servidor solo guarda una huella, por eso se muestra una única vez, al crearla.
| Clave | Dónde vive | Qué la protege | Qué abre |
|---|---|---|---|
pk_… | En el HTML de su sitio o en una aplicación: es pública por naturaleza, como una clave publicable de pago. | La lista de dominios autorizados de la clave, comparada con los encabezados Origin o Referer de cada llamada. Un dominio abre también sus subdominios, y www. y el dominio sin www. valen el uno por el otro. Lista vacía: ninguna restricción. | Hablar con los agentes publicados: interact, messages, history, attachments, theme, voice, site. |
sk_… | Solo en su servidor. Nunca en un navegador, una aplicación o un repositorio de código. | Su secreto. Trátela como una contraseña. | Las rutas de conversación sin control de origen (salvo voice, reservada a las claves pk_), más la administración: escribir un agente, su base de conocimiento, sus segmentos, leer las estadísticas y exportar las conversaciones. También recibe el costo de cada turno (usage). Una clave puede restringirse a alcances elegidos al crearla (agents:read, kb:write, interact…): una llamada fuera de alcance responde 403 con code « portee_manquante » y el nombre del alcance en porteeRequise. |
Dónde crearlas.
sk_: consola, Ajustes, pestaña « ChatGPT y Claude », sección plegada « Para un desarrollador: claves de API », botón « Crear una clave de servidor ». Reservado a quienes administran el espacio.pk_: página del agente, pestaña « Publicar », tarjeta « Sitio web », parte « Para un técnico ». Ahí también se ajusta la lista de dominios autorizados y se copia la etiqueta del widget, con la clave ya puesta.Reemplace la clave y el nombre del agente. El nombre es el del código de integración (data-agent), y el identificador del agente tal como aparece en la dirección de la consola (/agents/…) también se acepta. La API responde con la versión PUBLICADA del agente: un agente nunca publicado devuelve 404.
curl -X POST https://dalevoz.ai/api/v1/interact \
-H "Authorization: Bearer SU_CLAVE_DE_SERVIDOR" \
-H "Content-Type: application/json" \
-d '{
"agent": "mi-agente",
"sessionId": null,
"user": { "id": "client-42", "locale": "es" },
"action": { "type": "text", "payload": { "message": "Hola, ¿cuál es su horario?" } }
}'const response = await fetch("https://dalevoz.ai/api/v1/interact", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.DALEVOZ_SERVER_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
agent: "mi-agente",
sessionId: null, // null en el primer mensaje
user: { id: "client-42", locale: "es" },
action: { type: "text", payload: { message: "Hola, ¿cuál es su horario?" } },
}),
});
const data = await response.json();
if (!response.ok) throw new Error(data.error);
// Para reenviar en el siguiente turno y seguir la misma conversación
const sessionId = data.sessionId;
for (const trace of data.traces) {
if (trace.type === "text") console.log(trace.payload.message);
}import os
import requests
response = requests.post(
"https://dalevoz.ai/api/v1/interact",
headers={"Authorization": f"Bearer {os.environ['DALEVOZ_SERVER_KEY']}"},
json={
"agent": "mi-agente",
"sessionId": None, # None en el primer mensaje
"user": {"id": "client-42", "locale": "es"},
"action": {"type": "text", "payload": {"message": "Hola, ¿cuál es su horario?"}},
},
timeout=60,
)
data = response.json()
response.raise_for_status()
session_id = data["sessionId"] # para reenviar en el siguiente turno
for trace in data["traces"]:
if trace["type"] == "text":
print(trace["payload"]["message"])La respuesta:
{
"sessionId": "0b6f7c1e-5d3a-4f1b-9a57-2c8e4d1a9f30",
"traces": [
{ "type": "text", "payload": { "message": "Abrimos de martes a sábado, de 9 a 19 h.", "markdown": true } },
{ "type": "choice", "payload": { "buttons": [ { "label": "📅 Pedir cita", "value": "rdv" } ] } }
],
"usage": { "tokensIn": 2140, "tokensOut": 58, "costMicroUsd": 812 }
}sessionId: envíe null en el primer mensaje, luego reenvíe el de la respuesta para seguir la misma conversación. Un identificador desconocido o de otro espacio no da error: abre una conversación nueva, y la respuesta lleva el nuevo identificador.user.id: su identificador para esa persona. El mismo de un día a otro permite al agente reconocerla cuando su memoria está activada. Con una clave pk_, la memoria requiere además la firma de identidad (ver Identidad firmada). Nunca un secreto en este campo.usage: presente solo con una clave sk_. Una clave pk_ nunca lo recibe, ni en JSON ni en flujo.La descripción OpenAPI 3.1 de las mismas rutas se descarga aquí: /openapi.json.
https://dalevoz.ai. Cuerpo en JSON (Content-Type: application/json), salvo el dictado de voz, en multipart.Authorization: Bearer pk_… o Bearer sk_…. Solo la ruta theme acepta también la clave como parámetro (?key=).slug), dentro del espacio de la clave. Solo interact acepta también su identificador (UUID).{ "error": "…" }, a veces completado con issues (detalle de validación), code y detail. En las rutas que el widget muestra al visitante (interact, messages, history, attachments, voice), error es una frase para el visitante, en su idioma: para un programa, lea el estado HTTP y code.Rechazo de origen de una clave pk_ (estado 403):
{
"error": "(frase neutra para el visitante, en su idioma)",
"code": "origine_non_autorisee",
"detail": "Origine non autorisée pour cette clé (boutique.exemple.fr). Ajoutez ce domaine à la clé dans la console."
}Las rutas site/* devuelven este rechazo en una forma más corta, sin code: { "error": "Origine non autorisee pour cette cle" }.
Claves: pk_ (origen verificado) o sk_
Hace avanzar una conversación un turno. Es la ruta del widget, de las aplicaciones y de los servidores.
| Encabezado | Función |
|---|---|
Authorization | Bearer pk_… o sk_…, obligatorio. |
x-dalevoz-channel | Opcional. El canal, para las estadísticas: widget, iframe, sdk_js, ios, android, api, zendesk, playground, whatsapp, messenger, instagram, voice. Prima sobre channel del cuerpo. Sin él: widget para una pk_, api para una sk_. |
x-dalevoz-identity | Opcional. El token de identidad firmado, ver Identidad firmada. |
| Campo del cuerpo | Tipo | Función |
|---|---|---|
agent | string | Obligatorio. Nombre técnico o identificador del agente. |
sessionId | uuid | null | null en el primer turno, luego el de la respuesta. Desconocido: se abre una conversación nueva, sin error. |
action | object | Obligatorio. Ver la tabla siguiente. |
user | { id?, name?, locale? } | Quién habla, declarado por usted. locale elige el idioma de los mensajes de servicio. Nunca un secreto aquí. |
context | object | Contexto libre, FIJADO al crear la conversación (procedencia, versión de aplicación…). context.segment elige un segmento del agente. |
contexte | object | Lo que la página sabe del visitante, FUSIONADO en cada turno. Solo pasan las variables declaradas en el agente (pestaña Contexto): una clave no declarada se ignora, un texto se trunca. |
stream | boolean | true: respuesta en flujo text/event-stream (ver más abajo). |
consentement | fecha ISO | Cuándo aceptó el visitante el aviso de consentimiento del widget. Se guarda una vez en la conversación, la devuelve la exportación RGPD. Una fecha futura o de más de 400 días se sustituye por la hora del servidor. El widget la envía solo. |
| action.type | payload | Cuándo |
|---|---|---|
launch | {} | Abrir o retomar una conversación: el agente dice su bienvenida. |
text | { message, attachments?, parle? } | Un mensaje (8 000 caracteres como máximo, vacío permitido si hay adjuntos). attachments: 5 como máximo. parle: true si el mensaje es la transcripción de algo dicho; la respuesta se redacta entonces para leerse en voz alta. |
choice | { value, label? } | El clic en un botón: reenvíe el value del botón, y su label para el historial. |
event | { name, data? } | Un evento de la superficie. El widget lo usa para window.dalevoz.evenement (name « dv:evenement »). |
Un adjunto es una de las dos formas siguientes:
{ kind: "image", mediaType, data, filename? }: mediaType image/png, image/jpeg, image/webp o image/gif; data en base64 SIN el prefijo data:. La imagen va tal cual al modelo.{ kind: "text", filename, text, truncated? }: el texto de un PDF o un DOCX, extraído antes por /api/v1/attachments.Los adjuntos solo se leen si el agente los acepta (ajuste del agente); el tema público lo indica en attachmentsEnabled.
Respuesta (200). { sessionId, traces[], usage?, avertissements? }. Las trazas se muestran en orden. Su tipo:
| type | Contenido |
|---|---|
| text | payload.message (Markdown si payload.markdown es true). |
| choice | payload.buttons[]: { label, value, url? }. Con url, el botón abre el enlace en lugar de enviar value. |
| multi_choice | Varios botones para marcar (min, max, validateLabel). |
| slider | Un control deslizante (label, min, max, step, value?, unit, validateLabel). |
| card | Una ficha: title, description?, imageUrl?, buttons?… |
| carousel | payload.cards[]: varias fichas. |
| document | Un archivo para abrir: url, filename, caption?. |
| audio | Una nota de voz: url, transcript, seconds?, mime. |
| scheduler | Una agenda para integrar: url, label, height. |
| template | Una plantilla de mensaje WhatsApp (canales Meta). |
| handoff | El agente pasa a un humano: reason?, message?. |
| systeme | Un cambio de interlocutor: etat (attente, repris, pause, absent) y message. |
| end | La conversación ha terminado. |
Flujo (stream: true). La respuesta es un text/event-stream de líneas « data: {json} ». Orden: session (el identificador, antes que todo), meta (streaming: true si el texto llega de verdad palabra por palabra), varios delta (texto provisional para mostrar), varios tool (una categoría: recherche, web, cartes, action o vocal, nunca el nombre de la herramienta) y por último final, cuyo response es IDÉNTICO a la respuesta JSON: reemplace el texto provisional por final.response.traces. Una vez abierto el flujo, el estado HTTP es 200: un error llega como evento error { message, status? }.
curl -N -X POST https://dalevoz.ai/api/v1/interact \
-H "Authorization: Bearer SU_CLAVE_DE_SERVIDOR" \
-H "Content-Type: application/json" \
-d '{ "agent": "mi-agente", "sessionId": null,
"action": { "type": "text", "payload": { "message": "Hola" } },
"stream": true }'
data: {"type":"session","sessionId":"0b6f7c1e-5d3a-4f1b-9a57-2c8e4d1a9f30"}
data: {"type":"meta","streaming":true}
data: {"type":"delta","text":"¡Hola! "}
data: {"type":"tool","kind":"recherche","phase":"start"}
data: {"type":"tool","kind":"recherche","phase":"done"}
data: {"type":"delta","text":"Abrimos…"}
data: {"type":"final","response":{"sessionId":"0b6f7c1e-…","traces":[…]}}Errores.
| Estado | Causa |
|---|---|
| 400 | Cuerpo JSON inválido, o solicitud inválida (issues lo detalla). |
| 401 | Clave ausente, inválida o revocada; token de identidad rechazado; clave que exige identidad firmada y recibe user.id. |
| 403 | Clave pk_ llamada desde un dominio que no está en su lista. |
| 404 | Agente desconocido, o nunca publicado. |
| 423 | Agente en pausa. |
| 429 | Demasiadas llamadas: tope de la clave o del visitante (ver Límites). error es una frase para el visitante, code vale limite, reessayerDansS y el encabezado Retry-After dicen cuándo reintentar. |
| 500 | Error inesperado (mensaje para el visitante, en su idioma). |
| 502 | El modelo cortó su respuesta sin resultado (flujo). |
Claves: pk_ (origen verificado) o sk_
Lo que un asesor humano escribió desde la última llamada, para mostrarlo en su superficie mientras tiene el control. Consultar cada pocos segundos, reenviando cursor tal cual en since.
{
"status": "human",
"messages": [ { "id": "…", "at": "2026-09-23T10:12:04.512Z", "from": "human_agent", "agentName": "Julie", "text": "…" } ],
"events": [ { "id": "…", "at": "…", "etat": "repris", "message": "…" } ],
"questions": [ { "id": "…", "at": "…", "traces": [ { "type": "text", … }, { "type": "choice", … } ] } ],
"cursor": "2026-09-23T10:12:04.513Z"
}let cursor = "";
setInterval(async () => {
const url = new URL("https://dalevoz.ai/api/v1/messages");
url.searchParams.set("sessionId", sessionId);
if (cursor) url.searchParams.set("since", cursor);
const r = await fetch(url, { headers: { Authorization: `Bearer ${key}` } }).then((x) => x.json());
for (const m of r.messages) showTeamMemberMessage(m.agentName, m.text); // deduplicar por m.id
cursor = r.cursor ?? cursor;
}, 4000);Claves: pk_ (origen verificado) o sk_
El hilo de una conversación, para volver a mostrarlo cuando la persona regresa. Devuelve { items: [ { from: "user" | "bot" | "human", agentName?, traces[] } ] }, 60 elementos como máximo, los más recientes. Los botones solo se devuelven en el último elemento; las señales (handoff, end) no se repiten. Sesión desconocida, de otro espacio o mal formada: items vacío, nunca un error. Una clave ausente o inválida devuelve 401.
Claves: pk_ (origen verificado) o sk_
Extrae el texto de un PDF o de un DOCX. Cuerpo: { mediaType, data, filename? }, con mediaType application/pdf o application/vnd.openxmlformats-officedocument.wordprocessingml.document, data en base64 (15 000 000 caracteres como máximo, unos 11 MB de archivo). Respuesta: { filename, text, truncated }, con el texto cortado a 20 000 caracteres. Errores: 400 (tipo no admitido, archivo ausente o demasiado pesado), 401, 403, 422 (extracción imposible). Las imágenes no pasan por aquí: van directamente en interact.
// 1. Extraer el texto del PDF
const extracted = await fetch("https://dalevoz.ai/api/v1/attachments", {
method: "POST",
headers: { Authorization: `Bearer ${key}`, "Content-Type": "application/json" },
body: JSON.stringify({ mediaType: "application/pdf", data: base64NoPrefix, filename: "presupuesto.pdf" }),
}).then((r) => r.json());
// 2. Enviarlo con el mensaje
await fetch("https://dalevoz.ai/api/v1/interact", {
method: "POST",
headers: { Authorization: `Bearer ${key}`, "Content-Type": "application/json" },
body: JSON.stringify({
agent: "mi-agente",
sessionId,
action: {
type: "text",
payload: {
message: "¿Puede revisar este presupuesto?",
attachments: [{ kind: "text", filename: extracted.filename, text: extracted.text, truncated: extracted.truncated }],
},
},
}),
});Las rutas del « pulsar para hablar » del widget. Usan la cadena de voz configurada en el agente publicado.
Clave: solo pk_ (una sk_ recibe 401)
Transcribe un turno hablado. Cuerpo multipart: agent, audio (el archivo), dureeMs?, locale?. Respuesta: { texte, langue, secondes }, o { texte: "", vide: true } cuando no se oyó nada. Límites: 8 MB, 120 segundos, 20 llamadas por minuto y por espacio. Errores: 400, 401, 403, 404 (agente no encontrado o no publicado), 413 (audio demasiado pesado o largo), 429, 503 (escucha no configurada).
Clave: solo pk_ (una sk_ recibe 401)
Lee un texto en voz alta con la voz del agente. Cuerpo: { agent, texte, conversationId?, locale? }. Respuesta: los bytes de audio (Content-Type dado por el proveedor). El texto se corta a 1 200 caracteres. 30 llamadas por minuto y por espacio. Errores: 400, 401, 403, 404, 429, 503 (lectura no configurada).
Sin clave: dirección pública
El audio de una nota de voz del agente, la dirección que lleva una traza audio. Pública porque una etiqueta audio y los servidores de Meta no saben poner encabezados. La nota caduca a los treinta días; la caché es privada, una hora.
Claves: pk_ o sk_, en encabezado o en ?key=
El tema público de la versión publicada de un agente, ya resuelto. Respuesta: { resolved, agentName, title, textIdleMs, attachmentsEnabled, voiceMode, pttSilenceMs, conformite, credit }. Sin control de origen. Caché pública (60 s, 300 s en el CDN). Errores: 401 (clave o agente ausente), 404.
Sin clave: dirección pública
Una imagen de la biblioteca de un espacio (avatar, fondo del widget). Caché inmutable de un año; 404 not_found si no.
Escribir un agente y su base, leer sus resultados, desde su servidor. Cada escritura queda en el diario del agente, con el motivo que usted indique.
Clave: solo sk_ (una pk_ recibe 403)
Crea el agente, o lo reescribe si ya existe un agente con ese slug en el espacio. Respuesta: { slug, cree, id }.
| Campo | Regla |
|---|---|
| slug | Obligatorio. 2 a 60 caracteres: minúsculas, cifras, guiones, empezando por letra o cifra. |
| name | Obligatorio, 120 caracteres como máximo. |
| systemPrompt | Obligatorio, 60 000 caracteres como máximo. |
| llmProvider | anthropic | openai | grok | gemini |
| llmModel | Rechazado (400) en la oferta gratuita si no está entre los modelos de 1 crédito o menos; se controla solo cuando cambia. |
| localeDefault | 2 a 5 caracteres (fr, es…). |
| status | draft | live | paused |
| maxTokens | 256 a 32 000. Ausente, se vuelve a 4 096, incluso al reescribir. |
| greetingByLocale | Bienvenida por idioma. Si lleva botones, debe terminar con una pregunta cerrada. |
| launchButtonsByLocale | Botones de apertura por idioma: 2 a 5, cada uno empieza con UN emoji, 20 caracteres como máximo. |
| settings | Fusionado en los ajustes existentes, nunca reemplazado. |
| motif | Por qué esta escritura, 500 caracteres como máximo. Queda en el diario. |
{
"slug": "recepcion-tienda",
"name": "Recepción de la tienda",
"systemPrompt": "Eres el asistente de la tienda…",
"localeDefault": "es",
"status": "draft",
"greetingByLocale": { "es": "¡Hola! ¿Empezamos?" },
"launchButtonsByLocale": { "es": [ { "label": "🛍️ Productos" }, { "label": "🚚 Envíos" } ] },
"motif": "Creación desde nuestro back-office"
}name y systemPrompt se exigen en cada llamada, incluso al reescribir. Errores: 400 (validación, regla de forma de la bienvenida o de los botones, modelo fuera de la oferta), 401, 403 (pk_), 500.
Clave: solo sk_ (una pk_ recibe 403)
Un segmento adapta un agente a un público (una organización, una campaña) sin duplicarlo. Se elige en ejecución con context.segment en interact, o con el atributo data-segment del widget; sin segmento reconocido, se aplica el segmento default y luego el agente tal cual.
GET ?agent=: la lista, sin el contenido de los prompts: { agent, segments: [ { segment, champs, promptFragmentLongueur, systemPromptLongueur } ] }.POST { agent, segment, config, autoriserDefault?, autoriserVocal? }: crea o reemplaza. Respuesta { agent, segment, champs }.DELETE ?agent=&segment=: elimina. Respuesta { agent, segment, supprime: true }.Campos de config (cualquier otro campo devuelve 400): collections, carousels, carouselsDisabled, tools, promptFragment (añadido al prompt, 20 000 car.), systemPrompt (reemplaza el prompt, 20 000 car.), greeting, launchButtons (6 como máximo), welcomeVideoUrl, welcomeVoiceUrl.
Clave: solo sk_ (una pk_ recibe 403)
Sincroniza filas en la base de conocimiento: una fila se vuelve una ficha. Cuerpo: { agent, collection?, rows[], motif? }, rows de 1 a 2 000 elementos { name, text, sourceUrl? }.
{
"agent": "recepcion-tienda",
"collection": "catalogo",
"rows": [
{ "name": "Jarrón Oliva, 24 cm", "text": "Gres esmaltado, 39 €, en stock.", "sourceUrl": "https://ejemplo.com/vase-olive" }
],
"motif": "Sincronización nocturna del catálogo"
}Clave: solo sk_ (una pk_ recibe 403)
Relee las fichas de un agente, o de un solo lote: { agent, collection, count, rows: [ { name, sourceUrl, text } ] }. Llamar antes de un sync-table parcial: lea, reemplace lo que su fuente posee, reenvíe todo.
Clave: solo sk_ (una pk_ recibe 403)
Los resultados de un agente en un periodo. Parámetros:
| Parámetro | Función |
|---|---|
| agent | Obligatorio (slug). |
| days | 1 a 90, 7 por defecto, contado desde ahora. |
| from, to | Fechas ISO; una ventana de calendario que prima sobre days. from debe preceder a to. |
| channels | Canales a conservar, separados por comas. |
| excludePrefix | Prefijos de identificador de visitante a descartar (sus cuentas de prueba), separados por comas. |
Respuesta: agent, periode, tronque, totaux, fichesOuvertes, questionsSansFiche, demandes, rendezVous, pagesOrigine, satisfaction, sansIssue, ventes?, langues, canaux, joursActivite, heuresActivite, conversations. Errores: 400 (agente ausente, fecha inválida), 401, 403, 404.
Clave: solo sk_ (una pk_ recibe 403)
La exportación bruta de las conversaciones de un agente, turnos incluidos, tal como están en la base. from y to son obligatorios; channels y excludePrefix como arriba; limit de 1 a 200 (100 por defecto); cursor para la página siguiente.
{
"agent": "recepcion-tienda",
"periode": { "from": "2026-09-01T00:00:00.000Z", "to": "2026-09-08T00:00:00.000Z" },
"conversations": [
{ "id": "…", "createdAt": "…", "updatedAt": "…", "channel": "widget", "status": "…", "locale": "fr",
"externalUserId": "client-42", "issue": "…", "satisfaction": "…", "sujet": "…", "classifieAt": "…",
"turns": [ { "role": "user", "content": { … }, "createdAt": "…" } ] }
],
"nextCursor": "2026-09-03T17:42:10.118Z"
}Mientras nextCursor no sea null, vuelva a pasarlo en cursor con los mismos from y to. Errores: 400, 401, 403, 404.
Tres rutas pensadas para las páginas de aterrizaje: el visitante da la dirección de su sitio, el agente la lee, y luego la conversación puede seguir en WhatsApp. Solo tienen sentido en un agente con la lectura de sitio activada.
Claves: pk_ (origen verificado) o sk_
Cuerpo: { agent, url, locale?, segment?, contexte? }. Verifica en pocos segundos que el sitio responde, crea la conversación y devuelve { sessionId, statut: "encours", url }; la lectura (8 páginas como máximo) continúa después de la respuesta. Seis lecturas por hora y por dirección IP. Errores: 400 (adresse-invalide), 401, 403 (origen, o lecture-desactivee en el agente), 404 (agent-inconnu), 422 (site-injoignable), 429 (trop-de-lectures).
Claves: pk_ (origen verificado) o sk_
Consultar durante la lectura: { statut, url?, pages?, titre?, message? }, con statut aucune, encours, pret o echec. Una lectura en curso desde hace más de dos minutos se devuelve como echec. Errores: 400, 401, 403, 404 (session-inconnue).
Claves: pk_ (origen verificado) o sk_
Cuerpo: { sessionId, telephone }. El agente escribe primero por WhatsApp, conociendo ya el sitio leído. Hace falta un canal WhatsApp activo en el agente; el mensaje sale por una plantilla aprobada por Meta, en francés. Un número sin prefijo se lee como francés. Un solo envío por conversación, tres por hora y por dirección IP. Respuesta: { ok: true, waId } o { ok: true, deja: true }. Errores: 400 (numero-invalide), 401, 403, 404 (session-inconnue), 409 (site-non-lu), 429 (trop-d-envois), 502 (envoi-refuse), 503 (canal-absent, canal-sans-jeton).
Para responder a una solicitud de acceso o de supresión desde su servidor. El visitante se designa por su identificador: el user.id que usted envía, el sub del token firmado, el identificador pasado a dalevoz.identify(), o el número de WhatsApp. Todo se limita al espacio de la clave: dos espacios con su propio « client-42 » nunca se ven. ?agent= (nombre técnico o UUID) limita a un agente; sin él, todo el espacio. Codifique el identificador para una URL (encodeURIComponent).
Clave: solo sk_ (una pk_ recibe 403)
Todo lo que DaleVoz guarda de la persona, en un JSON: sus conversaciones con sus turnos (incluidos los mensajes retirados del hilo por un asesor, marcados deletedAt), la fecha de consentimiento de cada una (consentAt), su ficha de memoria, sus leads, sus citas y sus pedidos. Un visitante desconocido devuelve listas vacías, no un 404. Errores: 400 (visiteur_invalide), 401, 403 (clave pk_, o alcance visiteurs:gdpr ausente de la clave), 404 (agent_introuvable).
curl "https://dalevoz.ai/api/v1/visiteurs/client-42/export" \
-H "Authorization: Bearer SU_CLAVE_DE_SERVIDOR"
{ "userId": "client-42", "agent": null, "exportedAt": "…",
"conversations": [ { "id": "…", "agent": "recepcion-tienda", "channel": "widget",
"consentAt": "2026-09-24T10:12:03.000Z", "turns": [ { "role": "user", "content": { … }, "createdAt": "…" } ] } ],
"memories": [ { "agent": "recepcion-tienda", "summary": "…" } ],
"leads": [], "bookings": [], "orders": [] }Clave: solo sk_ (una pk_ recibe 403)
Irreversible. Borra las conversaciones (y sus turnos, leads y notas de voz), la ficha de memoria, los leads que llevan el identificador y los comentarios de Instagram vinculados. Las citas y los pedidos son piezas de su comercio: se quedan, sin nombre, correo, teléfono ni texto libre. Los costes y las ventas siguen contados, separados de la persona. Respuesta 200 con los contadores, incluso a cero: una supresión pedida dos veces no es un error. Mismos errores que la exportación.
curl -X DELETE "https://dalevoz.ai/api/v1/visiteurs/client-42" \
-H "Authorization: Bearer SU_CLAVE_DE_SERVIDOR"
{ "userId": "client-42", "agent": null,
"deleted": { "conversations": 3, "memories": 1, "leads": 1, "instagramComments": 0 },
"anonymized": { "bookings": 1, "orders": 0 } }Por defecto, quien habla con el agente se declara a sí mismo en user.id. Con una clave pk_, pública por naturaleza, cualquiera podría poner el identificador de otro y recuperar su conversación y lo que el agente recuerda de él. La identidad firmada cierra esa puerta: su servidor firma un token corto para el usuario que conoce, y DaleVoz verifica la firma.
x-dalevoz-identity de cada llamada a interact, junto a la clave: la clave dice qué aplicación llama, el token dice qué persona. Un token válido REEMPLAZA el user del cuerpo.| Elemento del token | Regla |
|---|---|
| Algoritmo | Solo HS256 (encabezado alg). Cualquier otro, none incluido, se rechaza. |
sub | Obligatorio. El identificador estable de la persona en su sistema, 200 caracteres como máximo. Se vuelve user.id. |
exp | Obligatorio. Como máximo 15 minutos después de iat cuando iat está presente. Cinco minutos bastan. |
iat, nbf | Opcionales. Se tolera un desfase de reloj de 60 segundos. |
name, locale | Opcionales. Se vuelven user.name y user.locale. |
| Tamaño | 4 096 caracteres como máximo. |
import { createHmac } from "node:crypto";
const b64url = (obj) => Buffer.from(JSON.stringify(obj)).toString("base64url");
// En SU servidor, para el usuario ya conectado en su sistema.
export function daleVozToken(user) {
const now = Math.floor(Date.now() / 1000);
const header = b64url({ alg: "HS256", typ: "JWT" });
const payload = b64url({
sub: user.id, // se vuelve user.id
name: user.name, // opcional, se vuelve user.name
locale: "es", // opcional, se vuelve user.locale
iat: now,
exp: now + 5 * 60, // obligatorio, 15 minutos como máximo
});
const signature = createHmac("sha256", process.env.DALEVOZ_IDENTITY_SECRET) // dvid_…
.update(`${header}.${payload}`)
.digest("base64url");
return `${header}.${payload}.${signature}`;
}
// Mismo resultado con la biblioteca jsonwebtoken:
// jwt.sign({ sub: user.id, name: user.name }, process.env.DALEVOZ_IDENTITY_SECRET,
// { algorithm: "HS256", expiresIn: "5m" });await fetch("https://dalevoz.ai/api/v1/interact", {
method: "POST",
headers: {
Authorization: "Bearer pk_…",
"x-dalevoz-identity": token, // entregado por su servidor
"Content-Type": "application/json",
},
body: JSON.stringify({
agent: "mi-agente",
sessionId,
// sin user.id: lo lleva el token
action: { type: "text", payload: { message } },
}),
});Rechazos posibles, todos en 401: token mal formado, algoritmo rechazado, firma inválida, token caducado o de vida demasiado larga, todavía no válido, sin sub utilizable, demasiado largo; clave sin secreto que recibe un token; clave con secreto que recibe user.id sin token. Un token inválido NUNCA se sustituye por el user.id del cuerpo.
Una etiqueta para pegar antes del final del body. El widget vive en un shadow DOM: su estilo no toca su página, y el suyo no lo toca. La etiqueta lista, clave incluida, se copia en la consola (pestaña « Publicar » del agente, tarjeta « Sitio web »).
<script src="https://dalevoz.ai/dalevoz-widget.js"
data-agent="mi-agente"
data-key="pk_…"
defer></script>El widget llama a la API en la dirección desde la que se carga. Guarda la conversación en el almacenamiento local del navegador: menos de 24 horas de inactividad y la persona recupera su hilo, más allá se abre una nueva conversación. También asigna un identificador de visitante estable por navegador, salvo que usted dé uno (data-uid o dalevoz.identify).
| Atributo | Función |
|---|---|
data-agent | Obligatorio. El nombre técnico del agente. |
data-key | Obligatorio. La clave pk_ del espacio. |
data-mode | widget (burbuja flotante, por defecto), embed (dentro de su página, siempre abierto) o popover (ventana centrada). |
data-target | En modo embed: el selector CSS del contenedor (si no, el body). |
data-locale | Fuerza el idioma. Si no, el del navegador (dos letras). |
data-title | Reemplaza el título del panel configurado en la consola. |
data-accent | Reemplaza el color de acento configurado en la consola (color CSS). |
data-uid | El identificador del visitante, cuando su sitio lo conoce (usuario conectado). Se vuelve user.id, y cada identificador tiene su propio hilo en un mismo navegador. 120 caracteres como máximo. Sigue siendo declarativo: sin token firmado, el agente no lee ni escribe ficha de memoria para este visitante (ver dalevoz.identify y la identidad firmada). |
data-contexte | Un objeto JSON pasado a dalevoz.contexte() al cargar, sin una línea de JavaScript. |
data-segment | El segmento del agente a aplicar (ver la ruta segments), 60 caracteres como máximo. |
data-vars | Un objeto JSON guardado en el contexto de la conversación al crearla (context.vars). |
data-session | Un identificador de conversación (UUID) a retomar, por ejemplo el devuelto por site/lire. |
data-reset | off quita el botón « nueva conversación » del encabezado. |
data-close | off quita la cruz de cierre (útil en una WebView de aplicación). |
data-host | La dirección de la API, si difiere de la del script. |
data-attribution | Vincula un pedido de su tienda a la conversación que lo originó. Ausente por defecto: no se añade nada. lien (recomendado): los enlaces abiertos desde el hilo hacia su propio sitio reciben dv=<identificador de conversación>, los demás parámetros (UTM) y el ancla quedan intactos, y no se deposita ninguna cookie; su tienda guarda el valor en su sesión y lo copia en el pedido. on: el widget deposita la cookie dv_conv (30 días, solo el identificador), a declarar en su banner de consentimiento. |
data-canal y data-plein los pone la página de integración en iframe de DaleVoz; no necesita escribirlos. data-greeting se lee pero no tiene efecto: la bienvenida se configura en el agente.
Los dos nombres designan el mismo objeto. Cada método se llama directamente (dalevoz.open()) o por la función (DaleVoz("open")), la forma del fragmento con cola de espera de abajo. Los nombres franceses de origen siguen siendo válidos.
| Función | Qué hace |
|---|---|
identify(objet) · identifier | Dice quién es el visitante. userId se vuelve user.id (200 caracteres como máximo) y cada persona recupera SU hilo en un mismo navegador; name se vuelve user.name; token (el token firmado por su servidor, o una función que lo devuelve) va en el encabezado x-dalevoz-identity y reemplaza user.id. Cualquier otro campo (email, oferta…) pasa por contexte(). Llamar antes de la apertura; llamado después, se deja el hilo del visitante anterior. identify(null) vuelve al visitante anónimo. |
open() · ouvrir() | Abre el panel. |
close() · fermer() | Cierra el panel (sin efecto en modo embed). La conversación sigue al reabrir. |
toggle() · basculer() | Abre si está cerrado, cierra si está abierto. |
on(nom, fonction) · off(nom, fonction?) | Escucha un evento del widget (tabla siguiente). off sin función quita todos los listeners de ese nombre. Un on("ready") puesto después de la carga se llama de inmediato. |
contexte(objet) | Declara lo que la página sabe del visitante. Se fusiona con lo existente (una clave ausente se queda, null borra), y sale con el próximo mensaje: nada se transmite mientras no exista una conversación. Solo las variables declaradas en el agente (pestaña « Contexto ») le llegan. Idempotente: se puede llamar en cada renderizado. |
evenement(nom, donnees?) | Señala un instante (carrito abandonado, etapa superada). El agente solo reacciona a los eventos declarados en él, y es la configuración del agente la que decide si habla. Con el panel cerrado, su respuesta aparece como burbuja junto al lanzador; el panel nunca se abre solo. Silencioso si el visitante eligió « No me interrumpa más » o durante una llamada de voz. |
consentement() | Devuelve { requis, accepteLe }: ¿está activado el aviso de consentimiento en el agente, y cuándo lo aceptó este navegador (fecha ISO o null)? |
<!-- Antes de la etiqueta del widget: las llamadas hechas antes de su carga se ponen en cola y luego se repiten. -->
<script>
window.DaleVoz = window.DaleVoz || function () {
(window.DaleVoz.q = window.DaleVoz.q || []).push(arguments);
};
// Utilizable de inmediato, aunque el script aún no esté cargado:
DaleVoz("identify", { userId: "client-42", name: "Alexis" });
DaleVoz("on", "message", function (m) { console.log(m.role, m.text); });
</script>// Una vez cargado, window.DaleVoz y window.dalevoz son el mismo objeto.
dalevoz.open();
dalevoz.close();
dalevoz.toggle();
// Lo que la página sabe del visitante. Se fusiona; null borra una clave.
dalevoz.contexte({ plan: "pro", cart_total: 129.9, page: "checkout" });
// Un instante que puede hacer reaccionar al agente, si está declarado en el agente.
dalevoz.evenement("cart_abandoned", { cart_total: 129.9 });
dalevoz.on("message", (m) => {
// m.role : "user" | "assistant" | "human_agent" ; m.text ; m.sessionId
if (m.role === "assistant") analytics.track("agent_reply");
});
dalevoz.on("open", () => console.log("panel abierto"));Visitante conectado. Sin token, el identificador sigue siendo declarativo: la conversación funciona, pero el agente no lee ni escribe la ficha de memoria de este visitante. Con un token, es él quien prueba quién habla; una clave que exige la identidad firmada rechaza entonces a todo visitante no identificado. Prefiera una FUNCIÓN de token: un token vive 15 minutos como máximo, una conversación más. Identidad firmada
// Usuario conectado en SU sitio. El token lo firma SU servidor (ver Identidad firmada).
dalevoz.identify({
userId: "client-42",
name: "Alexis Martin",
email: "alexis@ejemplo.com", // pasa por contexte(): declare la variable email en el agente
// Una función se vuelve a llamar antes de cada vencimiento del token (15 minutos como máximo):
token: () => fetch("/api/dalevoz-token").then((r) => r.text()),
});
// Cierre de sesión: vuelta al visitante anónimo de este navegador.
dalevoz.identify(null);Cada evento se recibe por dalevoz.on(nombre, función). Los cinco últimos salen también en window como CustomEvent, con el mismo contenido en event.detail.
| on(…) | En window | Cuándo, y qué lleva |
|---|---|---|
ready | dalevoz:ready | El widget está montado. En window, se emite al final de la carga del script, y una segunda vez (desde el elemento del widget, subiendo) cuando se aplica su tema: un listener de window debe soportar dos llamadas. on("ready") se llama una sola vez. |
message | dalevoz:message | Un mensaje del hilo: { role, text, sessionId }, con role user (el visitante, texto escrito, dictado o botón pulsado), assistant (el agente) o human_agent (un asesor, con agentName). Los mensajes releídos al retomar un hilo no se vuelven a emitir. Las llamadas de voz en tiempo real no pasan por aquí. |
open · close | dalevoz:open · dalevoz:close | Al abrir y cerrar el panel, solo cuando el estado cambia. |
consent | dalevoz:consent | El visitante acaba de aceptar el aviso: { acceptedAt }. |
identify | dalevoz:identify | Después de identify(): { userId, signed }. |
| - | dalevoz:panneau | Histórico: en cada apertura o cierre, con event.detail.ouvert (boolean). |
Una herramienta HTTP es una acción que el agente dispara por sí mismo: enviar una solicitud de llamada a su CRM, crear un ticket, reservar un horario. Se crea en la página del agente, pestaña « Acciones », o con una IA conectada por MCP. Se le da un nombre, una frase que dice CUÁNDO usarla, la dirección pública que recibe, el método (POST por defecto, PUT o GET), los datos a recoger (un asterisco los vuelve obligatorios: telephone*) y encabezados.
Los datos recogidos van en un cuerpo JSON, o como parámetros de la dirección para un GET. Una modificación afecta a la versión de trabajo: nada está en línea antes de publicar el agente.
Una clave de API nunca se escribe en claro en una herramienta. Se guarda en la bóveda del espacio: consola, Ajustes, pestaña « ChatGPT y Claude », « Para un desarrollador: bóveda de secretos ». El encabezado de la herramienta la cita luego por su nombre:
Authorization: Bearer {{secret:CRM_API_KEY}}
X-Api-Key: {{secret:AGENDA_CLE}}CLAVE_CRM). Valor: 4 000 caracteres como máximo. 50 secretos por espacio.{{env:TOOL_SECRET_NOM}} se sigue entendiendo: lee el secreto NOM de la misma bóveda, nunca una variable del servidor.DaleVoz llama a su servidor (POST, JSON) cuando algo pasa en una conversación, en lugar de que usted venga a preguntarlo. Una suscripción se crea en la consola, Ajustes, pestaña « ChatGPT y Claude », « Para un desarrollador: webhooks »: una dirección en https, los eventos a recibir, todos los agentes o uno solo. Su secreto, whsec_…, se muestra una sola vez; « Enviar una prueba » envía un test.ping, y el registro guarda 30 días de entregas.
| Encabezado | Contenido |
|---|---|
Dale-Voz-Signature | t=<unix>,v1=<hex>: v1 es el HMAC-SHA256, en hexadecimal, de « <t>.<corps> » con su secreto. |
Dale-Voz-Event | El tipo del evento. |
Dale-Voz-Delivery | El identificador de la entrega, el mismo en cada reintento: guárdelo para procesar un evento una sola vez. |
El cuerpo, siempre el mismo sobre:
{
"id": "evt_…",
"type": "lead.qualifie",
"cree_le": "2026-09-24T10:12:04.000Z",
"espace": { "id": "…", "slug": "mi-tienda" },
"agent": { "id": "…", "slug": "recepcion-tienda" },
"donnees": {
"lead_id": "…",
"conversation_id": "…",
"canal": "widget",
"nouveau": true,
"nom": "Camille Martin",
"email": "camille@ejemplo.com",
"besoin": "Presupuesto para 40 personas"
}
}Un campo vacío se omite. Las conversaciones de « Probar », en la consola, no emiten nada.
| Evento | Cuándo | Campos de donnees |
|---|---|---|
conversation.demarree | Empieza una conversación. | conversation_id, canal, langue, contact_id, nom |
conversation.terminee | Una conversación se cierra y se clasifica. | conversation_id, canal, terminee_le, issue, resume, sujet, satisfaction, messages_visiteur, messages_agent, duree_s, humain_intervenu |
transfert.demande | El visitante pide un humano. | conversation_id, canal, contact_id, nom, raison |
lead.qualifie | Un contacto se crea o se completa (nouveau: true o false). | lead_id, conversation_id, canal, nouveau, nom, email, telephone, besoin, secteur, preference_contact |
rdv.pris | Se toma una cita. | rdv_id, conversation_id, canal, debut, fin, duree_min, fuseau, nom, email, telephone, mode, sujet, invitation_envoyee |
satisfaction.recue | El visitante da su opinión. | conversation_id, canal, source, note, commentaire, resume |
test.ping | Un envío de prueba, desde la consola. | message, abonnement_id |
mode vale appel, ecrit o visio; note vale satisfied, partial, need_detail o not_resolved.
import express from "express";
import { createHmac, timingSafeEqual } from "node:crypto";
const TOLERANCE_S = 5 * 60;
function signatureValide(corpsBrut, entete, secret) {
const champs = {};
for (const morceau of (entete ?? "").split(",")) {
const i = morceau.indexOf("=");
if (i > 0) champs[morceau.slice(0, i).trim()] = morceau.slice(i + 1).trim();
}
const t = Number(champs.t);
if (!Number.isInteger(t) || Math.abs(Date.now() / 1000 - t) > TOLERANCE_S) return false;
const attendue = createHmac("sha256", secret).update(`${t}.${corpsBrut}`).digest();
const recue = Buffer.from(champs.v1 ?? "", "hex");
return recue.length === attendue.length && timingSafeEqual(recue, attendue);
}
const app = express();
// El cuerpo BRUTO: la firma se calcula sobre los bytes recibidos, no sobre un JSON releído.
app.post("/webhooks/dale-voz", express.raw({ type: "application/json" }), (req, res) => {
const corps = req.body.toString("utf8");
if (!signatureValide(corps, req.get("Dale-Voz-Signature"), process.env.DALEVOZ_WEBHOOK_SECRET)) {
return res.status(400).end();
}
const livraison = req.get("Dale-Voz-Delivery");
if (dejaTraitee(livraison)) return res.status(200).end(); // un reintento
const evenement = JSON.parse(corps);
traiter(evenement.type, evenement.donnees);
marquerTraitee(livraison);
res.status(200).end();
});import hashlib
import hmac
import os
import time
from flask import Flask, request
TOLERANCE_S = 5 * 60
app = Flask(__name__)
def signature_valide(corps: bytes, entete: str, secret: str) -> bool:
champs = dict(m.split("=", 1) for m in (entete or "").split(",") if "=" in m)
try:
t = int(champs.get("t", ""))
except ValueError:
return False
if abs(time.time() - t) > TOLERANCE_S:
return False
attendue = hmac.new(secret.encode(), f"{t}.".encode() + corps, hashlib.sha256).hexdigest()
return hmac.compare_digest(attendue, champs.get("v1", ""))
@app.post("/webhooks/dale-voz")
def webhook_dale_voz():
corps = request.get_data() # el cuerpo bruto, en bytes
if not signature_valide(corps, request.headers.get("Dale-Voz-Signature", ""), os.environ["DALEVOZ_WEBHOOK_SECRET"]):
return "", 400
livraison = request.headers.get("Dale-Voz-Delivery")
if deja_traitee(livraison):
return "", 200
evenement = request.get_json()
traiter(evenement["type"], evenement["donnees"])
marquer_traitee(livraison)
return "", 200DaleVoz expone un servidor MCP remoto. Conectado a Claude, ChatGPT, Claude Code o Codex, deja que la IA cree y ajuste sus agentes conversando, con SUS permisos en el espacio que usted autoriza. Ninguna clave que pegar: la autorización se hace por OAuth, en una pantalla de DaleVoz donde usted elige el espacio.
https://dalevoz.ai/api/mcpEl paso a paso ilustrado, herramienta por herramienta, está en la consola: Conectar mi IA. Una autorización abre un solo espacio: una agencia agrega una conexión por cliente.
Claude (todos los planes, incluido el gratuito, con un solo conector personalizado en el plan gratuito; en Team o Enterprise, es el propietario de la organización quien lo agrega; en la web, la aplicación de escritorio o el teléfono): el enlace de abajo abre la ventana « Añadir conector personalizado », con el nombre y la dirección ya completados. Deje las opciones propuestas y haga clic en « Añadir » al final de la ventana, luego en « Conectar » en la página del conector, y autorice su espacio en la página de DaleVoz que se abre. Sin el enlace: claude.ai/customize/connectors, « Añadir conector personalizado », pegue la dirección. El enlace: agregar DaleVoz a Claude.
ChatGPT (plan Plus, Pro, Business o Enterprise/Edu; no funciona con el plan gratuito ni con Go; en Business o Enterprise, es el administrador del espacio de ChatGPT quien crea la aplicación). Solo en chatgpt.com, en el navegador de una computadora: las aplicaciones MCP no existen ni en la aplicación ni en el teléfono.
Si ChatGPT le pide activar el modo desarrollador antes de crear una aplicación MCP: « Configuración », barra « Buscar » arriba de la configuración, escriba « desarrollador », luego active « Modo de desarrollador ».
Claude Code : un comando, luego su navegador se abre para la autorización.
claude mcp add --transport http dale-voz https://dalevoz.ai/api/mcpCodex : la misma lógica, en dos comandos.
codex mcp add dale-voz --url https://dalevoz.ai/api/mcp
codex mcp login dale-voz2026-07-28, 2025-11-25, 2025-06-18.Para empezar, pegue este mensaje en una conversación nueva: su IA abre DaleVoz, le dice dónde está y lo guía paso a paso.
Empiezo con DaleVoz: lanza dalevoz_demarrer, dime en tres líneas dónde estoy y guíame paso a paso, una pregunta a la vez, sin tecnicismos.
dalevoz_documentation. Sin conector, todo cabe en una dirección: https://dalevoz.ai/llms-full.txt?lang=es.El número de herramientas visibles depende de su rol y de su oferta. En autoservicio, su IA ve lo esencial (crear, alimentar, probar, publicar, instalar, leer las conversaciones) y abre el resto cuando hace falta, sin volver a conectar nada. Cada escritura queda en el historial del agente, a su nombre.
En qué orden usarlas para construir un agente que funcione: el método.
| Dónde | Límite |
|---|---|
| interact | Mensaje: 8 000 caracteres. Adjuntos: 5 por mensaje. |
| attachments | 15 000 000 caracteres de base64 (unos 11 MB); texto extraído cortado a 20 000 caracteres. |
| messages | 50 elementos por llamada. |
| history | Los 60 últimos elementos. |
| voice/dictee | 8 MB, 120 segundos; 20 llamadas por minuto y por espacio. |
| voice/lecture | 1 200 caracteres leídos; 30 llamadas por minuto y por espacio. |
| site/lire | 6 lecturas por hora y por dirección IP; 8 páginas leídas. |
| site/pont-whatsapp | 3 envíos por hora y por dirección IP; uno solo por conversación. |
| kb/sync-table | 2 000 filas por envío. |
| analytics | 90 días como máximo con days. |
| conversations/export | 200 conversaciones por página. |
| agents | Prompt: 60 000 caracteres; maxTokens de 256 a 32 000. |
| segments | promptFragment y systemPrompt: 20 000 caracteres cada uno. |
| Identidad firmada | Token de 4 096 caracteres, 15 minutos de vida como máximo. |
| Bóveda de secretos | 50 secretos por espacio, 4 000 caracteres por valor. |
| /api/mcp | 240 llamadas por minuto y por cuenta (una persona en un espacio, o el espacio para una clave sk_); 3 000 por dirección IP, de las cuales 120 fallos de autenticación como máximo (429, con Retry-After: 60). |
Los límites de arriba por espacio o por dirección IP (dictado, lectura, lectura de sitio, puente WhatsApp, MCP) se cuentan en memoria por instancia de servidor: el tope realmente alcanzado puede ser un múltiplo del indicado, no lo tome como una cuota exacta.
Una clave pk_ vive en el HTML de su sitio: sin tope, quien la copie podría vaciar sus créditos. Cada ruta pública cuenta sus llamadas en ventanas fijas (minuto, hora, día), en base de datos, para la CLAVE (todos los visitantes juntos) y, solo detrás de una clave pk_, para el VISITANTE, reconocido por su dirección IP. Los umbrales están 10 a 20 veces por encima de los picos medidos en nuestros clientes: detienen un script, no un sitio. Más allá: 429, con code limite, portee (cle o visiteur), reessayerDansS y el encabezado Retry-After; error es una frase para el visitante, en su idioma, que el widget muestra una vez sin reintentar. Un espacio que lo necesite (una conferencia donde toda la sala habla con el agente desde el mismo Wi-Fi) puede ampliarse: escríbanos.
| Ruta | Por clave | Por visitante (pk_) |
|---|---|---|
| interact | 300 por minuto, 3 000 por hora, 20 000 por día | 40 por minuto, 600 por hora |
| attachments | 60 por minuto, 600 por hora, 3 000 por día | 10 por minuto, 60 por hora |
| voice/dictee, voice/lecture | 600 por hora, 4 000 por día (las dos juntas) | 20 por minuto, 200 por hora |
| site/lire | 60 por hora, 400 por día | - |
| site/pont-whatsapp | 30 por hora, 200 por día | - |
Estos topes se suman a los de la oferta del espacio (conversaciones por mes, turnos por conversación), que no responden con 429 sino con un 200 cuyo mensaje se lo dice al visitante (ver la ruta interact).
| Estado | Significado en la API |
|---|---|
| 200 | Éxito. También para un tope de oferta alcanzado en interact (el mensaje está en las trazas). |
| 400 | Cuerpo ilegible, campo inválido (issues), parámetro ausente, regla de forma no respetada. |
| 401 | Clave ausente, desconocida o revocada; token de identidad rechazado; tipo de clave incorrecto en las rutas voice. |
| 403 | Clave pk_ en una ruta reservada a sk_; origen no autorizado; lectura de sitio desactivada. |
| 404 | Agente, sesión o recurso no encontrado en el espacio de la clave; agente nunca publicado. |
| 409 | Lote de base de conocimiento sincronizado en otro lugar; sitio todavía no leído. |
| 413 | Audio demasiado pesado o largo. |
| 422 | Adjunto ilegible; sitio inaccesible. |
| 423 | Agente en pausa. |
| 429 | Demasiadas llamadas (ver las dos tablas de arriba). code vale limite para un tope por clave; Retry-After dice cuándo reintentar. |
| 500, 502, 503 | Error de servidor, respuesta del modelo interrumpida, voz o canal no configurados. |