---
title: "Cómo hacer solicitudes a la Public API"
description: "Envía solicitudes POST de GraphQL a panel.chatfuel.com/graphql, pagina con cursores, suscríbete por WebSocket, sube archivos y respeta los límites."
canonical_url: https://chatfuel.com/es/docs/public-api/requests
markdown_url: https://chatfuel.com/es/docs/public-api/requests.md
last_updated: 2026-10-06
lang: es
site: https://chatfuel.com/docs
llms_txt: https://chatfuel.com/llms.txt
---

# Cómo hacer solicitudes a la Public API

Envía solicitudes POST de GraphQL a panel.chatfuel.com/graphql, pagina con cursores, suscríbete por WebSocket, sube archivos y respeta los límites.

La Public API de Chatfuel es un único endpoint GraphQL, `https://panel.chatfuel.com/graphql`. Las consultas y mutaciones son solicitudes HTTP `POST` con un cuerpo JSON; las suscripciones usan un WebSocket en la misma dirección; los archivos se suben a un endpoint HTTP aparte y luego se referencian por su ID. Cada solicitud lleva un token en el encabezado `Authorization: Bearer <token>`, como se describe en [autenticación](https://chatfuel.com/es/docs/public-api/authentication).

## Cómo enviar una consulta o mutación [#cómo-enviar-una-consulta-o-mutación]

El cuerpo de la solicitud es un objeto JSON con `query` y, opcionalmente, `variables` y `operationName`. Pasa siempre los valores mediante `variables` en lugar de armar la cadena de la consulta a mano.

Node.js 18 o posterior:

```js
const ENDPOINT = 'https://panel.chatfuel.com/graphql';

async function gql(query, variables) {
  const res = await fetch(ENDPOINT, {
    method: 'POST',
    headers: {
      Authorization: `Bearer ${process.env.CHATFUEL_VIRTUAL_USER_TOKEN}`,
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({ query, variables }),
  });
  if (!res.ok) throw new Error(`HTTP ${res.status}`);
  const body = await res.json();
  if (body.errors) throw new Error(JSON.stringify(body.errors));
  return body.data;
}

const data = await gql(
  `query Bot($id: BotID!) { bot(id: $id) { id title timezone } }`,
  { id: process.env.BOT_ID },
);
```

Python con `requests`:

```python
import os
import requests

ENDPOINT = "https://panel.chatfuel.com/graphql"

def gql(query, variables=None):
    res = requests.post(
        ENDPOINT,
        json={"query": query, "variables": variables or {}},
        headers={"Authorization": f"Bearer {os.environ['CHATFUEL_VIRTUAL_USER_TOKEN']}"},
        timeout=30,
    )
    res.raise_for_status()
    body = res.json()
    if body.get("errors"):
        raise RuntimeError(body["errors"])
    return body["data"]

data = gql("query Bot($id: BotID!) { bot(id: $id) { id title } }", {"id": os.environ["BOT_ID"]})
```

Una respuesta GraphQL puede tener el estado HTTP 200 y aun así contener `errors`. Revisa siempre el arreglo `errors`, como se describe en [errores](https://chatfuel.com/es/docs/public-api/errors).

## Cómo paginar listas [#cómo-paginar-listas]

Las listas largas son conexiones paginadas con cursores: pasas `first` (tamaño de página) y `after` (el cursor del último elemento que tienes), y lees `edges { node cursor }` junto con `pageInfo { hasNextPage endCursor }`. Los cursores son cadenas opacas; guárdalos tal como llegan.

```js
async function allContacts(botID) {
  const query = `
    query Contacts($botID: BotID!, $after: ContactSearchCursor) {
      bot(id: $botID) {
        contactsConnection(
          platforms: [whatsapp, instagram, facebook, tiktok, widget]
          first: 500
          after: $after
        ) {
          edges { node { id name } }
          pageInfo { hasNextPage endCursor }
        }
      }
    }`;
  const contacts = [];
  let after = null;
  do {
    const { bot } = await gql(query, { botID, after });
    const page = bot.contactsConnection;
    contacts.push(...page.edges.map((e) => e.node));
    after = page.pageInfo.hasNextPage ? page.pageInfo.endCursor : null;
  } while (after);
  return contacts;
}
```

La página más grande es de 500 elementos para contactos, conversaciones y reglas de palabras clave. Las páginas más pequeñas, de 50 a 100 elementos, mantienen las respuestas rápidas cuando seleccionas muchos campos.

## Cómo suscribirte a eventos [#cómo-suscribirte-a-eventos]

Las suscripciones envían eventos como mensajes nuevos, actualizaciones de contactos y cambios en reservas. Funcionan por WebSocket en `wss://panel.chatfuel.com/graphql` con el protocolo `graphql-transport-ws`, que implementa la biblioteca `graphql-ws`. Pasa el token en los parámetros de conexión como `authToken`, incluido el prefijo `Bearer `:

```js
import { createClient } from 'graphql-ws';
import WebSocket from 'ws';

const client = createClient({
  url: 'wss://panel.chatfuel.com/graphql',
  webSocketImpl: WebSocket,
  connectionParams: { authToken: `Bearer ${process.env.CHATFUEL_VIRTUAL_USER_TOKEN}` },
  keepAlive: 10_000,
});

client.subscribe(
  {
    query: `subscription NewMessages($botID: BotID!, $conversationID: ConversationID!) {
      messageAdded(botID: $botID, conversationID: $conversationID) { id sentTime }
    }`,
    variables: { botID: process.env.BOT_ID, conversationID: process.env.CONTACT_ID },
  },
  { next: (event) => console.log(event.data), error: console.error, complete: () => {} },
);
```

Los permisos se verifican al suscribirte y de nuevo en cada evento, así que un usuario virtual solo recibe los eventos que tiene permitido ver. Cada página de referencia enumera sus suscripciones. Vuelve a conectarte con backoff cuando el socket se cierre.

## Cómo subir archivos [#cómo-subir-archivos]

Las imágenes, los videos, los audios y los documentos se suben por HTTP simple y luego se pasan a las mutaciones mediante su ID de archivo. Envía el archivo como `multipart/form-data` al endpoint de subida con el ID del bot y el tipo de archivo (`Image`, `Video`, `Audio` o `Document`):

```bash
curl -s "https://panel.chatfuel.com/api/filestorage/upload/bot?botID=$BOT_ID&fileType=Image&extension=jpg" \
  -H "Authorization: Bearer $CHATFUEL_VIRTUAL_USER_TOKEN" \
  -F "file=@product.jpg"
```

La respuesta es un JSON que describe el archivo guardado; su `id` es el `FileID` que pasas a mutaciones como `goodsProductCreate`, `whatsAppImageSetImageFile` o `csvContactImportCreate`. Subir archivos a un bot requiere el rol Editor. Usa el ID del archivo en un plazo de dos horas: los archivos subidos que nunca se usan se eliminan.

Para adjuntar un archivo a un mensaje del chat, súbelo al endpoint del chat, que además recibe el ID del contacto y funciona con el rol Agent:

```bash
curl -s "https://panel.chatfuel.com/api/filestorage/upload/livechat?botID=$BOT_ID&contactID=$CONTACT_ID&fileType=Document&extension=pdf" \
  -H "Authorization: Bearer $CHATFUEL_VIRTUAL_USER_TOKEN" \
  -F "file=@invoice.pdf"
```

Los archivos multimedia del encabezado de las plantillas y el avatar del widget del sitio web tienen sus propios endpoints de subida. [Archivos y tareas](https://chatfuel.com/es/docs/public-api/files-and-tasks) los enumera todos y describe el tipo `File`.

## Límites de solicitudes [#límites-de-solicitudes]

La Public API permite **25 operaciones por segundo por cuenta**. Cada usuario virtual tiene su propia cuota. Un token de API personal comparte su cuota con tu propia sesión en el panel, otra razón más para ejecutar las integraciones como usuarios virtuales. Las solicitudes sin token están limitadas a 40 por segundo por dirección IP.

Una operación GraphQL cuenta una sola vez, sin importar cuántos campos seleccione. Cuando superas el límite, la solicitud se rechaza con el estado `429 Too Many Requests`. Espera alrededor de un segundo y vuelve a intentarlo con backoff exponencial; agrupa las lecturas en una sola consulta cuando puedas.

## Límites de tamaño de las consultas [#límites-de-tamaño-de-las-consultas]

Para proteger el servicio, cada operación está limitada a una profundidad de anidamiento de 300, a 10,000 campos seleccionados en total y a una complejidad de 8,000 por servicio de Chatfuel, donde la complejidad crece con cada campo seleccionado. Una consulta que supera un límite se rechaza antes de ejecutarse. Selecciona solo los campos que usas y divide las lecturas muy grandes en varias consultas.

## Problemas comunes [#problemas-comunes]

### "429 Too Many Requests" [#429-too-many-requests]

Se ejecutaron más de 25 operaciones por segundo con la misma cuenta. Agrega backoff y reintentos, combina las lecturas en menos consultas o reparte la carga entre varios usuarios virtuales.

### El WebSocket se conecta, pero todas las suscripciones fallan con "Unauthorized" [#el-websocket-se-conecta-pero-todas-las-suscripciones-fallan-con-unauthorized]

El parámetro de conexión `authToken` debe incluir el esquema: `Bearer <token>`. Un token sin el esquema se ignora.

### El endpoint de subida devuelve 401 [#el-endpoint-de-subida-devuelve-401]

Falta el token, o el rol del usuario virtual no permite la subida: las subidas al bot requieren Editor y las subidas al chat requieren Agent o Editor. Comprueba que `botID` pertenezca al bot del usuario virtual.
