Documentación para desarrolladores
Recursos HTTP versionados para integrar conciliación de pagos, avisos de WhatsApp y mensajería de bandeja de entrada desde tu propio sistema.
Desde tu cuenta de Kharyo, entra a Configuración de la API y crea una llave eligiendo solo los permisos (abilities) que tu integración necesita. Solo el propietario del espacio de trabajo puede crear llaves.
Envía la llave como Bearer token en cada solicitud.
Authorization: Bearer kh_xxxxxxxxxxxxxxxxxxxxxxxxxxxxUn buen primer request es consultar tu propio uso del mes.
curl https://api.kharyo.com/v1/usage \
-H "Authorization: Bearer kh_xxxxxxxxxxxxxxxxxxxxxxxxxxxx"Los errores siempre traen error y message. En los endpoints de escritura que mueven dinero o mensajes, envía una clave de idempotencia (header Idempotency-Key en cobros, campo client_id en mensajes) para que un reintento de red nunca duplique el efecto.
{ "error": "currency_mismatch", "message": "La referencia coincide con un pago registrado en USDT, no en USD." }Cada llave tiene un límite base de 60 solicitudes por minuto. Algunos endpoints de escritura tienen además su propio límite, más estricto, indicado en la referencia de abajo.
Cada llave tiene su propio conjunto de permisos, elegidos al crearla. Una llave sin el permiso que exige un endpoint recibe 403.
| notify:send | Enviar avisos de WhatsApp |
| targets:read | Leer destinos de avisos habilitados |
| claims:write | Registrar cobros |
| claims:read | Leer cobros y el cierre de caja |
| reconciliation:read | Leer el cierre de caja diario |
| usage:read | Leer el uso del espacio de trabajo |
| inbox:read | Leer conversaciones, mensajes y plantillas |
| inbox:write | Enviar mensajes y plantillas |
| templates:read | Leer plantillas de WhatsApp y los WABA conectados |
| templates:write | Crear, sincronizar y borrar plantillas de WhatsApp |
| webhooks:manage | Crear, listar y eliminar suscripciones de webhooks salientes |
Todas las respuestas de error son JSON. Existen dos formas, según en qué capa se generó el rechazo: es importante distinguirlas si tu integración hace switch sobre el código.
Token inválido, permiso faltante, ruta inexistente, validación de parámetros o límite genérico excedido. error es una frase legible.
{
"error": "Validation failed",
"message": "The amount field is required.",
"errors": { "amount": ["The amount field is required."] }
}La solicitud llegó al endpoint y este la rechazó. error es un código estable en snake_case, pensado para hacer switch sobre él.
{
"error": "subscription_required",
"message": "El plan del espacio de trabajo no está activo."
}Nota: un 403 por permiso faltante trae error: "Forbidden" (forma de arriba), mientras que un 403 porque tu usuario ya no pertenece al espacio de trabajo de la llave trae error: "forbidden_tenant" (forma de abajo). De igual forma, un 404 de ruta inexistente trae "Not found", y un 404 de recurso no encontrado dentro de un endpoint trae "not_found". El status HTTP es el mismo; el código de error distingue el motivo.
La API usa dos formatos, según el endpoint. Revisa cada uno en la referencia antes de asumir un shape.
{
"data": [...],
"links": { "first": "...", "last": "...", "prev": null, "next": "..." },
"meta": { "current_page": 1, "last_page": 3, "per_page": 20, "total": 45, ... }
}{
"data": [...],
"meta": { "current_page": 1, "last_page": 2, "per_page": 20, "total": 33 }
}GET /notification-targets, GET /inbox/templates, GET /templates/wabas, GET /webhooks y GET /webhooks/{id}/deliveries no están paginados: devuelven { "data": [...] } completo (deliveries, además, siempre trae como máximo 50 filas).
Además de llamar a la API, puedes dejar que Kharyo te avise: cuando ocurre alguno de estos eventos en tu espacio de trabajo, Kharyo envía una solicitud POST a la URL que registres, firmada para que puedas verificar que viene de nosotros.
| payment_claim.matched | Un cobro registrado cruzó con una notificación bancaria. |
| payment_claim.registered | Se registró un cobro esperado, todavía sin cruzar contra el banco. |
| lead.captured | Un chatbot capturó un lead con teléfono o correo. |
| inbox.message.received | Llegó un mensaje nuevo de un contacto en la bandeja de entrada. |
| inbox.sla.breached | Una conversación superó el SLA de primera respuesta del espacio de trabajo. |
| template.status_changed | Meta aprobó, rechazó, pausó o deshabilitó una plantilla de WhatsApp. |
curl -X POST https://api.kharyo.com/v1/webhooks \
-H "Authorization: Bearer kh_xxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{"url": "https://example.com/webhooks/kharyo", "events": ["payment_claim.matched", "lead.captured"]}'Verifica la firma sobre los bytes crudos que llegaron, antes de parsear el JSON: la mayoría de frameworks web parsean el cuerpo automáticamente, así que asegúrate de capturar el cuerpo original primero. Compara con una función de tiempo constante, nunca con ==.
import hashlib
import hmac
def verify_kharyo_signature(secret, timestamp, raw_body, signature_header):
expected = "sha256=" + hmac.new(
secret.encode(), f"{timestamp}.".encode() + raw_body, hashlib.sha256
).hexdigest()
return hmac.compare_digest(expected, signature_header)
# timestamp = headers["X-Kharyo-Timestamp"]
# signature_header = headers["X-Kharyo-Signature"]
# raw_body = el cuerpo tal cual llegó (bytes), antes de parsear el JSONTodos los endpoints viven bajo https://api.kharyo.com/v1 y exigen un Bearer token con el permiso indicado.
Envío de notificaciones de WhatsApp a destinos verificados del espacio de trabajo.
/v1/notifications/whatsappnotify:sendEnvía un aviso a uno o todos los destinos habilitados para la API.
Límite propio: 30/min y 2500/día (propio) + 60/min y 5000/día (compartido con el negocio)
curl -X POST https://api.kharyo.com/v1/notifications/whatsapp \
-H "Authorization: Bearer kh_xxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{"message": "Nuevo comprobante recibido por $45,00"}'/v1/notification-targetstargets:readLista los destinos verificados y habilitados para la API (chat_id enmascarado).
Registro y consulta de cobros, y cierre de caja diario.
/v1/payment-claimsclaims:writeRegistra un cobro esperado para que el conciliador lo cruce contra el banco. Soporta Idempotency-Key.
Límite propio: 30/min
curl -X POST https://api.kharyo.com/v1/payment-claims \
-H "Authorization: Bearer kh_xxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: 8f14e45f-ceea-467e-add3-8e0a1c0f5f3a" \
-d '{"amount": 250.50, "currency": "VES", "reference": "987654321"}'/v1/payment-claimsclaims:readLista los cobros del espacio de trabajo, con filtros por estado, referencia y fecha.
/v1/payment-claims/{id}claims:readConsulta un cobro por id.
/v1/reconciliation/daily-closereconciliation:readCierre de caja de un día (mismos números que la pantalla "Hoy" del conciliador).
Consumo del propio espacio de trabajo.
/v1/usageusage:readTokens y ejecuciones del mes, más el conteo de requests a esta API.
curl https://api.kharyo.com/v1/usage \
-H "Authorization: Bearer kh_xxxxxxxxxxxxxxxxxxxxxxxxxxxx"Conversaciones, mensajes y plantillas de WhatsApp.
/v1/inbox/conversationsinbox:readLista conversaciones, con filtros por estado, canal y última actualización.
/v1/inbox/conversations/{id}inbox:readConsulta una conversación.
/v1/inbox/conversations/{id}/messagesinbox:readLista los mensajes de una conversación (paginación sin links, ver más abajo).
/v1/inbox/conversations/{id}/messagesinbox:writeEnvía un mensaje manual en nombre del negocio. Soporta client_id para reintentos seguros.
Límite propio: 30/min (compartido con .../template)
curl -X POST https://api.kharyo.com/v1/inbox/conversations/{id}/messages \
-H "Authorization: Bearer kh_xxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{"content": "Hola, tenemos tu pedido listo."}'/v1/inbox/conversations/{id}/templateinbox:writeEnvía una plantilla de WhatsApp ya aprobada, sustituyendo variables (template_id es ULID; variables es una lista posicional; media.link para headers de imagen/video/documento). Solo en conversaciones de WhatsApp.
Límite propio: 30/min (compartido con .../messages)
curl -X POST https://api.kharyo.com/v1/inbox/conversations/{id}/template \
-H "Authorization: Bearer kh_xxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{"template_id": "01J9Z8Q3K7N4M2P5R6S8T0V1W3", "variables": ["Juan", "#123"]}'/v1/inbox/conversations/{id}/modeinbox:writePausa o reactiva la IA de una conversación (active | paused).
/v1/inbox/templatesinbox:readLista las plantillas de WhatsApp aprobadas del espacio de trabajo (proyección mínima; ver /v1/templates para gestión completa).
Gestión completa de plantillas: listar, crear, sincronizar con Meta y borrar.
/v1/templatestemplates:readLista paginada de plantillas del espacio de trabajo, con filtros por waba_id, status, language y category.
/v1/templates/wabastemplates:readLista los WABA (WhatsApp Business Account) conectados del espacio de trabajo.
/v1/templatestemplates:writeCrea una plantilla y la envía a aprobación de Meta. 409 si ya existe una con el mismo (waba_id, name, language); 502 si Meta la rechaza.
curl -X POST https://api.kharyo.com/v1/templates \
-H "Authorization: Bearer kh_xxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{"waba_id": "123456789012345", "name": "order_confirmation", "language": "es", "category": "UTILITY", "components": [{"type": "BODY", "text": "Hola {{1}}, tu pedido {{2}} está confirmado."}]}'/v1/templates/synctemplates:writeEncola una sincronización con Meta del estado de las plantillas de un WABA (aprobación, calidad, rechazo). Devuelve 202.
/v1/templates/{id}templates:readConsulta una plantilla por su id (ULID).
/v1/templates/{id}templates:writeBorra una plantilla en Meta y localmente. 502 si Meta rechaza el borrado.
Gestión de suscripciones a webhooks salientes: eventos que Kharyo envía a tu propio endpoint.
/v1/webhookswebhooks:manageCrea una suscripción de webhook (hasta 5 activas). El secreto solo se muestra en esta respuesta.
curl -X POST https://api.kharyo.com/v1/webhooks \
-H "Authorization: Bearer kh_xxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{"url": "https://example.com/webhooks/kharyo", "events": ["payment_claim.matched", "lead.captured"]}'/v1/webhookswebhooks:manageLista las suscripciones del espacio de trabajo.
/v1/webhooks/{id}webhooks:manageElimina una suscripción y su historial de entregas. Única forma de rotar el secreto.
/v1/webhooks/{id}/testwebhooks:manageEnvía un evento ping de prueba, firmado igual que una entrega real.
/v1/webhooks/{id}/deliverieswebhooks:manageLista los últimos 50 intentos de entrega, sin el cuerpo enviado.
La especificación completa (OpenAPI 3.1), con todos los schemas de request/response, vive en un solo archivo descargable.
Descargar especificación OpenAPI