Chatfuel
Public API

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.

Última atualização

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.

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:

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:

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.

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.

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

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 :

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

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):

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 "[email protected]"

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:

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 "[email protected]"

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 lista todos eles e descreve o tipo File.

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

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

"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 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 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.

Nesta página