Desarrolladores

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.

ConceptoValor
URL basehttps://api.kontesta.app
OpenAPI/integracion/openapi.json
VersiónVa en la ruta: todas las rutas empiezan con /v1
FormatoJSON en petición y respuesta, UTF-8
Llavektk_ + 8 caracteres de prefijo + . + el secreto

No hay entorno de pruebas público

Todo lo que hagas con tu llave pasa en tu cuenta real, y un mensaje que envíes sí le llega al cliente por WhatsApp. Para probar sin mandarle nada a nadie:
  • Empieza con una llave que solo tenga permisos de lectura (los que terminan en :read). Con ella cualquier endpoint que envía responde 403: no hay forma de que mande un mensaje.
  • Para tu receptor de webhooks, POST /v1/webhooks/{id}/ping te manda un evento test.ping firmado 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-aqui

Trata la llave como una contraseña

Una API key vale por todo el permiso que le diste, no caduca sola y no está atada a ningún usuario. Guárdala en variables de entorno o en tu bóveda de secretos — nunca en el código, en el repositorio, ni en el navegador: cualquier llamada desde el frontend expone la llave a quien abra las herramientas de desarrollo. Toda integración va servidor a servidor.

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

Un endpoint que no declara permiso explícitamente no es alcanzable con una API key, punto. No hay llave maestra ni permiso comodín. Por eso la referencia de endpoints de esta página es la superficie pública completa: lo que no aparece ahí, no se puede llamar con una llave, aunque exista en la app.

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.

paginar.php
<?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.

respuesta 403
{
  "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ódigoQué pasóQué hacer
400El cuerpo o los parámetros no pasaron validaciónLee message: dice el campo
401Falta la llave o no es válidaRevisa la cabecera y que la llave no esté revocada
403La llave es válida pero le falta el permisoAgrega el scope y rota la llave
404El recurso no existe o no es de tu cuentaVerifica el id
409Choca con el estado actualRelee el recurso antes de reintentar
422Válido en forma, imposible en negocioLee message: explica la regla
429Pasaste el límite de peticionesEspera y reintenta con espera creciente
5xxFalla nuestraReintenta 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.

PlanLecturas / minEscrituras / min
Prueba6030
Emprende / Esencial12060
Crece / Pro240120
Escala / Max480240
Enterprise600300

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

WhatsApp solo permite texto libre dentro de las 24 horas siguientes al último mensaje del cliente. Fuera de esa ventana hay que usar una plantilla aprobada (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

CabeceraContenido
X-Kontesta-Signaturet=<unix>,v1=<hex>
X-Kontesta-Event-IdIdentificador del evento — úsalo para no procesar dos veces
X-Kontesta-Event-TypeEl tipo, por ejemplo message.received
X-Kontesta-Delivery-IdIdentificador 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.

webhook.php
<?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

Contesta 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.

EventoCuándo se disparaCon «todos»
message.receivedEntra un mensaje de un clienteLlega
message.status_changedUn mensaje que enviaste cambia a entregado, leído o fallidoLlega
conversation.assignedLa conversación se asigna a un agenteLlega
conversation.closedSe cierra la conversaciónLlega
lead.createdSe crea una oportunidadLlega
lead.stage_changedUna oportunidad cambia de etapa en el embudoLlega
review.obtainedSe obtiene una reseñaLlega
appointment.createdSe agenda una citaLlega
appointment.updatedSe reprograma, confirma o cancela una cita, o se marca que el cliente no llegóLlega
payment.updatedCambia el estado de una liga de pagoLlega
handoff.requestedEl bot (o una regla, un agente o tu sistema) pide pasar la conversación a una personaLlega
call.endedTermina una llamada de WhatsApp: contestada, perdida, rechazada, sin respuesta o fallidaHay que pedirlo
call.recording_readyLa grabación de una llamada ya está guardada: trae la liga de descarga y la transcripción, si la hayHay que pedirlo
hosted_link.completedTu cliente terminó el flujo de una liga hospedada; por ejemplo, ya conectó su número de WhatsAppLlega
hosted_link.failedEl flujo de una liga hospedada falló o no se terminó a tiempoLlega

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.

handoff.requested
{
  "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-csharp

Para 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-reasonsconversations:read
POST/v1/conversation-close-reasonsconversations:write
PATCH/v1/conversation-close-reasons/{id}conversations:write
GET/v1/conversationsconversations:read
POST/v1/conversationsmessages:send
POST/v1/conversations/bulkconversations:write
GET/v1/conversations/countsconversations:read
GET/v1/conversations/{id}conversations:read
PATCH/v1/conversations/{id}conversations:write
POST/v1/conversations/{id}/handoffconversations:write
POST/v1/conversations/{id}/handoff/returnconversations:write
GET/v1/conversations/{id}/handoffsconversations:read
GET/v1/conversations/{id}/messagesmessages:read
POST/v1/conversations/{id}/messagesmessages:send
GET/v1/conversations/{id}/messages/at-datemessages:read
GET/v1/conversations/{id}/messages/searchmessages:read
GET/v1/conversations/{id}/notesconversations:read
POST/v1/conversations/{id}/notesconversations:write
POST/v1/conversations/{id}/presenceconversations:write
POST/v1/conversations/{id}/readconversations:write
POST/v1/conversations/{id}/request-contact-infomessages:send
GET/v1/conversations/{id}/scheduledmessages:read
POST/v1/conversations/{id}/scheduledmessages:send
DELETE/v1/conversations/{id}/scheduled/{scheduledId}messages:send
DELETE/v1/conversations/{id}/snoozeconversations:write
POST/v1/conversations/{id}/snoozeconversations:write
POST/v1/conversations/{id}/thread/passconversations:write
POST/v1/conversations/{id}/thread/takeconversations:write
POST/v1/conversations/{id}/typingmessages:send
GET/v1/inbox/viewsconversations:read
POST/v1/inbox/viewsconversations:write
DELETE/v1/inbox/views/{id}conversations:write
PATCH/v1/inbox/views/{id}conversations:write
GET/v1/metrics/speed-to-leadmetrics:read
GET/v1/teamsteams:read
POST/v1/teamsteams:write
GET/v1/teams/visibilityteams:read
PUT/v1/teams/visibilityteams:write
DELETE/v1/teams/{id}teams:write
PATCH/v1/teams/{id}teams:write
GET/v1/whatsapp/recipient-checkmessages:read

Iniciar conversación

Primer contacto con un número que todavía no escribió (plantilla aprobada).

POST/v1/messaging/sendmessages:send

Ficha de cliente

Datos del contacto, notas, datos fiscales, fotos, segmentos guardados y unir duplicados.

GET/v1/contactscontacts:read
GET/v1/contacts/blockedcontacts:read
POST/v1/contacts/bulkcontacts:write
POST/v1/contacts/erasure-requestcontacts:erase
GET/v1/contacts/fieldscontacts:read
POST/v1/contacts/fieldscontacts:write
DELETE/v1/contacts/fields/{fieldId}contacts:write
PATCH/v1/contacts/fields/{fieldId}contacts:write
GET/v1/contacts/person-suggestionscontacts:read
POST/v1/contacts/person-suggestions/dismisscontacts:write
GET/v1/contacts/segment/countcontacts:read
GET/v1/contacts/segmentscontacts:read
POST/v1/contacts/segmentscontacts: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}/personcontacts:read
GET/v1/contacts/{id}/person-suggestionscontacts:read
POST/v1/contacts/{id}/person/linkcontacts:write
POST/v1/contacts/{id}/person/unlinkcontacts:write
GET/v1/contacts/{id}/photoscontacts:read
POST/v1/contacts/{id}/tagscontacts:write
DELETE/v1/contacts/{id}/tags/{tagId}contacts:write
GET/v1/conversations/{id}/customercontacts:read
GET/v1/conversations/{id}/customer/appointmentscontacts:read
DELETE/v1/conversations/{id}/customer/blockcontacts:write
GET/v1/conversations/{id}/customer/blockcontacts:read
POST/v1/conversations/{id}/customer/blockcontacts:write
GET/v1/conversations/{id}/customer/consentcontacts:read
POST/v1/conversations/{id}/customer/consentcontacts:write
POST/v1/conversations/{id}/customer/erasure-requestcontacts:erase
GET/v1/conversations/{id}/customer/fiscalcontacts:read
PUT/v1/conversations/{id}/customer/fiscalcontacts:write
POST/v1/conversations/{id}/customer/mergecontacts:write
GET/v1/conversations/{id}/customer/merge-candidatescontacts:read
GET/v1/conversations/{id}/customer/notescontacts:read
POST/v1/conversations/{id}/customer/notescontacts: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/exportcontacts:read
GET/v1/contacts/importscontacts:write
POST/v1/contacts/importscontacts:write
POST/v1/contacts/imports/previewcontacts:write
GET/v1/contacts/imports/{id}contacts:write
GET/v1/contacts/imports/{id}/errors.csvcontacts:write

Leads y embudos

Tablero de oportunidades, etapas y pipelines.

GET/v1/contacts/{id}/leadsleads:read
GET/v1/conversations/{id}/leadsleads:read
GET/v1/lead-close-reasonsleads:read
POST/v1/lead-close-reasonspipelines:write
PATCH/v1/lead-close-reasons/{id}pipelines:write
GET/v1/leadsleads:read
POST/v1/leadsleads:write
GET/v1/leads/boardleads:read
PATCH/v1/leads/{id}leads:write
GET/v1/pipelinespipelines:read
POST/v1/pipelinespipelines:write
PATCH/v1/pipelines/{id}pipelines:write
POST/v1/pipelines/{id}/archivepipelines:write
POST/v1/pipelines/{id}/stagespipelines:write
POST/v1/pipelines/{id}/unarchivepipelines:write
GET/v1/reports/pipeline-conversionmetrics:read
GET/v1/reports/pipeline-stage-timemetrics:read
GET/v1/reports/pipeline-wonmetrics: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}/taskstasks:read
POST/v1/conversations/{id}/taskstasks:write
GET/v1/taskstasks:read
PATCH/v1/tasks/{id}tasks:write
GET/v1/team/workloadmetrics:read

Plantillas de WhatsApp

Plantillas aprobadas por Meta para iniciar conversación.

GET/v1/appointments/templatesappointments:read
POST/v1/appointments/templates/provisionappointments:write + templates:manage
POST/v1/appointments/templates/{kind}/resubmitappointments:write + templates:manage
GET/v1/templatestemplates:read
POST/v1/templatestemplates:manage
POST/v1/templates/header-sampletemplates:manage
GET/v1/templates/recommendedtemplates:read
POST/v1/templates/recommended/{name}templates:manage
POST/v1/templates/reconciletemplates:manage
DELETE/v1/templates/{id}templates:manage
GET/v1/templates/{id}templates:read

Automatizaciones

Reglas, horario de atención y corridas.

GET/v1/automationsautomations:read
POST/v1/automationsautomations:write
GET/v1/automations/business-hoursautomations:read
PUT/v1/automations/business-hoursautomations:write
DELETE/v1/automations/{id}automations:write
GET/v1/automations/{id}automations:read
PATCH/v1/automations/{id}automations:write
GET/v1/automations/{id}/runsautomations:read
POST/v1/automations/{id}/testautomations:write
POST/v1/conversations/{id}/tagstags:write
DELETE/v1/conversations/{id}/tags/{tagId}tags:write
GET/v1/tagstags:read
POST/v1/tagstags: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/botsbots:read
POST/v1/botsbots:write
GET/v1/bots/capabilitiesbots:read
GET/v1/bots/catalogbots:read
GET/v1/bots/connection-presetsbots:read
GET/v1/bots/connectionsbots:read
POST/v1/bots/connectionsbots:write
DELETE/v1/bots/connections/{connectionId}bots:write
PATCH/v1/bots/connections/{connectionId}bots:write
POST/v1/bots/connections/{connectionId}/testbots:write
GET/v1/bots/envbots:read
PUT/v1/bots/envbots:write
GET/v1/bots/templatesbots:read
DELETE/v1/bots/{id}bots:write
GET/v1/bots/{id}bots:read
PATCH/v1/bots/{id}bots:write
PUT/v1/bots/{id}/channelsbots:write
PUT/v1/bots/{id}/draftbots:write
POST/v1/bots/{id}/duplicatebots:write
POST/v1/bots/{id}/http-testbots:write
GET/v1/bots/{id}/metricsbots:read
POST/v1/bots/{id}/publishbots:write
GET/v1/bots/{id}/runsbots:read
GET/v1/bots/{id}/sessionsbots:read
POST/v1/bots/{id}/simulatebots:write
PUT/v1/bots/{id}/test-phonesbots:write
POST/v1/bots/{id}/validatebots:read
GET/v1/bots/{id}/versionsbots:read
POST/v1/bots/{id}/versions/restorebots:write
GET/v1/bots/{id}/versions/{versionId}bots:read
GET/v1/conversations/{conversationId}/bot-sessionconversations:read
POST/v1/conversations/{conversationId}/bot-session/exitconversations:write
POST/v1/conversations/{conversationId}/bot-session/startconversations:write

Respuestas guardadas

Macros del equipo para el compositor.

GET/v1/macrosmacros:read
POST/v1/macrosmacros:write
GET/v1/macros/variablesmacros: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/appointmentsappointments:read
POST/v1/appointmentsappointments:write
GET/v1/appointments/availabilityappointments:read
GET/v1/appointments/calendarappointments:read
GET/v1/appointments/calendar/dayappointments:read
GET/v1/appointments/typesappointments:read
GET/v1/appointments/waitlistappointments:read
GET/v1/appointments/waitlist/overviewappointments:read
DELETE/v1/appointments/waitlist/{id}appointments:write
PATCH/v1/appointments/waitlist/{id}appointments:write
POST/v1/appointments/waitlist/{id}/convertappointments:write
DELETE/v1/appointments/{id}appointments:write
GET/v1/appointments/{id}appointments:read
PATCH/v1/appointments/{id}appointments:write
POST/v1/appointments/{id}/chargeappointments:write
POST/v1/appointments/{id}/completeappointments:write
POST/v1/appointments/{id}/confirmappointments:write + messages:send
POST/v1/appointments/{id}/no-showappointments:write
DELETE/v1/appointments/{id}/use-packageappointments:write
POST/v1/appointments/{id}/use-packageappointments:write
GET/v1/commission-rulescommissions:read
POST/v1/commission-rulescommissions: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/overviewcommissions:read
POST/v1/conversations/{id}/appointmentsappointments:write
POST/v1/conversations/{id}/waitlistappointments:write
GET/v1/reports/appointmentsappointments:read
GET/v1/reports/commissionscommissions:read

Llamadas

Llamadas de WhatsApp: detalle de una llamada, grabación y transcripción.

GET/v1/calls/{id}conversations:read
GET/v1/calls/{id}/recordingcalls:media:read
GET/v1/calls/{id}/transcriptcalls:media:read
GET/v1/conversations/{id}/call-permissionconversations:read
POST/v1/conversations/{id}/call-permission/requestmessages:send

Cobros

Ligas de pago dentro de la conversación.

GET/v1/conversations/{id}/payment-linkspayments:read
POST/v1/conversations/{id}/payment-linkspayments:write
GET/v1/payment-accountspayments:read
POST/v1/payment-accountspayments:write
DELETE/v1/payment-accounts/{id}payments:write
PATCH/v1/payment-accounts/{id}payments:write
POST/v1/payment-accounts/{id}/testpayments:write
POST/v1/payment-accounts/{id}/test-chargepayments:write
GET/v1/payment-accounts/{id}/webhook-urlpayments:read
POST/v1/payment-accounts/{id}/webhook/testpayments:write
GET/v1/payment-linkspayments:read
GET/v1/payment-links/{id}payments:read
POST/v1/payment-links/{id}/cancelpayments:write
GET/v1/payments/overviewpayments:read
GET/v1/payments/settingspayments:read
PATCH/v1/payments/settingspayments:write

Facturación CFDI

Conexión con el PAC, series, timbrado y cancelación.

GET/v1/conversations/{id}/invoicesinvoices:read
POST/v1/conversations/{id}/invoicesinvoices:write
GET/v1/invoicesinvoices:read
GET/v1/invoices/{id}invoices:read
POST/v1/invoices/{id}/cancelinvoices:write
GET/v1/invoices/{id}/pdfinvoices:read
GET/v1/invoices/{id}/xmlinvoices:read
GET/v1/invoicing/connectionsinvoices:read
POST/v1/invoicing/connectionsinvoices: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}/testinvoices:write
GET/v1/invoicing/emisorinvoices:read
POST/v1/invoicing/emisor/csdinvoices:write
PUT/v1/invoicing/emisor/fiscalinvoices:write
POST/v1/invoicing/emisor/logoinvoices:write
GET/v1/invoicing/seriesinvoices:read
POST/v1/invoicing/seriesinvoices:write

Catálogo y productos

Productos, inventario y envío de producto al chat.

GET/v1/catalog/productscatalog:read
POST/v1/catalog/productscatalog: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}/imagescatalog:write
GET/v1/catalog/products/{id}/inventorycatalog:read
POST/v1/catalog/products/{id}/inventory/adjustcatalog:write
POST/v1/conversations/{id}/catalog/send-productcatalog:write + messages:send

Lealtad

Programas de puntos y sellos, saldo y canjes.

GET/v1/conversations/{id}/loyaltyloyalty:read
POST/v1/conversations/{id}/loyalty/adjustloyalty:write
POST/v1/conversations/{id}/loyalty/earnloyalty:write
POST/v1/conversations/{id}/loyalty/enrollloyalty:write
POST/v1/conversations/{id}/loyalty/packagesloyalty:write
POST/v1/conversations/{id}/loyalty/packages/sellloyalty:write
POST/v1/conversations/{id}/loyalty/redeemloyalty:write
POST/v1/conversations/{id}/loyalty/send-balanceloyalty:write + messages:send
POST/v1/conversations/{id}/loyalty/send-wallet-passloyalty:write + messages:send
GET/v1/loyalty/membersloyalty:read
GET/v1/loyalty/members/{id}loyalty:read
GET/v1/loyalty/overviewloyalty:read
GET/v1/loyalty/package-typesloyalty:read
POST/v1/loyalty/package-typesloyalty:write
PATCH/v1/loyalty/package-types/{id}loyalty:write
GET/v1/loyalty/programsloyalty:read
POST/v1/loyalty/programsloyalty:write
GET/v1/loyalty/programs/{id}loyalty:read
PATCH/v1/loyalty/programs/{id}loyalty:write
POST/v1/loyalty/wallet-passesloyalty:write
GET/v1/loyalty/wallet-passes/{id}loyalty:read
GET/v1/packages/overviewloyalty:read

Reputación

Reseñas, conexiones y solicitudes de reseña.

POST/v1/conversations/{id}/review-requestmessages:send + reputation:write
POST/v1/reputation/callback/{kind}reputation:write
GET/v1/reputation/connect/{kind}reputation:read
GET/v1/reputation/connectionsreputation:read
DELETE/v1/reputation/connections/{id}reputation:write
GET/v1/reputation/overviewreputation:read
GET/v1/reputation/reviewsreputation:read
PATCH/v1/reputation/reviews/{id}reputation:write
POST/v1/reputation/reviews/{id}/replyreputation:write
POST/v1/reputation/syncreputation:write

Puntos de entrada

WALINK, QR y widget con su llave pública.

GET/v1/entry-pointsentrypoints:read
POST/v1/entry-pointsentrypoints:write
GET/v1/entry-points/channelsentrypoints: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}/flowsflows:write + messages:send

Integraciones

Conectores salientes configurados por el tenant.

GET/v1/integrationsintegrations:read
POST/v1/integrationsintegrations:write
DELETE/v1/integrations/{id}integrations:write
GET/v1/integrations/{id}integrations:read
PATCH/v1/integrations/{id}integrations:write
POST/v1/integrations/{id}/testintegrations:write

Webhooks

Suscripciones, entregas, reintentos y rotación del secreto.

GET/v1/webhookswebhooks:read
POST/v1/webhookswebhooks:write
POST/v1/webhooks/deliveries/{id}/redeliverwebhooks:write
DELETE/v1/webhooks/{id}webhooks:write
GET/v1/webhooks/{id}webhooks:read
PATCH/v1/webhooks/{id}webhooks:write
GET/v1/webhooks/{id}/deliverieswebhooks:read
POST/v1/webhooks/{id}/pingwebhooks:write
POST/v1/webhooks/{id}/rotate-secretwebhooks: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-linkshostedlinks:write
GET/v1/hosted-links/{id}hostedlinks:read
POST/v1/hosted-links/{id}/cancelhostedlinks: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/channelsai:read
PUT/v1/ai/channels/{channelAccountId}/modeai:write
GET/v1/ai/credentialsai:read
POST/v1/ai/credentialsai:write
DELETE/v1/ai/credentials/{id}ai:write
POST/v1/ai/credentials/{id}/testai:write
GET/v1/ai/crm/conversations/{id}/readingai:read
GET/v1/ai/crm/conversations/{id}/suggestionsai:read
POST/v1/ai/crm/conversations/{id}/suggestionsai:write
GET/v1/ai/crm/csatai:read
GET/v1/ai/crm/lead-scoresai:read
GET/v1/ai/crm/lead-scores/{leadId}ai:read
POST/v1/ai/crm/lead-scores/{leadId}/rescoreai:write
GET/v1/ai/crm/quality-auditsai:read
GET/v1/ai/crm/quality-audits/summaryai:read
GET/v1/ai/crm/statusai:read
GET/v1/ai/disclosureai:read
POST/v1/ai/messages/{id}/transcribeai:write
POST/v1/ai/rewriteai:write
GET/v1/ai/settingsai:read
PUT/v1/ai/settingsai:write
GET/v1/ai/skillai:read
PUT/v1/ai/skill/draftai:write
POST/v1/ai/skill/draft/composeai:write
POST/v1/ai/skill/polishai:write
POST/v1/ai/skill/testai:write
POST/v1/ai/skill/unpublish/{channelAccountId}ai:write
POST/v1/ai/skill/versionsai:write
GET/v1/ai/skill/versions/{id}ai:read
POST/v1/ai/skill/versions/{id}/publishai:write
POST/v1/ai/skill/versions/{id}/restoreai:write
GET/v1/ai/suggestai:write
GET/v1/ai/usageai:read
GET/v1/conversations/{id}/insightai:read
POST/v1/conversations/{id}/insight/reanalyzeai:write

Base de conocimiento

Fuentes del KB, ingesta y búsqueda.

GET/v1/rag/catalograg:read
PUT/v1/rag/catalograg:write
POST/v1/rag/catalog/syncrag:write
GET/v1/rag/enginerag:read
POST/v1/rag/engine/provisionrag:write
POST/v1/rag/searchrag:read
GET/v1/rag/sourcesrag:read
POST/v1/rag/sourcesrag:write
POST/v1/rag/sources/filerag:write
POST/v1/rag/sources/reprocess-stalerag:write
POST/v1/rag/sources/siterag:write
DELETE/v1/rag/sources/{id}rag:write
GET/v1/rag/sources/{id}rag:read
POST/v1/rag/sources/{id}/reingestrag:write

Configuración

Ajustes del tenant expuestos a la API.

GET/v1/appointment-resourcesappointments:read
POST/v1/appointment-resourcesappointments: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-typesappointments:read
POST/v1/appointment-typesappointments: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}/remindersappointments:read
PUT/v1/appointment-types/{id}/remindersappointments:write
GET/v1/appointment-types/{id}/waitlistappointments:read
PUT/v1/appointment-types/{id}/waitlistappointments:write
GET/v1/availability-exceptionsappointments:read
POST/v1/availability-exceptionsappointments:write
DELETE/v1/availability-exceptions/{id}appointments:write
PATCH/v1/availability-exceptions/{id}appointments:write
GET/v1/availability-rulesappointments:read
POST/v1/availability-rulesappointments:write
DELETE/v1/availability-rules/{id}appointments:write
PATCH/v1/availability-rules/{id}appointments:write

Archivos

Descarga de adjuntos.

POST/v1/media/uploadmessages:send
GET/v1/media/{mediaBlobId}contacts:read

Fotos de servicio

Evidencia antes/después.

POST/v1/conversations/{id}/photoscontacts:write
GET/v1/messages/{id}/mediacontacts:read

Tiempo real

Flujo de eventos por Server-Sent Events.

GET/v1/inbox/streamconversations: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

El paquete existe y está probado, pero aún no lo publicamos: 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.
ejemplo.ts
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.

Conecta tu número