Todo lo que hace la app, también por API.
392 endpoints REST sobre HTTPS, autenticados con una llave que tú generas y revocas. Webhooks firmados para enterarte de lo que pasa sin estar preguntando. Esta página es la guía completa: sirve para integrar desde PHP, C#, TypeScript, Python o lo que uses, porque no hay nada que no sea una petición HTTP con una cabecera.
Antes de empezar
Necesitas dos cosas: una cuenta de Kontesta y una API key. La llave se crea desde la app, en Ajustes → Llaves de API, y hace falta permiso de administrador. No se puede crear una llave usando otra llave — es a propósito: evita que una llave filtrada se multiplique sola.
Al crearla eliges qué permisos lleva (ver Permisos y scopes). El secreto completo se muestra una sola vez: en nuestra base solo queda su hash, así que si lo pierdes no hay forma de recuperarlo, solo de rotarlo.
| Concepto | Valor |
|---|---|
URL base | https://api.kontesta.app |
| OpenAPI | /integracion/openapi.json |
| Versión | Va en la ruta: todas las rutas empiezan con /v1 |
| Formato | JSON en petición y respuesta, UTF-8 |
| Llave | ktk_ + 8 caracteres de prefijo + . + el secreto |
No hay entorno de pruebas público
- Empieza con una llave que solo tenga permisos de lectura (los que terminan en
:read). Con ella cualquier endpoint que envía responde403: no hay forma de que mande un mensaje. - Para tu receptor de webhooks,
POST /v1/webhooks/{id}/pingte manda un eventotest.pingfirmado igual que los reales. - Un bot se prueba con
POST /v1/bots/{id}/simulate, que corre la entrada del cliente sin WhatsApp y sin efectos. - Cuando ya vayas a enviar, hazlo a una conversación con tu propio número.
Autenticación
Manda la llave en la cabecera X-Api-Key. Si tu cliente HTTP te complica las cabeceras personalizadas, también se acepta como Authorization: Bearer — el prefijo ktk_ nos deja distinguirla de un token de sesión.
X-Api-Key: ktk_a1b2c3d4.tu-secreto-aqui
# o bien
Authorization: Bearer ktk_a1b2c3d4.tu-secreto-aquiTrata la llave como una contraseña
Para cambiar una llave sin cortar el servicio existe la rotación: te devuelve una llave nueva y deja la vieja funcionando durante una ventana de gracia (24 horas por omisión, hasta 7 días, o 0 para cortar de inmediato). Despliegas la nueva, verificas y la vieja muere sola.
Tu primera llamada
Lista las conversaciones abiertas. Si esto responde 200, ya estás integrado: todo lo demás es cambiar la ruta y el cuerpo.
curl -s "https://api.kontesta.app/v1/conversations?status=open&limit=30" \
-H "X-Api-Key: $KONTESTA_API_KEY"Un 401 significa que la llave no llegó o no es válida. Un 403 significa que llegó bien pero le falta el permiso — no es lo mismo, y la diferencia te ahorra media hora de depuración.
Permisos y scopes
Cada llave lleva una lista de permisos con la forma recurso:verbo — conversations:read, messages:send, leads:write. Cada endpoint exige el suyo, y la llave debe traerlo o la respuesta es 403.
Todo lo que no se concede, se niega
La consecuencia práctica: dale a cada llave el mínimo que necesita. Una integración que solo publica leads desde tu sitio no necesita conversations:read, y si algún día se filtra, no leerá las conversaciones de nadie. Es más trabajo el primer día y menos daño el peor día.
Paginación, errores y límites
Paginación
Todo listado responde con la misma forma: items (el arreglo) y nextCursor. Se pagina por cursor, no por número de página: pides limit (1 a 100, 30 por omisión) y devuelves el nextCursor en el parámetro cursor para la siguiente página; cuando viene nulo se acabó. Es un poco más incómodo que page=2, pero no se salta ni repite registros cuando entran datos nuevos mientras paginas — que en un inbox pasa todo el tiempo.
<?php
$cursor = null;
do {
$params = ['status' => 'open', 'limit' => 100];
if ($cursor !== null) {
$params['cursor'] = $cursor;
}
$url = 'https://api.kontesta.app/v1/conversations?' . http_build_query($params);
$pagina = json_decode(pedir($url), true);
foreach ($pagina['items'] as $conversacion) {
procesar($conversacion);
}
$cursor = $pagina['nextCursor'] ?? null;
} while ($cursor !== null);Errores
Todos los errores traen la misma forma. El campo requestId es el que nos sirve para rastrear qué pasó: si nos escribes por un error, mándalo.
{
"statusCode": 403,
"error": "Forbidden",
"message": "Scope insuficiente: la llave no concede [messages:send]",
"requestId": "a4898ca6-b9ba-496b-a0bf-814ee17ad7f1",
"timestamp": "2026-08-05T19:56:10.378Z",
"path": "/v1/conversations/cmrh3l84d001yxqdd992h7uwa/messages"
}| Código | Qué pasó | Qué hacer |
|---|---|---|
| 400 | El cuerpo o los parámetros no pasaron validación | Lee message: dice el campo |
| 401 | Falta la llave o no es válida | Revisa la cabecera y que la llave no esté revocada |
| 403 | La llave es válida pero le falta el permiso | Agrega el scope y rota la llave |
| 404 | El recurso no existe o no es de tu cuenta | Verifica el id |
| 409 | Choca con el estado actual | Relee el recurso antes de reintentar |
| 422 | Válido en forma, imposible en negocio | Lee message: explica la regla |
| 429 | Pasaste el límite de peticiones | Espera y reintenta con espera creciente |
| 5xx | Falla nuestra | Reintenta con espera creciente; si insiste, escríbenos con el requestId |
Límites de peticiones
Ventana de un minuto, contada por cuenta, y con cubetas separadas para lectura (GET) y escritura (el resto). Al pasarte recibes 429.
| Plan | Lecturas / min | Escrituras / min |
|---|---|---|
| Prueba | 60 | 30 |
| Emprende / Esencial | 120 | 60 |
| Crece / Pro | 240 | 120 |
| Escala / Max | 480 | 240 |
| Enterprise | 600 | 300 |
Enviar un mensaje
El caso más común. Se envía dentro de una conversación existente: el número de destino y la línea de salida se derivan de ella, así que no los mandas tú y no hay forma de equivocar el mapeo.
curl -s -X POST \
"https://api.kontesta.app/v1/conversations/cvs_abc123/messages" \
-H "X-Api-Key: $KONTESTA_API_KEY" \
-H "Content-Type: application/json" \
-d '{"kind":"text","text":"Tu pedido va en camino."}'La ventana de 24 horas es de Meta, no nuestra
kind: "template"). No es una restricción que podamos levantar: la pone Meta y la aplica su API.Webhooks
En vez de preguntar cada minuto si hay algo nuevo, das de alta una URL tuya y te avisamos. Cada entrega es un POST con el evento en el cuerpo.
curl -s -X POST "https://api.kontesta.app/v1/webhooks" \
-H "X-Api-Key: $KONTESTA_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"url": "https://tu-sistema.example.com/hooks/kontesta",
"events": ["message.received", "lead.created"]
}'
# La respuesta trae el secreto de firma. Se muestra una sola vez:
# { "id": "whk_...", "secret": "whsec_...", ... }Al crear la suscripción te devolvemos un secreto que empieza con whsec_. Con él firmamos cada entrega, y ese es el único modo de saber que la petición viene de nosotros: la URL es pública, cualquiera puede llamarla.
Cabeceras de cada entrega
| Cabecera | Contenido |
|---|---|
X-Kontesta-Signature | t=<unix>,v1=<hex> |
X-Kontesta-Event-Id | Identificador del evento — úsalo para no procesar dos veces |
X-Kontesta-Event-Type | El tipo, por ejemplo message.received |
X-Kontesta-Delivery-Id | Identificador de este intento de entrega |
Verificar la firma
La firma es HMAC-SHA256 del texto {timestamp}.{cuerpo crudo} con tu secreto. Tres reglas que importan: usa el cuerpo tal como llegó (si lo parseas a objeto y lo vuelves a serializar, la firma ya no coincide), compara en tiempo constante, y rechaza lo que tenga más de 5 minutos para que nadie pueda reenviar una petición vieja.
<?php
function verificarFirma(
string $cuerpoCrudo,
?string $cabecera,
string $secreto,
int $toleranciaSeg = 300
): bool {
if ($cabecera === null) {
return false;
}
// La cabecera viene como "t=1754413462,v1=9f86d0..."
$t = null;
$v1 = null;
foreach (explode(',', $cabecera) as $parte) {
$pos = strpos($parte, '=');
if ($pos === false) {
continue;
}
$clave = trim(substr($parte, 0, $pos));
$valor = trim(substr($parte, $pos + 1));
if ($clave === 't') {
$t = $valor;
} elseif ($clave === 'v1') {
$v1 = $valor;
}
}
if ($t === null || $v1 === null) {
return false;
}
// Anti-reenvio: nada mas viejo que la tolerancia.
if (abs(time() - (int) $t) > $toleranciaSeg) {
return false;
}
$esperado = hash_hmac('sha256', $t . '.' . $cuerpoCrudo, $secreto);
// hash_equals compara en tiempo constante. NUNCA usar ===.
return hash_equals($esperado, $v1);
}
// El cuerpo CRUDO, sin parsear: si lo decodificas y lo vuelves a
// codificar, cambia un espacio y la firma ya no coincide.
$cuerpoCrudo = file_get_contents('php://input');
$cabecera = $_SERVER['HTTP_X_KONTESTA_SIGNATURE'] ?? null;
if (!verificarFirma($cuerpoCrudo, $cabecera, getenv('KONTESTA_WEBHOOK_SECRET'))) {
http_response_code(401);
exit;
}
$evento = json_decode($cuerpoCrudo, true);
// Responde 2xx rapido; el trabajo pesado va en cola.
http_response_code(200);
encolar($evento['id'], $evento['type'], $evento['data']);Responde rápido y sé idempotente
2xx en cuanto recibas y haz el trabajo pesado aparte. Si tardas o fallas, reintentamos — y eso significa que el mismo evento puede llegarte dos veces. Guarda los X-Kontesta-Event-Id que ya procesaste y descarta los repetidos.Catálogo de eventos
Al suscribirte eliges cuáles te interesan. Todos llegan con el mismo sobre: id, type, apiVersion, tenantId, occurredAt y data. Con events: [] recibes todos los eventos, menos call.ended y call.recording_ready: esos hay que pedirlos por nombre.
| Evento | Cuándo se dispara | Con «todos» |
|---|---|---|
message.received | Entra un mensaje de un cliente | Llega |
message.status_changed | Un mensaje que enviaste cambia a entregado, leído o fallido | Llega |
conversation.assigned | La conversación se asigna a un agente | Llega |
conversation.closed | Se cierra la conversación | Llega |
lead.created | Se crea una oportunidad | Llega |
lead.stage_changed | Una oportunidad cambia de etapa en el embudo | Llega |
review.obtained | Se obtiene una reseña | Llega |
appointment.created | Se agenda una cita | Llega |
appointment.updated | Se reprograma, confirma o cancela una cita, o se marca que el cliente no llegó | Llega |
payment.updated | Cambia el estado de una liga de pago | Llega |
handoff.requested | El bot (o una regla, un agente o tu sistema) pide pasar la conversación a una persona | Llega |
call.ended | Termina una llamada de WhatsApp: contestada, perdida, rechazada, sin respuesta o fallida | Hay que pedirlo |
call.recording_ready | La grabación de una llamada ya está guardada: trae la liga de descarga y la transcripción, si la hay | Hay que pedirlo |
hosted_link.completed | Tu cliente terminó el flujo de una liga hospedada; por ejemplo, ya conectó su número de WhatsApp | Llega |
hosted_link.failed | El flujo de una liga hospedada falló o no se terminó a tiempo | Llega |
Ejemplo: handoff.requested (traspaso a una persona)
Es el evento que engancha tu sistema cuando el bot suelta la conversación: el cliente pidió hablar con alguien, la pregunta cayó fuera de su base de conocimiento, quiere pagar o agendar, o una regla lo decidió. Viaja sin datos del contacto — ni nombre ni teléfono, solo identificadores, motivo y fechas; el detalle lo consultas por API con conversationId.
{
"id": "evt_01J8...",
"type": "handoff.requested",
"apiVersion": "v1",
"tenantId": "ten_...",
"occurredAt": "2026-09-11T18:02:11.000Z",
"data": {
"conversationId": "cm...",
"handoffId": "cm...",
"channel": "WHATSAPP",
"reason": "CUSTOMER_REQUEST",
"requestedBy": "BOT",
"requestedAt": "2026-09-11T18:02:11.000Z",
"outsideHours": false,
"assignedToId": "usr_...",
"summaryNoteId": "cm..."
}
}
// reason: CUSTOMER_REQUEST | NO_KB_MATCH | MAX_TURNS | NEGATIVE_SENTIMENT |
// PAYMENT_OR_BOOKING | PROVIDER_ERROR | META_AGENT_REQUEST | RULE | MANUAL | OTHER |
// AUDIO_UNTRANSCRIBED
// requestedBy: BOT | META_AGENT | AUTOMATION | USER | API
// assignedToId / summaryNoteId pueden venir null (nadie disponible / sin nota todavía).El mismo mecanismo funciona al revés. Si corres tu propio bot sobre nuestra API y no puede resolver, nos devuelve el hilo con POST /v1/conversations/{id}/handoff: el bot de Kontesta queda en pausa, una persona lo toma desde la bandeja con una nota de contexto y, cuando termina, regresa el hilo con /handoff/return. El historial vive en GET /v1/conversations/{id}/handoffs.
# Tu bot no puede resolver: devuélvenos el hilo para que lo tome una persona.
curl -s -X POST "https://api.kontesta.app/v1/conversations/cm.../handoff" \
-H "X-Api-Key: $KONTESTA_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"reason": "PAYMENT_OR_BOOKING",
"note": "Quiere pagar 2 sillas y agendar entrega el viernes",
"notifyCustomer": true
}'
# 201 → episodio nuevo · 200 + "alreadyPending": true → ya había uno pendiente (idempotente)
# 409 HANDOFF_CONVERSATION_CLOSED → la conversación no está abierta
# Cuando la persona termine, regresa el hilo al bot:
curl -s -X POST "https://api.kontesta.app/v1/conversations/cm.../handoff/return" \
-H "X-Api-Key: $KONTESTA_API_KEY"Referencia de endpoints
Los 392 endpoints que puedes llamar con una API key, con el permiso que exige cada uno. Esta lista se genera del código, no se escribe a mano.
El archivo OpenAPI
La misma superficie, con los cuerpos de petición y respuesta, está en /integracion/openapi.json (OpenAPI 3). Trae solo lo que una llave puede llamar. Con él puedes generar un cliente en tu lenguaje, por ejemplo con openapi-generator:
curl -sO https://kontesta.mx/integracion/openapi.json
# Python
openapi-generator-cli generate -i openapi.json -g python -o kontesta-python
# C#
openapi-generator-cli generate -i openapi.json -g csharp -o kontesta-csharpPara probar a mano en Postman: Import, pega la URL del archivo y elige generar una colección. Los endpoints quedan agrupados por área; tu llave va en la autorización de la colección (tipo API Key, cabecera X-Api-Key).
Conversaciones y mensajes
El inbox: listar hilos, leer y enviar mensajes, asignar, traspaso a una persona.
| GET | /v1/conversation-close-reasons | conversations:read |
| POST | /v1/conversation-close-reasons | conversations:write |
| PATCH | /v1/conversation-close-reasons/{id} | conversations:write |
| GET | /v1/conversations | conversations:read |
| POST | /v1/conversations | messages:send |
| POST | /v1/conversations/bulk | conversations:write |
| GET | /v1/conversations/counts | conversations:read |
| GET | /v1/conversations/{id} | conversations:read |
| PATCH | /v1/conversations/{id} | conversations:write |
| POST | /v1/conversations/{id}/handoff | conversations:write |
| POST | /v1/conversations/{id}/handoff/return | conversations:write |
| GET | /v1/conversations/{id}/handoffs | conversations:read |
| GET | /v1/conversations/{id}/messages | messages:read |
| POST | /v1/conversations/{id}/messages | messages:send |
| GET | /v1/conversations/{id}/messages/at-date | messages:read |
| GET | /v1/conversations/{id}/messages/search | messages:read |
| GET | /v1/conversations/{id}/notes | conversations:read |
| POST | /v1/conversations/{id}/notes | conversations:write |
| POST | /v1/conversations/{id}/presence | conversations:write |
| POST | /v1/conversations/{id}/read | conversations:write |
| POST | /v1/conversations/{id}/request-contact-info | messages:send |
| GET | /v1/conversations/{id}/scheduled | messages:read |
| POST | /v1/conversations/{id}/scheduled | messages:send |
| DELETE | /v1/conversations/{id}/scheduled/{scheduledId} | messages:send |
| DELETE | /v1/conversations/{id}/snooze | conversations:write |
| POST | /v1/conversations/{id}/snooze | conversations:write |
| POST | /v1/conversations/{id}/thread/pass | conversations:write |
| POST | /v1/conversations/{id}/thread/take | conversations:write |
| POST | /v1/conversations/{id}/typing | messages:send |
| GET | /v1/inbox/views | conversations:read |
| POST | /v1/inbox/views | conversations:write |
| DELETE | /v1/inbox/views/{id} | conversations:write |
| PATCH | /v1/inbox/views/{id} | conversations:write |
| GET | /v1/metrics/speed-to-lead | metrics:read |
| GET | /v1/teams | teams:read |
| POST | /v1/teams | teams:write |
| GET | /v1/teams/visibility | teams:read |
| PUT | /v1/teams/visibility | teams:write |
| DELETE | /v1/teams/{id} | teams:write |
| PATCH | /v1/teams/{id} | teams:write |
| GET | /v1/whatsapp/recipient-check | messages:read |
Iniciar conversación
Primer contacto con un número que todavía no escribió (plantilla aprobada).
| POST | /v1/messaging/send | messages:send |
Ficha de cliente
Datos del contacto, notas, datos fiscales, fotos, segmentos guardados y unir duplicados.
| GET | /v1/contacts | contacts:read |
| GET | /v1/contacts/blocked | contacts:read |
| POST | /v1/contacts/bulk | contacts:write |
| POST | /v1/contacts/erasure-request | contacts:erase |
| GET | /v1/contacts/fields | contacts:read |
| POST | /v1/contacts/fields | contacts:write |
| DELETE | /v1/contacts/fields/{fieldId} | contacts:write |
| PATCH | /v1/contacts/fields/{fieldId} | contacts:write |
| GET | /v1/contacts/person-suggestions | contacts:read |
| POST | /v1/contacts/person-suggestions/dismiss | contacts:write |
| GET | /v1/contacts/segment/count | contacts:read |
| GET | /v1/contacts/segments | contacts:read |
| POST | /v1/contacts/segments | contacts:write |
| DELETE | /v1/contacts/segments/{segmentId} | contacts:write |
| GET | /v1/contacts/segments/{segmentId} | contacts:read |
| PATCH | /v1/contacts/segments/{segmentId} | contacts:write |
| GET | /v1/contacts/{id} | contacts:read |
| PATCH | /v1/contacts/{id} | contacts:write |
| PUT | /v1/contacts/{id}/fields/{fieldId} | contacts:write |
| GET | /v1/contacts/{id}/person | contacts:read |
| GET | /v1/contacts/{id}/person-suggestions | contacts:read |
| POST | /v1/contacts/{id}/person/link | contacts:write |
| POST | /v1/contacts/{id}/person/unlink | contacts:write |
| GET | /v1/contacts/{id}/photos | contacts:read |
| POST | /v1/contacts/{id}/tags | contacts:write |
| DELETE | /v1/contacts/{id}/tags/{tagId} | contacts:write |
| GET | /v1/conversations/{id}/customer | contacts:read |
| GET | /v1/conversations/{id}/customer/appointments | contacts:read |
| DELETE | /v1/conversations/{id}/customer/block | contacts:write |
| GET | /v1/conversations/{id}/customer/block | contacts:read |
| POST | /v1/conversations/{id}/customer/block | contacts:write |
| GET | /v1/conversations/{id}/customer/consent | contacts:read |
| POST | /v1/conversations/{id}/customer/consent | contacts:write |
| POST | /v1/conversations/{id}/customer/erasure-request | contacts:erase |
| GET | /v1/conversations/{id}/customer/fiscal | contacts:read |
| PUT | /v1/conversations/{id}/customer/fiscal | contacts:write |
| POST | /v1/conversations/{id}/customer/merge | contacts:write |
| GET | /v1/conversations/{id}/customer/merge-candidates | contacts:read |
| GET | /v1/conversations/{id}/customer/notes | contacts:read |
| POST | /v1/conversations/{id}/customer/notes | contacts:write |
| DELETE | /v1/conversations/{id}/customer/notes/{noteId} | contacts:write |
Importar y exportar contactos
Importación desde CSV o Excel en cola (vista previa, avance y reporte de errores) y exportación del directorio a CSV.
| GET | /v1/contacts/export | contacts:read |
| GET | /v1/contacts/imports | contacts:write |
| POST | /v1/contacts/imports | contacts:write |
| POST | /v1/contacts/imports/preview | contacts:write |
| GET | /v1/contacts/imports/{id} | contacts:write |
| GET | /v1/contacts/imports/{id}/errors.csv | contacts:write |
Leads y embudos
Tablero de oportunidades, etapas y pipelines.
| GET | /v1/contacts/{id}/leads | leads:read |
| GET | /v1/conversations/{id}/leads | leads:read |
| GET | /v1/lead-close-reasons | leads:read |
| POST | /v1/lead-close-reasons | pipelines:write |
| PATCH | /v1/lead-close-reasons/{id} | pipelines:write |
| GET | /v1/leads | leads:read |
| POST | /v1/leads | leads:write |
| GET | /v1/leads/board | leads:read |
| PATCH | /v1/leads/{id} | leads:write |
| GET | /v1/pipelines | pipelines:read |
| POST | /v1/pipelines | pipelines:write |
| PATCH | /v1/pipelines/{id} | pipelines:write |
| POST | /v1/pipelines/{id}/archive | pipelines:write |
| POST | /v1/pipelines/{id}/stages | pipelines:write |
| POST | /v1/pipelines/{id}/unarchive | pipelines:write |
| GET | /v1/reports/pipeline-conversion | metrics:read |
| GET | /v1/reports/pipeline-stage-time | metrics:read |
| GET | /v1/reports/pipeline-won | metrics:read |
| DELETE | /v1/stages/{id} | pipelines:write |
| PATCH | /v1/stages/{id} | pipelines:write |
Tareas de seguimiento
Pendientes por contacto y “mis pendientes”.
| GET | /v1/conversations/{id}/tasks | tasks:read |
| POST | /v1/conversations/{id}/tasks | tasks:write |
| GET | /v1/tasks | tasks:read |
| PATCH | /v1/tasks/{id} | tasks:write |
| GET | /v1/team/workload | metrics:read |
Plantillas de WhatsApp
Plantillas aprobadas por Meta para iniciar conversación.
| GET | /v1/appointments/templates | appointments:read |
| POST | /v1/appointments/templates/provision | appointments:write + templates:manage |
| POST | /v1/appointments/templates/{kind}/resubmit | appointments:write + templates:manage |
| GET | /v1/templates | templates:read |
| POST | /v1/templates | templates:manage |
| POST | /v1/templates/header-sample | templates:manage |
| GET | /v1/templates/recommended | templates:read |
| POST | /v1/templates/recommended/{name} | templates:manage |
| POST | /v1/templates/reconcile | templates:manage |
| DELETE | /v1/templates/{id} | templates:manage |
| GET | /v1/templates/{id} | templates:read |
Automatizaciones
Reglas, horario de atención y corridas.
| GET | /v1/automations | automations:read |
| POST | /v1/automations | automations:write |
| GET | /v1/automations/business-hours | automations:read |
| PUT | /v1/automations/business-hours | automations:write |
| DELETE | /v1/automations/{id} | automations:write |
| GET | /v1/automations/{id} | automations:read |
| PATCH | /v1/automations/{id} | automations:write |
| GET | /v1/automations/{id}/runs | automations:read |
| POST | /v1/automations/{id}/test | automations:write |
| POST | /v1/conversations/{id}/tags | tags:write |
| DELETE | /v1/conversations/{id}/tags/{tagId} | tags:write |
| GET | /v1/tags | tags:read |
| POST | /v1/tags | tags:write |
| DELETE | /v1/tags/{id} | tags:write |
Bots
Bots conversacionales: borrador, validación, simulación sin WhatsApp, publicación por versión, conexiones y métricas.
| GET | /v1/bots | bots:read |
| POST | /v1/bots | bots:write |
| GET | /v1/bots/capabilities | bots:read |
| GET | /v1/bots/catalog | bots:read |
| GET | /v1/bots/connection-presets | bots:read |
| GET | /v1/bots/connections | bots:read |
| POST | /v1/bots/connections | bots:write |
| DELETE | /v1/bots/connections/{connectionId} | bots:write |
| PATCH | /v1/bots/connections/{connectionId} | bots:write |
| POST | /v1/bots/connections/{connectionId}/test | bots:write |
| GET | /v1/bots/env | bots:read |
| PUT | /v1/bots/env | bots:write |
| GET | /v1/bots/templates | bots:read |
| DELETE | /v1/bots/{id} | bots:write |
| GET | /v1/bots/{id} | bots:read |
| PATCH | /v1/bots/{id} | bots:write |
| PUT | /v1/bots/{id}/channels | bots:write |
| PUT | /v1/bots/{id}/draft | bots:write |
| POST | /v1/bots/{id}/duplicate | bots:write |
| POST | /v1/bots/{id}/http-test | bots:write |
| GET | /v1/bots/{id}/metrics | bots:read |
| POST | /v1/bots/{id}/publish | bots:write |
| GET | /v1/bots/{id}/runs | bots:read |
| GET | /v1/bots/{id}/sessions | bots:read |
| POST | /v1/bots/{id}/simulate | bots:write |
| PUT | /v1/bots/{id}/test-phones | bots:write |
| POST | /v1/bots/{id}/validate | bots:read |
| GET | /v1/bots/{id}/versions | bots:read |
| POST | /v1/bots/{id}/versions/restore | bots:write |
| GET | /v1/bots/{id}/versions/{versionId} | bots:read |
| GET | /v1/conversations/{conversationId}/bot-session | conversations:read |
| POST | /v1/conversations/{conversationId}/bot-session/exit | conversations:write |
| POST | /v1/conversations/{conversationId}/bot-session/start | conversations:write |
Respuestas guardadas
Macros del equipo para el compositor.
| GET | /v1/macros | macros:read |
| POST | /v1/macros | macros:write |
| GET | /v1/macros/variables | macros:read |
| DELETE | /v1/macros/{id} | macros:write |
| GET | /v1/macros/{id} | macros:read |
| PATCH | /v1/macros/{id} | macros:write |
Citas y agenda
Tipos de servicio, disponibilidad, agendar y reprogramar.
| GET | /v1/appointments | appointments:read |
| POST | /v1/appointments | appointments:write |
| GET | /v1/appointments/availability | appointments:read |
| GET | /v1/appointments/calendar | appointments:read |
| GET | /v1/appointments/calendar/day | appointments:read |
| GET | /v1/appointments/types | appointments:read |
| GET | /v1/appointments/waitlist | appointments:read |
| GET | /v1/appointments/waitlist/overview | appointments:read |
| DELETE | /v1/appointments/waitlist/{id} | appointments:write |
| PATCH | /v1/appointments/waitlist/{id} | appointments:write |
| POST | /v1/appointments/waitlist/{id}/convert | appointments:write |
| DELETE | /v1/appointments/{id} | appointments:write |
| GET | /v1/appointments/{id} | appointments:read |
| PATCH | /v1/appointments/{id} | appointments:write |
| POST | /v1/appointments/{id}/charge | appointments:write |
| POST | /v1/appointments/{id}/complete | appointments:write |
| POST | /v1/appointments/{id}/confirm | appointments:write + messages:send |
| POST | /v1/appointments/{id}/no-show | appointments:write |
| DELETE | /v1/appointments/{id}/use-package | appointments:write |
| POST | /v1/appointments/{id}/use-package | appointments:write |
| GET | /v1/commission-rules | commissions:read |
| POST | /v1/commission-rules | commissions:write |
| DELETE | /v1/commission-rules/{id} | commissions:write |
| GET | /v1/commission-rules/{id} | commissions:read |
| PATCH | /v1/commission-rules/{id} | commissions:write |
| GET | /v1/commissions/overview | commissions:read |
| POST | /v1/conversations/{id}/appointments | appointments:write |
| POST | /v1/conversations/{id}/waitlist | appointments:write |
| GET | /v1/reports/appointments | appointments:read |
| GET | /v1/reports/commissions | commissions:read |
Llamadas
Llamadas de WhatsApp: detalle de una llamada, grabación y transcripción.
| GET | /v1/calls/{id} | conversations:read |
| GET | /v1/calls/{id}/recording | calls:media:read |
| GET | /v1/calls/{id}/transcript | calls:media:read |
| GET | /v1/conversations/{id}/call-permission | conversations:read |
| POST | /v1/conversations/{id}/call-permission/request | messages:send |
Cobros
Ligas de pago dentro de la conversación.
| GET | /v1/conversations/{id}/payment-links | payments:read |
| POST | /v1/conversations/{id}/payment-links | payments:write |
| GET | /v1/payment-accounts | payments:read |
| POST | /v1/payment-accounts | payments:write |
| DELETE | /v1/payment-accounts/{id} | payments:write |
| PATCH | /v1/payment-accounts/{id} | payments:write |
| POST | /v1/payment-accounts/{id}/test | payments:write |
| POST | /v1/payment-accounts/{id}/test-charge | payments:write |
| GET | /v1/payment-accounts/{id}/webhook-url | payments:read |
| POST | /v1/payment-accounts/{id}/webhook/test | payments:write |
| GET | /v1/payment-links | payments:read |
| GET | /v1/payment-links/{id} | payments:read |
| POST | /v1/payment-links/{id}/cancel | payments:write |
| GET | /v1/payments/overview | payments:read |
| GET | /v1/payments/settings | payments:read |
| PATCH | /v1/payments/settings | payments:write |
Facturación CFDI
Conexión con el PAC, series, timbrado y cancelación.
| GET | /v1/conversations/{id}/invoices | invoices:read |
| POST | /v1/conversations/{id}/invoices | invoices:write |
| GET | /v1/invoices | invoices:read |
| GET | /v1/invoices/{id} | invoices:read |
| POST | /v1/invoices/{id}/cancel | invoices:write |
| GET | /v1/invoices/{id}/pdf | invoices:read |
| GET | /v1/invoices/{id}/xml | invoices:read |
| GET | /v1/invoicing/connections | invoices:read |
| POST | /v1/invoicing/connections | invoices:write |
| DELETE | /v1/invoicing/connections/{id} | invoices:write |
| GET | /v1/invoicing/connections/{id} | invoices:read |
| PATCH | /v1/invoicing/connections/{id} | invoices:write |
| POST | /v1/invoicing/connections/{id}/test | invoices:write |
| GET | /v1/invoicing/emisor | invoices:read |
| POST | /v1/invoicing/emisor/csd | invoices:write |
| PUT | /v1/invoicing/emisor/fiscal | invoices:write |
| POST | /v1/invoicing/emisor/logo | invoices:write |
| GET | /v1/invoicing/series | invoices:read |
| POST | /v1/invoicing/series | invoices:write |
Catálogo y productos
Productos, inventario y envío de producto al chat.
| GET | /v1/catalog/products | catalog:read |
| POST | /v1/catalog/products | catalog:write |
| DELETE | /v1/catalog/products/{id} | catalog:write |
| GET | /v1/catalog/products/{id} | catalog:read |
| PATCH | /v1/catalog/products/{id} | catalog:write |
| POST | /v1/catalog/products/{id}/images | catalog:write |
| GET | /v1/catalog/products/{id}/inventory | catalog:read |
| POST | /v1/catalog/products/{id}/inventory/adjust | catalog:write |
| POST | /v1/conversations/{id}/catalog/send-product | catalog:write + messages:send |
Lealtad
Programas de puntos y sellos, saldo y canjes.
| GET | /v1/conversations/{id}/loyalty | loyalty:read |
| POST | /v1/conversations/{id}/loyalty/adjust | loyalty:write |
| POST | /v1/conversations/{id}/loyalty/earn | loyalty:write |
| POST | /v1/conversations/{id}/loyalty/enroll | loyalty:write |
| POST | /v1/conversations/{id}/loyalty/packages | loyalty:write |
| POST | /v1/conversations/{id}/loyalty/packages/sell | loyalty:write |
| POST | /v1/conversations/{id}/loyalty/redeem | loyalty:write |
| POST | /v1/conversations/{id}/loyalty/send-balance | loyalty:write + messages:send |
| POST | /v1/conversations/{id}/loyalty/send-wallet-pass | loyalty:write + messages:send |
| GET | /v1/loyalty/members | loyalty:read |
| GET | /v1/loyalty/members/{id} | loyalty:read |
| GET | /v1/loyalty/overview | loyalty:read |
| GET | /v1/loyalty/package-types | loyalty:read |
| POST | /v1/loyalty/package-types | loyalty:write |
| PATCH | /v1/loyalty/package-types/{id} | loyalty:write |
| GET | /v1/loyalty/programs | loyalty:read |
| POST | /v1/loyalty/programs | loyalty:write |
| GET | /v1/loyalty/programs/{id} | loyalty:read |
| PATCH | /v1/loyalty/programs/{id} | loyalty:write |
| POST | /v1/loyalty/wallet-passes | loyalty:write |
| GET | /v1/loyalty/wallet-passes/{id} | loyalty:read |
| GET | /v1/packages/overview | loyalty:read |
Reputación
Reseñas, conexiones y solicitudes de reseña.
| POST | /v1/conversations/{id}/review-request | messages:send + reputation:write |
| POST | /v1/reputation/callback/{kind} | reputation:write |
| GET | /v1/reputation/connect/{kind} | reputation:read |
| GET | /v1/reputation/connections | reputation:read |
| DELETE | /v1/reputation/connections/{id} | reputation:write |
| GET | /v1/reputation/overview | reputation:read |
| GET | /v1/reputation/reviews | reputation:read |
| PATCH | /v1/reputation/reviews/{id} | reputation:write |
| POST | /v1/reputation/reviews/{id}/reply | reputation:write |
| POST | /v1/reputation/sync | reputation:write |
Puntos de entrada
WALINK, QR y widget con su llave pública.
| GET | /v1/entry-points | entrypoints:read |
| POST | /v1/entry-points | entrypoints:write |
| GET | /v1/entry-points/channels | entrypoints:read |
| DELETE | /v1/entry-points/{id} | entrypoints:write |
| GET | /v1/entry-points/{id} | entrypoints:read |
| PATCH | /v1/entry-points/{id} | entrypoints:write |
WhatsApp Flows
Formularios de captura y reserva dentro del chat.
| POST | /v1/conversations/{id}/flows | flows:write + messages:send |
Integraciones
Conectores salientes configurados por el tenant.
| GET | /v1/integrations | integrations:read |
| POST | /v1/integrations | integrations:write |
| DELETE | /v1/integrations/{id} | integrations:write |
| GET | /v1/integrations/{id} | integrations:read |
| PATCH | /v1/integrations/{id} | integrations:write |
| POST | /v1/integrations/{id}/test | integrations:write |
Webhooks
Suscripciones, entregas, reintentos y rotación del secreto.
| GET | /v1/webhooks | webhooks:read |
| POST | /v1/webhooks | webhooks:write |
| POST | /v1/webhooks/deliveries/{id}/redeliver | webhooks:write |
| DELETE | /v1/webhooks/{id} | webhooks:write |
| GET | /v1/webhooks/{id} | webhooks:read |
| PATCH | /v1/webhooks/{id} | webhooks:write |
| GET | /v1/webhooks/{id}/deliveries | webhooks:read |
| POST | /v1/webhooks/{id}/ping | webhooks:write |
| POST | /v1/webhooks/{id}/rotate-secret | webhooks:write |
Ligas hospedadas
Liga de un solo uso para que tu cliente conecte su número de WhatsApp en Kontesta, al estilo 3-D Secure.
| POST | /v1/hosted-links | hostedlinks:write |
| GET | /v1/hosted-links/{id} | hostedlinks:read |
| POST | /v1/hosted-links/{id}/cancel | hostedlinks:write |
IA (BYOK)
Credenciales propias, ruteo, presupuesto y uso.
| GET | /v1/ai/bot-config/{channelAccountId} | ai:read |
| PUT | /v1/ai/bot-config/{channelAccountId} | ai:write |
| GET | /v1/ai/channels | ai:read |
| PUT | /v1/ai/channels/{channelAccountId}/mode | ai:write |
| GET | /v1/ai/credentials | ai:read |
| POST | /v1/ai/credentials | ai:write |
| DELETE | /v1/ai/credentials/{id} | ai:write |
| POST | /v1/ai/credentials/{id}/test | ai:write |
| GET | /v1/ai/crm/conversations/{id}/reading | ai:read |
| GET | /v1/ai/crm/conversations/{id}/suggestions | ai:read |
| POST | /v1/ai/crm/conversations/{id}/suggestions | ai:write |
| GET | /v1/ai/crm/csat | ai:read |
| GET | /v1/ai/crm/lead-scores | ai:read |
| GET | /v1/ai/crm/lead-scores/{leadId} | ai:read |
| POST | /v1/ai/crm/lead-scores/{leadId}/rescore | ai:write |
| GET | /v1/ai/crm/quality-audits | ai:read |
| GET | /v1/ai/crm/quality-audits/summary | ai:read |
| GET | /v1/ai/crm/status | ai:read |
| GET | /v1/ai/disclosure | ai:read |
| POST | /v1/ai/messages/{id}/transcribe | ai:write |
| POST | /v1/ai/rewrite | ai:write |
| GET | /v1/ai/settings | ai:read |
| PUT | /v1/ai/settings | ai:write |
| GET | /v1/ai/skill | ai:read |
| PUT | /v1/ai/skill/draft | ai:write |
| POST | /v1/ai/skill/draft/compose | ai:write |
| POST | /v1/ai/skill/polish | ai:write |
| POST | /v1/ai/skill/test | ai:write |
| POST | /v1/ai/skill/unpublish/{channelAccountId} | ai:write |
| POST | /v1/ai/skill/versions | ai:write |
| GET | /v1/ai/skill/versions/{id} | ai:read |
| POST | /v1/ai/skill/versions/{id}/publish | ai:write |
| POST | /v1/ai/skill/versions/{id}/restore | ai:write |
| GET | /v1/ai/suggest | ai:write |
| GET | /v1/ai/usage | ai:read |
| GET | /v1/conversations/{id}/insight | ai:read |
| POST | /v1/conversations/{id}/insight/reanalyze | ai:write |
Base de conocimiento
Fuentes del KB, ingesta y búsqueda.
| GET | /v1/rag/catalog | rag:read |
| PUT | /v1/rag/catalog | rag:write |
| POST | /v1/rag/catalog/sync | rag:write |
| GET | /v1/rag/engine | rag:read |
| POST | /v1/rag/engine/provision | rag:write |
| POST | /v1/rag/search | rag:read |
| GET | /v1/rag/sources | rag:read |
| POST | /v1/rag/sources | rag:write |
| POST | /v1/rag/sources/file | rag:write |
| POST | /v1/rag/sources/reprocess-stale | rag:write |
| POST | /v1/rag/sources/site | rag:write |
| DELETE | /v1/rag/sources/{id} | rag:write |
| GET | /v1/rag/sources/{id} | rag:read |
| POST | /v1/rag/sources/{id}/reingest | rag:write |
Configuración
Ajustes del tenant expuestos a la API.
| GET | /v1/appointment-resources | appointments:read |
| POST | /v1/appointment-resources | appointments:write |
| DELETE | /v1/appointment-resources/{id} | appointments:write |
| GET | /v1/appointment-resources/{id} | appointments:read |
| PATCH | /v1/appointment-resources/{id} | appointments:write |
| GET | /v1/appointment-types | appointments:read |
| POST | /v1/appointment-types | appointments:write |
| DELETE | /v1/appointment-types/{id} | appointments:write |
| GET | /v1/appointment-types/{id} | appointments:read |
| PATCH | /v1/appointment-types/{id} | appointments:write |
| GET | /v1/appointment-types/{id}/reminders | appointments:read |
| PUT | /v1/appointment-types/{id}/reminders | appointments:write |
| GET | /v1/appointment-types/{id}/waitlist | appointments:read |
| PUT | /v1/appointment-types/{id}/waitlist | appointments:write |
| GET | /v1/availability-exceptions | appointments:read |
| POST | /v1/availability-exceptions | appointments:write |
| DELETE | /v1/availability-exceptions/{id} | appointments:write |
| PATCH | /v1/availability-exceptions/{id} | appointments:write |
| GET | /v1/availability-rules | appointments:read |
| POST | /v1/availability-rules | appointments:write |
| DELETE | /v1/availability-rules/{id} | appointments:write |
| PATCH | /v1/availability-rules/{id} | appointments:write |
Archivos
Descarga de adjuntos.
| POST | /v1/media/upload | messages:send |
| GET | /v1/media/{mediaBlobId} | contacts:read |
Fotos de servicio
Evidencia antes/después.
| POST | /v1/conversations/{id}/photos | contacts:write |
| GET | /v1/messages/{id}/media | contacts:read |
Tiempo real
Flujo de eventos por Server-Sent Events.
| GET | /v1/inbox/stream | conversations:read |
SDK de TypeScript
Si trabajas en Node o TypeScript hay un cliente tipado que te ahorra armar las peticiones a mano y trae la verificación de webhooks ya resuelta. Cubre conversaciones, leads, pipelines, automatizaciones, etiquetas, plantillas, métricas, webhooks e integraciones.
Todavía no está en npm
npm i @kontesta/sdk todavía no funciona. Mientras tanto, integra con peticiones HTTP directas como en los ejemplos de arriba — el contrato es el mismo y no vas a tener que reescribir nada cuando salga. Si lo quieres antes, escríbenos.import { Kontesta } from '@kontesta/sdk';
const k = new Kontesta({ apiKey: process.env.KONTESTA_API_KEY! });
// Una página
const { items, nextCursor } = await k.conversations.list({
status: 'open',
limit: 30,
});
// …o todas, sin escribir el bucle del cursor
for await (const c of k.conversations.iterate({ status: 'open' })) {
console.log(c.id);
}Para cualquier otro lenguaje no hace falta SDK: son peticiones HTTP con una cabecera, como los ejemplos de PHP, C# y Python de esta página. Si prefieres un cliente tipado en tu lenguaje, genéralo con el archivo OpenAPI.