Referencia de API
La API de CustomerHero te permite gestionar chatbots, clientes, conversaciones y más de forma programática. Todos los endpoints devuelven respuestas en JSON.
Autenticación
La mayoría de los endpoints de la API requieren autenticación mediante una clave de API. Incluye tu clave en la cabecera Authorization como token Bearer.
Crea claves de API en la configuración de tu panel.
curl https://api.customerhero.app/api/chatbots \
-H "Authorization: Bearer sk_live_tu_clave_api"URL base
CustomerHero ofrece hosts regionales para que tus datos permanezcan en la región que elegiste al crear tu organización. Envía las solicitudes al host que coincide con la región de tu organización:
# EE. UU. (predeterminado)
https://us.api.customerhero.app
# UE (residencia de datos GDPR)
https://eu.api.customerhero.appEl host heredado https://api.customerhero.app también acepta solicitudes y las redirige a la región correcta; pero usar el host regional directamente evita una redirección en cada solicitud.
La especificación OpenAPI completa está disponible en /api/openapi.json (se abre en una pestaña nueva).
Errores
La API usa códigos de estado HTTP estándar. Las respuestas de error incluyen un cuerpo JSON con un campo error.
| Estado | Significado |
|---|---|
| 200 | Éxito |
| 201 | Creado |
| 400 | Solicitud incorrecta — parámetros faltantes o no válidos |
| 401 | No autorizado — clave de API no válida o ausente |
| 403 | Prohibido — permisos insuficientes |
| 402 | Pago requerido — se alcanzó el límite del plan o se acabaron los créditos |
| 404 | No encontrado — el recurso no existe |
| 429 | Demasiadas solicitudes — se alcanzó el límite de tasa |
| 500 | Error interno del servidor |
{
"error": "Unauthorized"
}Límites de tasa e idempotencia
La API protege la infraestructura compartida con límites de tasa por clave, por ruta y por IP. Cuando superas un límite recibes una respuesta HTTP 429 con una cabecera Retry-After (en segundos). Espera al menos ese tiempo antes de reintentar. Las rutas calientes como el endpoint público de chat y los flujos de login tienen límites más estrictos que el CRUD del panel.
Estrategia de reintento. Trata 429 y 5xx como transitorios. Reintenta con retroceso exponencial y jitter (p. ej. 1 s, 2 s, 4 s, 8 s con ±20 % de jitter). Limita a 5 intentos. Nunca reintentes con 4xx distintos de 429: son errores del cliente.
Idempotencia. Las solicitudes mutantes (POST, PUT, PATCH) aceptan la cabecera Idempotency-Key. Reutilizar la misma clave dentro de 24 horas devuelve la respuesta original en lugar de ejecutar la operación de nuevo. Usa un UUID nuevo por operación lógica:
curl https://us.api.customerhero.app/api/orgs/ORG_ID/customers \
-X POST \
-H "Authorization: Bearer sk_live_..." \
-H "Idempotency-Key: 8f4b2c0e-3a91-4d2f-9a4f-0d3a5b1e8c77" \
-H "Content-Type: application/json" \
-d '{"email":"jane@acme.com"}'Webhooks
Suscríbete a eventos desde la configuración de webhooks del panel. Cada suscripción recibe un POST por evento, firmado con un secreto HMAC-SHA256 que defines al crearla. Las solicitudes incluyen una cabecera Idempotency-Key igual al id del evento, para que los receptores puedan deduplicar reintentos con seguridad.
Cabeceras
| Cabecera | Valor |
|---|---|
| X-CustomerHero-Event-Id | Identificador estable de esta entrega — úsalo como tu clave de idempotencia. |
| X-CustomerHero-Event-Type | Nombre del evento, p. ej. conversation.created. |
| X-CustomerHero-Timestamp | Marca de tiempo Unix (segundos) en la que se firmó la solicitud. |
| X-CustomerHero-Signature | t=<timestamp>,v1=<hmac-sha256-hex>. v1 es el único esquema actual; los nuevos se añadirán sin retirarlo. |
| Idempotency-Key | Refleja X-CustomerHero-Event-Id para que los clientes HTTP genéricos puedan deduplicar. |
Esquema de firma
La firma es hmac_sha256(secret, "<timestamp>.<cuerpo_crudo>"), codificada en hex. Usa el cuerpo crudo de la solicitud — re-serializar el JSON cambia los bytes y rompe la verificación. Rechaza solicitudes con un timestamp con más de 5 minutos de desfase respecto al reloj de tu servidor para evitar ataques de repetición.
Ejemplos de verificación
Cada fragmento parsea la cabecera de firma, recalcula el HMAC sobre t.body y compara en tiempo constante.
Node.js
const crypto = require('crypto');
function verify(rawBody, headers, secret) {
const sigHeader = headers['x-customerhero-signature'] || '';
const parts = Object.fromEntries(
sigHeader.split(',').map((p) => p.split('=')),
);
const ts = parts.t;
const v1 = parts.v1;
if (!ts || !v1) return false;
if (Math.abs(Date.now() / 1000 - Number(ts)) > 300) return false;
const expected = crypto
.createHmac('sha256', secret)
.update(`${ts}.${rawBody}`)
.digest('hex');
const a = Buffer.from(v1, 'hex');
const b = Buffer.from(expected, 'hex');
return a.length === b.length && crypto.timingSafeEqual(a, b);
}Python
import hmac, hashlib, time
def verify(raw_body: bytes, headers: dict, secret: str) -> bool:
sig_header = headers.get("X-CustomerHero-Signature", "")
parts = dict(p.split("=", 1) for p in sig_header.split(",") if "=" in p)
ts = parts.get("t")
v1 = parts.get("v1")
if not ts or not v1:
return False
if abs(time.time() - int(ts)) > 300:
return False
expected = hmac.new(
secret.encode(),
f"{ts}.".encode() + raw_body,
hashlib.sha256,
).hexdigest()
return hmac.compare_digest(v1, expected)Ruby
require 'openssl'
def verify(raw_body, headers, secret)
sig_header = headers['X-CustomerHero-Signature'].to_s
parts = sig_header.split(',').to_h { |p| p.split('=', 2) }
ts = parts['t']
v1 = parts['v1']
return false unless ts && v1
return false if (Time.now.to_i - ts.to_i).abs > 300
expected = OpenSSL::HMAC.hexdigest('SHA256', secret, "#{ts}.#{raw_body}")
Rack::Utils.secure_compare(v1, expected)
endPHP
<?php
function verify(string $rawBody, array $headers, string $secret): bool {
$sigHeader = $headers['X-CustomerHero-Signature'] ?? '';
$parts = [];
foreach (explode(',', $sigHeader) as $pair) {
[$k, $v] = array_pad(explode('=', $pair, 2), 2, null);
if ($k && $v) $parts[$k] = $v;
}
$ts = $parts['t'] ?? null;
$v1 = $parts['v1'] ?? null;
if (!$ts || !$v1) return false;
if (abs(time() - (int)$ts) > 300) return false;
$expected = hash_hmac('sha256', $ts . '.' . $rawBody, $secret);
return hash_equals($expected, $v1);
}Incrustación del widget
Añade el widget de chat a tu sitio web con un único script. Consulta la guía del Widget para ver todas las opciones de personalización.
<script
src="https://widget.customerhero.app/v1/loader.js"
data-chatbot-id="TU_CHATBOT_ID"
data-api-base="https://us.api.customerhero.app"
async
></script>Chatbots
Manage your chatbots — create, list, update, and delete.
Conversations
List, view, and update conversations. Manage tags and timeline.
Customers
Manage customer profiles — list, create, update, merge, and delete.
Companies
Manage company profiles and their contacts.
Data Sources
Add and manage training data for chatbots — URLs, text, Q&A, and files.
Channels
Configure messaging channels — widget, WhatsApp, email, and more.
Tags
Manage conversation tags for your organization.
Canned Responses
Manage reusable response templates.
API Keys
Manage API keys for programmatic access.
Team
Manage team members and invitations.