---
title: "Como fazer requisições à Public API"
description: "Envie requisições POST GraphQL para panel.chatfuel.com/graphql, pagine com cursores, assine eventos via WebSocket, envie arquivos e respeite os limites."
canonical_url: https://chatfuel.com/pt/docs/public-api/requests
markdown_url: https://chatfuel.com/pt/docs/public-api/requests.md
last_updated: 2026-10-06
lang: pt
site: https://chatfuel.com/docs
llms_txt: https://chatfuel.com/llms.txt
---

# Como fazer requisições à Public API

Envie requisições POST GraphQL para panel.chatfuel.com/graphql, pagine com cursores, assine eventos via WebSocket, envie arquivos e respeite os limites.

A Public API do Chatfuel é um único endpoint GraphQL, `https://panel.chatfuel.com/graphql`. Consultas e mutações são requisições HTTP `POST` com um corpo JSON; assinaturas usam um WebSocket no mesmo endereço; arquivos são enviados para um endpoint HTTP separado e depois referenciados pelo ID. Toda requisição leva um token no cabeçalho `Authorization: Bearer <token>`, como descrito em [autenticação](https://chatfuel.com/pt/docs/public-api/authentication).

## Como enviar uma consulta ou mutação [#como-enviar-uma-consulta-ou-mutação]

O corpo da requisição é um objeto JSON com `query` e, opcionalmente, `variables` e `operationName`. Sempre passe os valores por `variables` em vez de montar a string da consulta manualmente.

Node.js 18 ou superior:

```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 com `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"]})
```

Uma resposta GraphQL pode ter status HTTP 200 e, mesmo assim, conter `errors`. Sempre verifique o array `errors`, como descrito em [erros](https://chatfuel.com/pt/docs/public-api/errors).

## Como paginar listas [#como-paginar-listas]

Listas longas são conexões paginadas por cursor: você passa `first` (tamanho da página) e `after` (o cursor do último item que você tem) e lê `edges { node cursor }` junto com `pageInfo { hasNextPage endCursor }`. Cursores são strings opacas; armazene-os exatamente como vieram.

```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;
}
```

A maior página tem 500 itens para contatos, conversas e regras de palavras-chave. Páginas menores, de 50 a 100 itens, mantêm as respostas rápidas quando você seleciona muitos campos.

## Como assinar eventos [#como-assinar-eventos]

As assinaturas enviam eventos como novas mensagens, atualizações de contatos e alterações em agendamentos. Elas funcionam via WebSocket em `wss://panel.chatfuel.com/graphql` com o protocolo `graphql-transport-ws`, implementado pela biblioteca `graphql-ws`. Passe o token nos parâmetros de conexão como `authToken`, incluindo o prefixo `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: () => {} },
);
```

As permissões são verificadas quando você assina e novamente a cada evento, então um usuário virtual só recebe os eventos que tem permissão para ver. Cada página de referência lista as suas assinaturas. Reconecte com backoff quando o socket for fechado.

## Como enviar arquivos [#como-enviar-arquivos]

Imagens, vídeos, áudios e documentos são enviados por HTTP simples e depois passados às mutações pelo ID do arquivo. Envie o arquivo como `multipart/form-data` para o endpoint de upload com o ID do bot e o tipo de arquivo (`Image`, `Video`, `Audio` ou `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"
```

A resposta é um JSON que descreve o arquivo armazenado; o `id` dele é o `FileID` que você passa para mutações como `goodsProductCreate`, `whatsAppImageSetImageFile` ou `csvContactImportCreate`. O upload para um bot exige a função Editor. Use o ID do arquivo em até duas horas: arquivos enviados que nunca são usados são excluídos.

Para anexar um arquivo a uma mensagem do chat, envie-o para o endpoint do chat, que também recebe o ID do contato e funciona com a função 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"
```

A mídia do cabeçalho de templates e o avatar do widget do site têm seus próprios endpoints de upload. [Arquivos e tarefas](https://chatfuel.com/pt/docs/public-api/files-and-tasks) lista todos eles e descreve o tipo `File`.

## Limites de requisições [#limites-de-requisições]

A Public API permite **25 operações por segundo por conta**. Cada usuário virtual tem a sua própria cota. Um token de API pessoal compartilha a cota com a sua própria sessão no painel, mais um motivo para executar integrações como usuários virtuais. Requisições sem token são limitadas a 40 por segundo por endereço IP.

Uma operação GraphQL conta uma única vez, não importa quantos campos ela selecione. Quando você ultrapassa o limite, a requisição é rejeitada com o status `429 Too Many Requests`. Aguarde cerca de um segundo e tente novamente com backoff exponencial; sempre que possível, agrupe leituras em uma única consulta.

## Limites de tamanho da consulta [#limites-de-tamanho-da-consulta]

Para proteger o serviço, cada operação é limitada a uma profundidade de aninhamento de 300, a 10.000 campos selecionados no total e a uma complexidade de 8.000 por serviço do Chatfuel, sendo que a complexidade cresce a cada campo selecionado. Uma consulta que ultrapassa um limite é rejeitada antes de ser executada. Selecione apenas os campos que você usa e divida leituras muito grandes em várias consultas.

## Problemas comuns [#problemas-comuns]

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

Mais de 25 operações por segundo foram executadas na mesma conta. Adicione backoff e novas tentativas, combine leituras em menos consultas ou distribua a carga entre vários usuários virtuais.

### O WebSocket conecta, mas todas as assinaturas falham com "Unauthorized" [#o-websocket-conecta-mas-todas-as-assinaturas-falham-com-unauthorized]

O parâmetro de conexão `authToken` precisa incluir o esquema: `Bearer <token>`. Um token sem o esquema é ignorado.

### O endpoint de upload retorna 401 [#o-endpoint-de-upload-retorna-401]

O token está ausente, ou a função do usuário virtual não permite o upload: uploads para o bot exigem Editor, e uploads para o chat exigem Agent ou Editor. Verifique se o `botID` pertence ao bot do usuário virtual.
