> ## Documentation Index
> Fetch the complete documentation index at: https://docs.jelou.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Mensajería

> Envía mensajes de WhatsApp desde tu función con ctx.jelou: texto, imágenes, botones, listas, carruseles, templates HSM y más.

## ¿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

```typescript theme={null}
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 };
}
```

<Warning>
  `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`.
</Warning>

## Enviar mensajes

### `ctx.jelou.send(options)`

Envía un mensaje individual. Retorna `{ messageId: string }`.

<Tabs>
  <Tab title="Texto">
    ```typescript theme={null}
    await ctx.jelou.send({
      type: "text",
      to: "+593987654321",
      text: "Tu pedido #1234 está en camino",
    });
    ```
  </Tab>

  <Tab title="Imagen">
    ```typescript theme={null}
    await ctx.jelou.send({
      type: "image",
      to: "+593987654321",
      mediaUrl: "https://cdn.example.com/producto.jpg",
      caption: "Producto: Laptop Dell XPS 15",
    });
    ```
  </Tab>

  <Tab title="Video">
    ```typescript theme={null}
    await ctx.jelou.send({
      type: "video",
      to: "+593987654321",
      mediaUrl: "https://cdn.example.com/tutorial.mp4",
      caption: "Tutorial de configuración",
    });
    ```
  </Tab>

  <Tab title="Archivo">
    ```typescript theme={null}
    await ctx.jelou.send({
      type: "file",
      to: "+593987654321",
      mediaUrl: "https://cdn.example.com/factura.pdf",
      filename: "factura-1234.pdf",
      caption: "Tu factura del mes de abril",
    });
    ```
  </Tab>

  <Tab title="Audio">
    ```typescript theme={null}
    await ctx.jelou.send({
      type: "audio",
      to: "+593987654321",
      mediaUrl: "https://cdn.example.com/mensaje.ogg",
    });
    ```
  </Tab>
</Tabs>

### Mensajes interactivos

<Tabs>
  <Tab title="Botones">
    ```typescript theme={null}
    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" },
      ],
    });
    ```
  </Tab>

  <Tab title="Lista">
    ```typescript theme={null}
    await ctx.jelou.send({
      type: "list",
      to: "+593987654321",
      text: "Selecciona una categoría de productos:",
      buttonText: "Ver categorías",
      sections: [
        {
          title: "Electrónica",
          rows: [
            { id: "laptops", title: "Laptops", description: "Portátiles y notebooks" },
            { id: "phones", title: "Teléfonos", description: "Smartphones y accesorios" },
          ],
        },
        {
          title: "Hogar",
          rows: [
            { id: "furniture", title: "Muebles" },
            { id: "kitchen", title: "Cocina" },
          ],
        },
      ],
    });
    ```
  </Tab>

  <Tab title="Quick Reply">
    ```typescript theme={null}
    await ctx.jelou.send({
      type: "quick_reply",
      to: "+593987654321",
      text: "¿Fue útil esta información?",
      replies: [
        { title: "Sí, gracias", payload: "helpful_yes" },
        { title: "No, necesito más ayuda", payload: "helpful_no" },
      ],
    });
    ```
  </Tab>

  <Tab title="CTA URL">
    ```typescript theme={null}
    await ctx.jelou.send({
      type: "cta_url",
      to: "+593987654321",
      text: "Completa tu compra en nuestra tienda:",
      displayText: "Ir a la tienda",
      url: "https://tienda.example.com/checkout/1234",
    });
    ```
  </Tab>
</Tabs>

### Mensajes avanzados

<Tabs>
  <Tab title="Ubicación">
    ```typescript theme={null}
    await ctx.jelou.send({
      type: "location",
      to: "+593987654321",
      lat: -2.1894,
      lng: -79.8891,
      name: "Tienda Guayaquil",
      address: "Av. 9 de Octubre 123, Guayaquil",
    });
    ```
  </Tab>

  <Tab title="Contactos">
    ```typescript theme={null}
    await ctx.jelou.send({
      type: "contacts",
      to: "+593987654321",
      contacts: [
        {
          name: { formatted_name: "Soporte Técnico", first_name: "Soporte" },
          phones: [{ phone: "+593912345678", type: "WORK" }],
        },
      ],
    });
    ```
  </Tab>

  <Tab title="Carrusel">
    ```typescript theme={null}
    await ctx.jelou.send({
      type: "carousel",
      to: "+593987654321",
      cards: [
        {
          mediaUrl: "https://cdn.example.com/laptop.jpg",
          body: "Laptop Dell XPS 15 — $1,299",
          buttons: [
            { id: "buy_laptop", title: "Comprar" },
            { id: "info_laptop", title: "Más info" },
          ],
        },
        {
          mediaUrl: "https://cdn.example.com/tablet.jpg",
          body: "iPad Pro 12.9\" — $999",
          buttons: [
            { id: "buy_tablet", title: "Comprar" },
            { id: "info_tablet", title: "Más info" },
          ],
        },
      ],
    });
    ```
  </Tab>

  <Tab title="Flow">
    ```typescript theme={null}
    await ctx.jelou.send({
      type: "flow",
      to: "+593987654321",
      text: "Completa tu registro:",
      flowId: "flow_abc123",
      flowCta: "Iniciar registro",
      flowAction: {
        screen: "REGISTER",
        data: { userId: "user-42" },
      },
    });
    ```
  </Tab>

  <Tab title="Sticker">
    ```typescript theme={null}
    await ctx.jelou.send({
      type: "sticker",
      to: "+593987654321",
      mediaUrl: "https://cdn.example.com/sticker.webp",
    });
    ```
  </Tab>
</Tabs>

## Enviar templates HSM

### `ctx.jelou.sendTemplate(options)`

Envía un template HSM aprobado por WhatsApp. Retorna `Array<{ id, destination }>`.

```typescript theme={null}
// Template básico
await ctx.jelou.sendTemplate({
  template: "confirmacion_pedido",
  to: "+593987654321",
  language: "es",
  params: ["María", "PED-1234", "$59.99"],
});
```

### Múltiples destinatarios

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

### Template con media

```typescript theme={null}
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:

```typescript theme={null}
await ctx.jelou.send({
  type: "text",
  to: "+593987654321",
  text: "Mensaje desde otro bot",
  botId: "bot-notificaciones-456",
});
```

## Manejo de errores

```typescript theme={null}
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:

```typescript theme={null}
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
```

<Card title="Testing completo" icon="flask-vial" href="/guides/functions/testing">
  Referencia de createMockJelouClient, createMockMemoryClient y más.
</Card>
