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

# Enviar lista

> Envía un menú interactivo con secciones y opciones seleccionables

**Auth:** `TokenAccount` o `TokenInstance` • **Rate-limit:** `Global` (100/min) • **Idempotente:** no

## Descripción

Envía una **lista interactiva** con hasta **10 secciones** y **10 filas** por sección (límite global de **100 filas** entre todas las secciones). El destinatario toca el botón (`buttonText`) para abrir el menú y elegir una de las opciones, y WhatsApp retorna el `id` de la fila seleccionada como un mensaje de respuesta. Ideal para menús, catálogos cortos, FAQs guiadas y soporte estructurado.

## Ejemplos

### Lista simple (1 sección)

Un menú lean con una única sección "Dishes" y dos filas. El destinatario toca "See options" para abrir el menú y seleccionar una de las opciones, que regresa como una respuesta cargando el `id` (`p1` o `p2`).

<CodeGroup>
  ```bash cURL theme={null}
  curl -X POST "https://ryzeapi.cloud/api/message/list/$Instance_Name" \
    -H "token: $Token_Instance" \
    -H "Content-Type: application/json" \
    -d '{
      "number":      "5511999999999",
      "contentText": "Pick an item from the menu:",
      "buttonText":  "See options",
      "sections": [
        {
          "title": "Dishes",
          "rows": [
            { "id": "p1", "title": "Lasagna", "description": "Bolognese, 4 slices" },
            { "id": "p2", "title": "Risotto", "description": "Mushroom" }
          ]
        }
      ]
    }'
  ```

  ```javascript JavaScript theme={null}
  await fetch(`https://ryzeapi.cloud/api/message/list/${process.env.Instance_Name}`, {
    method: "POST",
    headers: {
      "token":        process.env.Token_Instance,
      "Content-Type": "application/json"
    },
    body: JSON.stringify({
      number:      "5511999999999",
      contentText: "Pick an item from the menu:",
      buttonText:  "See options",
      sections: [
        {
          title: "Dishes",
          rows: [
            { id: "p1", title: "Lasagna", description: "Bolognese, 4 slices" },
            { id: "p2", title: "Risotto", description: "Mushroom" }
          ]
        }
      ]
    })
  });
  ```

  ```python Python theme={null}
  import os, requests

  requests.post(
      f"https://ryzeapi.cloud/api/message/list/{os.environ['Instance_Name']}",
      headers={
          "token":        os.environ["Token_Instance"],
          "Content-Type": "application/json"
      },
      json={
          "number":      "5511999999999",
          "contentText": "Pick an item from the menu:",
          "buttonText":  "See options",
          "sections": [
              {
                  "title": "Dishes",
                  "rows": [
                      {"id": "p1", "title": "Lasagna", "description": "Bolognese, 4 slices"},
                      {"id": "p2", "title": "Risotto", "description": "Mushroom"}
                  ]
              }
          ]
      }
  )
  ```

  ```go Go theme={null}
  package main

  import (
      "net/http"
      "os"
      "strings"
  )

  func main() {
      body := strings.NewReader(`{
          "number":      "5511999999999",
          "contentText": "Pick an item from the menu:",
          "buttonText":  "See options",
          "sections": [
              {
                  "title": "Dishes",
                  "rows": [
                      { "id": "p1", "title": "Lasagna", "description": "Bolognese, 4 slices" },
                      { "id": "p2", "title": "Risotto", "description": "Mushroom" }
                  ]
              }
          ]
      }`)
      req, _ := http.NewRequest("POST", "https://ryzeapi.cloud/api/message/list/"+os.Getenv("Instance_Name"), body)
      req.Header.Set("token", os.Getenv("Token_Instance"))
      req.Header.Set("Content-Type", "application/json")
      http.DefaultClient.Do(req)
  }
  ```
</CodeGroup>

### Menú multi-sección (categorías)

Una lista con múltiples categorías agrupadas en secciones. Cada sección se renderiza con su propio encabezado dentro del menú, separando visualmente los grupos.

<CodeGroup>
  ```bash cURL theme={null}
  curl -X POST "https://ryzeapi.cloud/api/message/list/$Instance_Name" \
    -H "token: $Token_Instance" \
    -H "Content-Type: application/json" \
    -d '{
      "number":      "5511999999999",
      "contentText": "Full menu. Choose an option:",
      "buttonText":  "Open menu",
      "sections": [
        {
          "title": "Main dishes",
          "rows": [
            { "id": "p1", "title": "Lasagna", "description": "Bolognese, 4 slices" },
            { "id": "p2", "title": "Risotto", "description": "Mushroom" },
            { "id": "p3", "title": "Salmon",  "description": "Grilled with vegetables" }
          ]
        },
        {
          "title": "Drinks",
          "rows": [
            { "id": "b1", "title": "Natural juice" },
            { "id": "b2", "title": "Soda" }
          ]
        },
        {
          "title": "Desserts",
          "rows": [
            { "id": "s1", "title": "Pudding" },
            { "id": "s2", "title": "Ice cream", "description": "3 flavors" }
          ]
        }
      ]
    }'
  ```

  ```javascript JavaScript theme={null}
  await fetch(`https://ryzeapi.cloud/api/message/list/${process.env.Instance_Name}`, {
    method: "POST",
    headers: {
      "token":        process.env.Token_Instance,
      "Content-Type": "application/json"
    },
    body: JSON.stringify({
      number:      "5511999999999",
      contentText: "Full menu. Choose an option:",
      buttonText:  "Open menu",
      sections: [
        {
          title: "Main dishes",
          rows: [
            { id: "p1", title: "Lasagna", description: "Bolognese, 4 slices" },
            { id: "p2", title: "Risotto", description: "Mushroom" },
            { id: "p3", title: "Salmon",  description: "Grilled with vegetables" }
          ]
        },
        {
          title: "Drinks",
          rows: [
            { id: "b1", title: "Natural juice" },
            { id: "b2", title: "Soda" }
          ]
        },
        {
          title: "Desserts",
          rows: [
            { id: "s1", title: "Pudding" },
            { id: "s2", title: "Ice cream", description: "3 flavors" }
          ]
        }
      ]
    })
  });
  ```

  ```python Python theme={null}
  import os, requests

  requests.post(
      f"https://ryzeapi.cloud/api/message/list/{os.environ['Instance_Name']}",
      headers={
          "token":        os.environ["Token_Instance"],
          "Content-Type": "application/json"
      },
      json={
          "number":      "5511999999999",
          "contentText": "Full menu. Choose an option:",
          "buttonText":  "Open menu",
          "sections": [
              {
                  "title": "Main dishes",
                  "rows": [
                      {"id": "p1", "title": "Lasagna", "description": "Bolognese, 4 slices"},
                      {"id": "p2", "title": "Risotto", "description": "Mushroom"},
                      {"id": "p3", "title": "Salmon",  "description": "Grilled with vegetables"}
                  ]
              },
              {
                  "title": "Drinks",
                  "rows": [
                      {"id": "b1", "title": "Natural juice"},
                      {"id": "b2", "title": "Soda"}
                  ]
              },
              {
                  "title": "Desserts",
                  "rows": [
                      {"id": "s1", "title": "Pudding"},
                      {"id": "s2", "title": "Ice cream", "description": "3 flavors"}
                  ]
              }
          ]
      }
  )
  ```

  ```go Go theme={null}
  package main

  import (
      "net/http"
      "os"
      "strings"
  )

  func main() {
      body := strings.NewReader(`{
          "number":      "5511999999999",
          "contentText": "Full menu. Choose an option:",
          "buttonText":  "Open menu",
          "sections": [
              {
                  "title": "Main dishes",
                  "rows": [
                      { "id": "p1", "title": "Lasagna", "description": "Bolognese, 4 slices" },
                      { "id": "p2", "title": "Risotto", "description": "Mushroom" },
                      { "id": "p3", "title": "Salmon",  "description": "Grilled with vegetables" }
                  ]
              },
              {
                  "title": "Drinks",
                  "rows": [
                      { "id": "b1", "title": "Natural juice" },
                      { "id": "b2", "title": "Soda" }
                  ]
              },
              {
                  "title": "Desserts",
                  "rows": [
                      { "id": "s1", "title": "Pudding" },
                      { "id": "s2", "title": "Ice cream", "description": "3 flavors" }
                  ]
              }
          ]
      }`)
      req, _ := http.NewRequest("POST", "https://ryzeapi.cloud/api/message/list/"+os.Getenv("Instance_Name"), body)
      req.Header.Set("token", os.Getenv("Token_Instance"))
      req.Header.Set("Content-Type", "application/json")
      http.DefaultClient.Do(req)
  }
  ```
</CodeGroup>

### Lista con encabezado y pie

Agrega `headerText` (título sobre el cuerpo) y `footerText` (texto en gris debajo del botón), útil para branding y disclaimers cortos.

<CodeGroup>
  ```bash cURL theme={null}
  curl -X POST "https://ryzeapi.cloud/api/message/list/$Instance_Name" \
    -H "token: $Token_Instance" \
    -H "Content-Type: application/json" \
    -d '{
      "number":      "5511999999999",
      "headerText":  "RyzeAPI Support",
      "contentText": "How can we help you today?",
      "footerText":  "24/7 support",
      "buttonText":  "See options",
      "sections": [
        {
          "title": "Support",
          "rows": [
            { "id": "sup_tec",  "title": "Technical support" },
            { "id": "sup_fin",  "title": "Billing" },
            { "id": "sup_com",  "title": "Sales",   "description": "Talk to sales" }
          ]
        }
      ]
    }'
  ```

  ```javascript JavaScript theme={null}
  await fetch(`https://ryzeapi.cloud/api/message/list/${process.env.Instance_Name}`, {
    method: "POST",
    headers: {
      "token":        process.env.Token_Instance,
      "Content-Type": "application/json"
    },
    body: JSON.stringify({
      number:      "5511999999999",
      headerText:  "RyzeAPI Support",
      contentText: "How can we help you today?",
      footerText:  "24/7 support",
      buttonText:  "See options",
      sections: [
        {
          title: "Support",
          rows: [
            { id: "sup_tec", title: "Technical support" },
            { id: "sup_fin", title: "Billing" },
            { id: "sup_com", title: "Sales", description: "Talk to sales" }
          ]
        }
      ]
    })
  });
  ```

  ```python Python theme={null}
  import os, requests

  requests.post(
      f"https://ryzeapi.cloud/api/message/list/{os.environ['Instance_Name']}",
      headers={
          "token":        os.environ["Token_Instance"],
          "Content-Type": "application/json"
      },
      json={
          "number":      "5511999999999",
          "headerText":  "RyzeAPI Support",
          "contentText": "How can we help you today?",
          "footerText":  "24/7 support",
          "buttonText":  "See options",
          "sections": [
              {
                  "title": "Support",
                  "rows": [
                      {"id": "sup_tec", "title": "Technical support"},
                      {"id": "sup_fin", "title": "Billing"},
                      {"id": "sup_com", "title": "Sales", "description": "Talk to sales"}
                  ]
              }
          ]
      }
  )
  ```

  ```go Go theme={null}
  package main

  import (
      "net/http"
      "os"
      "strings"
  )

  func main() {
      body := strings.NewReader(`{
          "number":      "5511999999999",
          "headerText":  "RyzeAPI Support",
          "contentText": "How can we help you today?",
          "footerText":  "24/7 support",
          "buttonText":  "See options",
          "sections": [
              {
                  "title": "Support",
                  "rows": [
                      { "id": "sup_tec", "title": "Technical support" },
                      { "id": "sup_fin", "title": "Billing" },
                      { "id": "sup_com", "title": "Sales", "description": "Talk to sales" }
                  ]
              }
          ]
      }`)
      req, _ := http.NewRequest("POST", "https://ryzeapi.cloud/api/message/list/"+os.Getenv("Instance_Name"), body)
      req.Header.Set("token", os.Getenv("Token_Instance"))
      req.Header.Set("Content-Type", "application/json")
      http.DefaultClient.Do(req)
  }
  ```
</CodeGroup>

## Respuesta exitosa

El `content` retornado es el `contentText` que enviaste, y `messageType` es fijo en `list`. Guarda el `messageId` para correlacionar con los eventos de selección que llegan vía webhook.

```json 200 OK theme={null}
{
  "success": true,
  "message": "List message sent successfully",
  "status":  "sent",
  "data": {
    "messageId":   "3EB08FCF27E532F1B0F5",
    "direction":   "sent",
    "messageType": "list",
    "content":     "Pick an item from the menu:",
    "source":      "api",
    "timestamp":   "2026-04-30T14:30:00Z",
    "chat": {
      "jid":     "5511999999999@s.whatsapp.net",
      "isGroup": false
    },
    "sender": {
      "jid":      "5511777777777@s.whatsapp.net",
      "instance": "minha-instancia"
    }
  }
}
```

<Note>
  Cuando el destinatario elige una opción, WhatsApp envía un mensaje de respuesta que contiene el `id` de la fila seleccionada, captura esa respuesta vía webhook/websocket de eventos para continuar el flujo.
</Note>

## Parámetros de ruta

<ParamField path="instance" type="string" required>
  Nombre de la instancia (p. ej., `$Instance_Name`).
</ParamField>

## Cabeceras

<ParamField header="token" type="string" required>
  `TokenAccount` o `TokenInstance`.
</ParamField>

<ParamField header="Content-Type" type="string" required>
  `application/json`
</ParamField>

## Cuerpo de la solicitud

<ParamField body="number" type="string" required>
  Destino: teléfono (`5511999999999`) o JID (`@s.whatsapp.net`, `@lid`, `@g.us`, `@newsletter`).
</ParamField>

<ParamField body="contentText" type="string" required>
  Cuerpo principal del mensaje (descripción). Aparece sobre el botón que abre la lista.
</ParamField>

<ParamField body="buttonText" type="string" required>
  Texto del botón que abre la lista (p. ej., `"See options"`, `"Open menu"`). Limitado por WhatsApp a unos pocos caracteres.
</ParamField>

<ParamField body="sections" type="ListSection[]" required>
  Array de **1 a 10 secciones**. El número total de filas entre todas las secciones no puede exceder **100**.

  <Expandable title="ListSection">
    <ParamField body="title" type="string" required>
      Título de la sección (encabezado de grupo dentro del menú).
    </ParamField>

    <ParamField body="rows" type="ListRow[]" required>
      Array de **1 a 10 filas** por sección.

      <Expandable title="ListRow">
        <ParamField body="id" type="string" required>
          Identificador único de la fila. Es el valor que regresa como respuesta cuando el usuario selecciona esta opción.
        </ParamField>

        <ParamField body="title" type="string" required>
          Título mostrado para la opción.
        </ParamField>

        <ParamField body="description" type="string">
          Texto secundario en gris, debajo del título.
        </ParamField>
      </Expandable>
    </ParamField>
  </Expandable>
</ParamField>

<ParamField body="headerText" type="string">
  Título mostrado sobre `contentText`. Opcional.
</ParamField>

<ParamField body="footerText" type="string">
  Texto en gris claro debajo del botón. Opcional, ideal para disclaimers cortos.
</ParamField>

<ParamField body="delay" type="int" default="0">
  Tiempo en **segundos** a esperar antes de enviar. Durante el intervalo, el servidor envía el indicador "escribiendo..." al destinatario y dispara "pausado" antes del envío real.
</ParamField>

<ParamField body="replyTo" type="string">
  ID del mensaje a citar (respuesta). El mensaje original debe pertenecer a la misma instancia y haber sido guardado en la base de datos.
</ParamField>

<ParamField body="replyPrivate" type="boolean" default="false">
  Cuando es `true` **y** `replyTo` apunta a un mensaje originado en un grupo, la respuesta se redirige al chat **privado** del autor original (manteniendo la cita).
</ParamField>

<ParamField body="source" type="string" default="api">
  Identificador de origen para trazabilidad (p. ej., `crm`, `bot-suporte`, `n8n`). Guardado en el registro del mensaje en la base de datos y propagado a los webhooks.
</ParamField>

## Notas

<Note>
  * **Límites de WhatsApp:** máximo de **10 secciones**, **10 filas por sección** y **100 filas en total**. ¿Excediste? El servidor responde con `400` antes de intentar enviar.
  * La fila seleccionada por el usuario regresa a través del evento de mensaje como una respuesta cargando el `id` original, captura esto vía webhook para mapear la elección.
  * Las listas funcionan bien en DMs, grupos y canales, pero la UX puede variar entre WhatsApp Business y WhatsApp personal.
  * `description` es opcional por fila, pero mejora mucho la legibilidad cuando el título por sí solo es ambiguo.
</Note>

## Errores

| HTTP | Status interno   | Mensaje                                                      |
| ---- | ---------------- | ------------------------------------------------------------ |
| 400  | ,                | `Instance name is required`                                  |
| 400  | ,                | `Invalid request body: <detail>`                             |
| 400  | ,                | `Number is required`                                         |
| 400  | ,                | `ContentText is required`                                    |
| 400  | ,                | `ButtonText is required`                                     |
| 400  | ,                | `At least one section is required`                           |
| 400  | ,                | `Maximum of 10 sections allowed`                             |
| 400  | ,                | `Section N: Title is required`                               |
| 400  | ,                | `Section N: At least one row is required`                    |
| 400  | ,                | `Section N: Maximum of 10 rows allowed`                      |
| 400  | ,                | `Section N, Row M: ID is required`                           |
| 400  | ,                | `Section N, Row M: Title is required`                        |
| 400  | ,                | `Total number of rows across all sections cannot exceed 100` |
| 400  | `invalid_number` | `Invalid phone number format: <detail>`                      |
| 404  | ,                | `Instance not found`                                         |
| 500  | `send_failed`    | `Failed to send message: <reason>`                           |
| 503  | `disconnected`   | `Instance is not connected to WhatsApp`                      |

Envoltorio de error:

```json theme={null}
{
  "success": false,
  "error": { "message": "ContentText is required" }
}
```
