Guia para avanzados

Patrones, webhooks, manejo de errores, rate limits y optimizaciones para llevar tu integracion a produccion.

Arquitectura recomendada

Para alta disponibilidad y observabilidad:

Webhooks firmados

Cuando configuras un webhook con secret, cada request llega con un header X-WAAPI-Signature con un HMAC-SHA256 del body:

$body = file_get_contents('php://input');
$signature = $_SERVER['HTTP_X_WAAPI_SIGNATURE'] ?? '';
$expected = hash_hmac('sha256', $body, $secret);
if (!hash_equals($expected, $signature)) {
    http_response_code(401);
    exit('Firma invalida');
}
// OK, procesar evento

Eventos disponibles

Rate limits y backoff

Por default, con account_protection: false en la sesion del servidor, puedes mandar hasta 256 mensajes/min por celular. Si excedes, recibes un 429 con retry_after en el body.

Patron de retry con exponential backoff

function enviar_con_retry($params, $max_intentos = 5) {
    for ($i = 0; $i < $max_intentos; $i++) {
        $response = enviar($params);
        if ($response['ok']) return $response;
        if ($response['status'] === 429) {
            $wait = $response['retry_after'] ?? 5;
            sleep($wait);
        } elseif ($response['status'] >= 500) {
            sleep(pow(2, $i));  // 1, 2, 4, 8, 16 segundos
        } else {
            return $response;  // 4xx no recuperable
        }
    }
    return ['ok' => false, 'error' => 'max_intentos_exceeded'];
}

Idempotencia

Si reintentas un mensaje con el mismo msg_id, el sistema lo detecta y no lo duplica. Esto es util cuando tu worker crashea a mitad de envio.

Modo directo vs cola

Los 11 endpoints de envio (texto + 5 medios + 5 base64) soportan 2 modos:

Cola humanizada (default, recomendado para el 90% de los casos)

Por default, los mensajes se encolan y un worker los envia en los proximos segundos. Esto es lo que parece mas humano a ojos de WhatsApp: el trafico se distribuye en el tiempo en lugar de llegar todo junto.

Ventajas:

Modo directo (directo=1, para tiempo real)

Si necesitas envio instantaneo, agrega "directo": 1 al body. La API llama a WhatsApp al instante y registra el resultado como enviado en tu historial.

Casos de uso:

NO uses este modo para:

Comportamiento en errores:

Ejemplo: sistema 2FA

import requests, random

def enviar_otp(destinatario, codigo):
    return requests.post(
        'https://api.multimensajes.com/api/mensaje_enviar_texto.php',
        headers={'Authorization': 'Bearer WA_8_a1b2c3d4e5f6...'},
        json={
            'destinatario': destinatario,
            'mensaje': f'Tu codigo de verificacion es: {codigo}. Valido por 5 min.',
            'directo': 1,  # envio instantaneo
        },
        timeout=10,
    ).json()

# Generar codigo aleatorio unico
codigo = str(random.randint(100000, 999999))
resp = enviar_otp('5218711281619', codigo)
if resp['ok']:
    print(f"Enviado en modo {resp['modo']} con id {resp['msg_id']}")
else:
    print(f"Error: {resp['error']}")

Ejemplo: envio masivo (cola, 1 llamada por mensaje)

import requests
import time

clientes = [
    {'tel': '5218711281619', 'nombre': 'Juan', 'pedido': '004827'},
    {'tel': '5218711281619', 'nombre': 'Maria', 'pedido': '004828'},
    # ...
]

for cli in clientes:
    # Cada mensaje es UNICO (personalizado)
    mensaje = f"Hola {cli['nombre']}, tu pedido {cli['pedido']} esta listo. Gracias por tu compra."
    requests.post(
        'https://api.multimensajes.com/api/mensaje_enviar_texto.php',
        headers={'Authorization': 'Bearer WA_8_a1b2c3d4e5f6...'},
        json={
            'destinatario': cli['tel'],
            'mensaje': mensaje,
            # NO 'directo' = cola humanizada
        },
    )
    time.sleep(0.1)  # 10 msg/seg en el front, la cola los distribuye a 1 cada 5s en el back

Envio de archivos pesados

Tienes 2 opciones para cada tipo (imagen, documento, audio, video, sticker):

Opcion A: Por URL publica

La URL del archivo debe cumplir:

Opcion B: Por base64 (recomendado para contenido dinamico)

Los endpoints con sufijo _base64 aceptan el archivo directamente codificado. El sistema lo guarda temporalmente (24h) en /storage/uploads/, lo sube a WhatsApp, y luego un cron lo limpia.

Ventajas sobre URL:

Limites base64: imagen 16MB, documento 50MB, audio 16MB, video 50MB, sticker 1MB.

Acepta data URI (data:image/png;base64,iVBOR...) o base64 puro.

Ejemplo: enviar una imagen generada con PIL a partir de un texto:

import base64, requests
from PIL import Image, ImageDraw

# Generar imagen en memoria
img = Image.new('RGB', (800, 400), color=(99, 102, 241))
d = ImageDraw.Draw(img)
d.text((50, 180), 'Hola desde MultiMensajes', fill='white')
buf = __import__('io').BytesIO()
img.save(buf, format='PNG')

# Convertir a base64 y enviar
img_b64 = base64.b64encode(buf.getvalue()).decode()
r = requests.post(
    'https://api.multimensajes.com/api/mensaje_enviar_imagen_base64.php',
    headers={'Authorization': 'Bearer WA_8_a1b2c3d4e5f6...'},
    json={
        'destinatario': '5218711281619',
        'imageBase64': img_b64,
        'mime': 'image/png',
        'caption': 'Imagen generada al vuelo',
    },
    timeout=30,
)
print(r.json())

Validacion de numeros

Todos los numeros deben estar en formato internacional sin el signo +:

El sistema rechaza numeros que no tengan al menos 10 digitos.

Monitoreo

Para integrar con tus dashboards:

Seguridad

SDKs y librerias

La API es REST pura — no necesitas un SDK. Pero si quieres generar uno para tu lenguaje favorito, importa el OpenAPI 3.0 en openapi-generator o Swagger Codegen.

Casos de uso comunes

Anti-spam: WhatsApp suspende cuentas que mandan mensajes no solicitados. Configura horarios (8 AM - 10 PM default), pide opt-in, y siempre permite al destinatario escribir "BAJA" para desuscribirse.

Proteccion anti-duplicado y anti-baneo (detalle)

La API implementa 3 capas de proteccion para mantener tu cuenta sana:

  1. Cola humanizada (capa 1): default. Distribuye el trafico en el tiempo.
  2. Anti-duplicado con cache en memoria (capa 2): rechaza el mismo mensaje 3 veces en 2 minutos (bloqueo 5 min).
  3. Rate limit del servidor (capa 3): hasta 256 msg/min por sesion. Si excedes, 429 con retry_after.

Como se calcula el hash de duplicado

El hash es diferente por tipo de mensaje e incluye destinatario + celular. Asi un cliente NO puede afectar a otro.

Si te banean igual (queja formal a WhatsApp)

Si tu cuenta de WhatsApp fue suspendida por spam (raro si respetas las reglas), puedes apelar en whatsapp.com/contact. Adjunta pruebas de que tus destinatarios dieron opt-in.