Saltar al contenido principal

¿Qué es ctx.jelou?

ctx.jelou es el cliente de mensajería integrado. Permite enviar mensajes de WhatsApp directamente desde tu función sin configurar APIs externas. Está disponible automáticamente cuando la empresa tiene credenciales de la API de Jelou configuradas.

Verificar disponibilidad

handler: async (input, ctx) => {
  if (!ctx.jelou.available) {
    return { error: "Mensajería no configurada para esta empresa" };
  }

  await ctx.jelou.send({ type: "text", to: input.telefono, text: "Hola" });
  return { enviado: true };
}
ctx.jelou.available es false cuando la empresa no tiene clientId/clientSecret configurados. Llamar a send() o sendTemplate() en un cliente no disponible lanza un Error.

Enviar mensajes

ctx.jelou.send(options)

Envía un mensaje individual. Retorna { messageId: string }.
await ctx.jelou.send({
  type: "text",
  to: "+593987654321",
  text: "Tu pedido #1234 está en camino",
});

Mensajes interactivos

await ctx.jelou.send({
  type: "buttons",
  to: "+593987654321",
  text: "¿Cómo deseas recibir tu pedido?",
  buttons: [
    { id: "delivery", title: "Envío a domicilio" },
    { id: "pickup", title: "Retiro en tienda" },
    { id: "express", title: "Envío express" },
  ],
});

Mensajes avanzados

await ctx.jelou.send({
  type: "location",
  to: "+593987654321",
  lat: -2.1894,
  lng: -79.8891,
  name: "Tienda Guayaquil",
  address: "Av. 9 de Octubre 123, Guayaquil",
});

Enviar templates HSM

ctx.jelou.sendTemplate(options)

Envía un template HSM aprobado por WhatsApp. Retorna Array<{ id, destination }>.
// Template básico
await ctx.jelou.sendTemplate({
  template: "confirmacion_pedido",
  to: "+593987654321",
  language: "es",
  params: ["María", "PED-1234", "$59.99"],
});

Múltiples destinatarios

await ctx.jelou.sendTemplate({
  template: "promocion_mensual",
  to: ["+593987654321", "+593912345678", "+593998765432"],
  language: "es",
  params: ["20%", "30 de abril"],
});

Template con media

await ctx.jelou.sendTemplate({
  template: "recibo_pago",
  to: "+593987654321",
  language: "es",
  params: ["$150.00"],
  mediaUrl: "https://cdn.example.com/recibo-1234.pdf",
  filename: "recibo.pdf",
});

Override de bot

Todos los mensajes usan ctx.bot.id por defecto. Para enviar desde otro bot:
await ctx.jelou.send({
  type: "text",
  to: "+593987654321",
  text: "Mensaje desde otro bot",
  botId: "bot-notificaciones-456",
});

Manejo de errores

import { JelouApiError } from "@jelou/functions";

try {
  await ctx.jelou.send({ type: "text", to: "+593987654321", text: "Hola" });
} catch (err) {
  if (err instanceof JelouApiError) {
    if (err.isRateLimit()) {
      ctx.log("Rate limit", { retryAfter: 2 });
      return { error: "rate_limit" };
    }
    if (err.isAuth()) {
      ctx.log("Credenciales inválidas", { status: err.status });
      return { error: "auth_error" };
    }
    if (err.isValidation()) {
      ctx.log("Datos inválidos", { status: err.status, code: err.code });
      return { error: "validation_error" };
    }
  }
  throw err;
}

Testing

Usa createMockJelouClient() para testing sin enviar mensajes reales:
import { createMockContext, createMockJelouClient } from "@jelou/functions/testing";

const mockJelou = createMockJelouClient();
const ctx = createMockContext({ jelou: mockJelou });

await ctx.jelou.send({ type: "text", to: "+593987654321", text: "Test" });

mockJelou.calls.length;       // 1
mockJelou.calls[0].method;    // "send"
mockJelou.calls[0].args.text; // "Test"
mockJelou.reset();             // limpia las llamadas

Testing completo

Referencia de createMockJelouClient, createMockMemoryClient y más.