Resumen
Envía mensajes de WhatsApp desde tu sistema con tu propio número: confirmaciones de pedido, comprobantes en PDF, recordatorios de pago o avisos de despacho. Y recibe en tu sistema lo que te responden tus clientes.
- Vinculas tu número una sola vez escaneando un QR en el portal (como WhatsApp Web).
- Tu sistema llama a la API con tu token.
- El mensaje sale desde tu número; tu celular sigue funcionando normal.
URL base: https://whatsapp.holainge.com · Comprueba que responde: GET https://whatsapp.holainge.com/salud
Antes de empezar
- Contrata un plan de la API WhatsApp.
- En Mis suscripciones > API WhatsApp pulsa Vincular número y escanea el QR desde WhatsApp > Dispositivos vinculados.
- Crea un token de Desarrollo para integrar sin enviar nada, y uno de Pruebas para enviarte mensajes a ti mismo.
- Cuando todo funcione, crea un token de Producción.
Entornos
| Entorno del token | Qué pasa al enviar | Consumo |
|---|---|---|
| Desarrollo | No se envía nada a WhatsApp. La respuesta es real pero con estado Simulado. Ideal para programar. | Límite de pruebas |
| Pruebas | Se envía de verdad, solo a tu propio número vinculado. | Límite de pruebas |
| Producción | Se envía a cualquier número. | Límite mensual del plan |
Cada mensaje aceptado cuenta 1 en el consumo del mes. Si WhatsApp lo rechaza (por ejemplo, el número no existe), no se cuenta.
Endpoints
| Método | Ruta | Descripción |
|---|---|---|
| POST | /api/v1/mensajes/texto | Envía un mensaje de texto. |
| POST | /api/v1/mensajes/imagen | Envía una imagen (JPG, PNG o WEBP) con texto opcional. |
| POST | /api/v1/mensajes/documento | Envía un documento (PDF, XML, Excel, Word, ZIP...). |
| GET | /api/v1/mensajes/{id} | Consulta un mensaje y su estado (enviado, entregado, leído). |
| GET | /api/v1/mensajes?cantidad=50 | Últimos mensajes del entorno del token. |
| GET | /api/v1/estado | Verifica el token y si tu número está conectado. |
Todas las rutas exigen la cabecera Authorization: Bearer <token>. Puedes enviar Idempotency-Key: <tu-id> para reintentar sin duplicar: con la misma clave te devolvemos el mismo mensaje (si el envío falló, la clave se libera para que puedas reintentar).
Enviar texto
curl -X POST https://whatsapp.holainge.com/api/v1/mensajes/texto \
-H "Authorization: Bearer inr_..." \
-H "Content-Type: application/json" \
-H "Idempotency-Key: pedido-1520-confirmacion" \
-d '{
"numero": "51924246085",
"texto": "Hola Juan, tu pedido #1520 fue confirmado. Llegará mañana entre 9 y 12."
}'
numero: con código de país (Perú:51+ 9 dígitos). También aceptamos924246085o+51 924 246 085.texto: hasta 4096 caracteres. Admite el formato de WhatsApp:*negrita*,_cursiva_, emojis y saltos de línea (\n).
Enviar imagen o PDF
Envía el archivo de una de estas dos formas (no ambas):
url: dirección https pública del archivo; nosotros lo descargamos.base64: el contenido del archivo en Base64 (connombreArchivosi es documento).
Tamaño máximo: 8 MB.
{
"numero": "51924246085",
"url": "https://tusistema.com/comprobantes/F001-123.pdf",
"nombreArchivo": "F001-123.pdf",
"texto": "Hola Juan, te enviamos tu factura F001-123. ¡Gracias por tu compra!"
}
{
"numero": "51924246085",
"base64": "iVBORw0KGgoAAAANSUhEUgAA...",
"texto": "Así quedó tu pedido 📦"
}
Respuesta y estados
201 si el mensaje se envió (o se simuló), 200 si es una repetición con la misma Idempotency-Key, 422 si WhatsApp lo rechazó:
{
"id": 1520,
"tipo": "texto",
"numero": "51924246085",
"entorno": "Produccion",
"estado": "Enviado",
"error": null,
"fecha": "2026-11-14T10:30:00-05:00",
"actualizadoEn": "2026-11-14T10:30:02-05:00",
"repetido": false
}
| Estado | Significado |
|---|---|
Enviado | WhatsApp recibió el mensaje. |
Entregado | Llegó al celular del destinatario (dos checks). |
Leido | El destinatario lo abrió (checks azules; solo si tiene activada la confirmación de lectura). |
Simulado | Token de Desarrollo: no se envió. |
Error | No se envió. El campo error explica por qué (ej. "Ese número no tiene WhatsApp"). |
Si tu número no está conectado, la API responde 400 con regla_negocio y no cuenta consumo.
Estado del número
{
"api": "WHATSAPP",
"entorno": "Produccion",
"descripcionEntorno": "Producción: se envían a cualquier número.",
"conectado": true,
"estadoNumero": "Conectado",
"numero": "51924246085",
"limiteSolicitudesMinuto": 10,
"limiteMensual": 3000,
"horaServidor": "2026-11-14T10:30:00-05:00"
}
estadoNumero: SinVincular, EsperandoQr, Conectado o Desconectado.
Webhook
Configura tu URL en Mis suscripciones > API WhatsApp > Webhook. Te enviamos un POST con JSON en cada evento. Responde con cualquier código 2xx en menos de 10 segundos; si no, reintentamos a los 1, 5, 15, 60 y 240 minutos.
| Evento | Cuándo |
|---|---|
mensaje.recibido | Un cliente te escribió. |
mensaje.estado | Un mensaje que enviaste fue entregado o leído. |
conexion | Tu número se conectó o se desconectó. |
prueba | Pulsaste "Enviar evento de prueba" en el portal. |
mensaje.recibido
{
"evento": "mensaje.recibido",
"fecha": "2026-11-14T10:31:00-05:00",
"datos": {
"id": "3EB0C767D26A8B1F",
"de": "51987654321",
"nombre": "Juan Pérez",
"tipo": "texto",
"texto": "Hola, ¿a qué hora llega mi pedido?",
"fechaMensaje": "2026-11-14T10:30:58-05:00"
}
}
tipo: texto, imagen, documento, audio, video, sticker, ubicacion, contacto, reaccion u otro. Los mensajes de grupos no se reenvían.
mensaje.estado
{ "evento": "mensaje.estado", "fecha": "...", "datos": { "id": 1520, "estado": "Leido" } }
conexion
{ "evento": "conexion", "fecha": "...", "datos": { "conectado": false, "numero": "51924246085" } }
Validar la firma
Cada aviso trae estas cabeceras:
X-Inercia-Evento: el tipo de evento.X-Inercia-Id: identificador único del aviso (úsalo para ignorar repetidos).X-Inercia-Marca-Tiempo: hora Unix en segundos.X-Inercia-Firma:HEX( HMAC-SHA256( secreto, marcaTiempo + "." + cuerpo ) )en minúsculas.
Calcula la firma con el cuerpo tal como llegó (sin volver a serializar el JSON) y compárala. Rechaza avisos con una marca de tiempo de más de 5 minutos.
// ASP.NET Core (C#)
app.MapPost("/webhooks/whatsapp", async (HttpRequest req) =>
{
using var lector = new StreamReader(req.Body);
var cuerpo = await lector.ReadToEndAsync();
var marca = req.Headers["X-Inercia-Marca-Tiempo"].ToString();
var firma = req.Headers["X-Inercia-Firma"].ToString();
var secreto = Environment.GetEnvironmentVariable("INERCIA_WEBHOOK_SECRETO")!;
var esperada = Convert.ToHexString(HMACSHA256.HashData(
Encoding.UTF8.GetBytes(secreto), Encoding.UTF8.GetBytes($"{marca}.{cuerpo}"))).ToLowerInvariant();
if (!CryptographicOperations.FixedTimeEquals(Encoding.UTF8.GetBytes(esperada), Encoding.UTF8.GetBytes(firma))
|| Math.Abs(DateTimeOffset.UtcNow.ToUnixTimeSeconds() - long.Parse(marca)) > 300)
return Results.Unauthorized();
// ... procesa el evento (en segundo plano si tarda) ...
return Results.Ok();
});
// Node.js (Express): usa express.raw para tener el cuerpo original
app.post("/webhooks/whatsapp", express.raw({ type: "application/json" }), (req, res) => {
const marca = req.get("X-Inercia-Marca-Tiempo");
const esperada = crypto.createHmac("sha256", process.env.INERCIA_WEBHOOK_SECRETO)
.update(`${marca}.${req.body}`).digest("hex");
if (esperada !== req.get("X-Inercia-Firma")) return res.sendStatus(401);
const evento = JSON.parse(req.body);
res.sendStatus(200);
});
Ejemplo en C#
using System.Net.Http.Json;
var http = new HttpClient { BaseAddress = new Uri("https://whatsapp.holainge.com/") };
http.DefaultRequestHeaders.Authorization = new("Bearer", Environment.GetEnvironmentVariable("INERCIA_TOKEN"));
var solicitud = new HttpRequestMessage(HttpMethod.Post, "api/v1/mensajes/texto")
{
Content = JsonContent.Create(new { numero = "51924246085", texto = "Tu pedido #1520 está en camino 🚚" })
};
solicitud.Headers.Add("Idempotency-Key", "pedido-1520-despacho");
var respuesta = await http.SendAsync(solicitud);
var cuerpo = await respuesta.Content.ReadAsStringAsync();
Console.WriteLine($"{(int)respuesta.StatusCode}: {cuerpo}");
Buenas prácticas (evita bloqueos)
Esta API conecta tu número como un dispositivo vinculado. WhatsApp puede bloquear números que se comportan como spam, así que:
- Usa un número dedicado a tu negocio, con su foto y nombre de perfil.
- Escribe solo a clientes que te dieron su número y esperan tu mensaje (pedidos, comprobantes, citas, cobranzas).
- No envíes publicidad masiva ni a listas compradas.
- Personaliza los mensajes (nombre, número de pedido) en lugar de enviar el mismo texto a todos.
- Respeta el límite por minuto de tu plan: ya añadimos una pequeña pausa entre envíos para que se parezcan a los de una persona.
- Si un cliente pide que no le escribas más, quítalo de tus envíos.
Estas reglas forman parte de las condiciones de uso del servicio API WhatsApp que aceptaste al registrarte.