
🤖 Configurar menu persistente e botões para o bot do Facebook Messenger
Lançou um bot no Facebook Messenger, ele responde a mensagens, mas falta qualquer coisa. Um utilizador abre o chat e vê uma janela vazia. Sem menu, sem dicas, sem botão «Começar». Primeiro toque, e silêncio. As pessoas simplesmente não percebem o que o seu bot pode fazer.
Três componentes transformam um bot sem rosto numa interface compreensível: um menu persistente com ações rápidas, um botão «Começar» para o primeiro contacto e um texto de saudação que dá as boas-vindas ao utilizador pelo nome. Anteriormente, tudo isto era configurado através do parâmetro obsoleto thread_settings. Agora, a Meta transferiu o controlo para a API unificada do Messenger Profile, e as antigas chamadas cURL dos tutoriais de 2017 simplesmente não funcionam.
Neste guia, a abordagem atual para configurar o menu persistente, o botão Começar e a saudação através da API do Messenger Profile. Com exemplos cURL funcionais e um handler POSTBACK em PHP que distingue os cliques nos itens do menu.
💡 Visão geral rápida:
- Configurar o menu persistente através de
persistent_menuna API do Messenger Profile: até 20 itens, localização, desativação do compositor - Adicionar o botão «Começar» através do parâmetro
get_started: no primeiro toque, o Facebook devolve o PSID do utilizador - Definir o texto de saudação através de
greeting: os modelos{{user_first_name}}ainda funcionam em 2026 - Escrever um handler POSTBACK em PHP: um switch sobre
payloaddistingue qual o item do menu em que o utilizador clicou - Considerar os limites: 10 chamadas à API do Profile a cada 10 minutos por página, até 24 horas para atualizações da cache do menu
O que mudou: Thread Settings → Messenger Profile API
Antes de 2020, o menu, o botão «Começar» e a saudação eram configurados com pedidos POST separados para o endpoint /me/thread_settings. O tipo de definição era especificado no corpo através de setting_type: call_to_actions para o menu, greeting para a saudação. Em 2026, esta abordagem não funciona, o endpoint foi removido da documentação.
Agora, todas as propriedades do bot são definidas através da Messenger Profile API, um endpoint unificado:
1 POST https://graph.facebook.com/v22.0/me/messenger_profile?access_token=PAGE_ACCESS_TOKEN
O corpo do pedido é um objeto JSON com as propriedades necessárias: persistent_menu para o menu, get_started para o botão «Começar», greeting para a saudação, ice_breakers e whitelisted_domains. Pode passá-las em conjunto ou separadamente. O perfil é sobrescrito, não passe uma propriedade se não a quiser alterar.
Documentação oficial: Persistent Menu no Meta for Developers. A versão da API é atualizada a cada seis meses, verifique a atual através do Changelog.
Requisitos para o menu funcionar, atuais em junho de 2026:
- A página do Facebook está publicada, o bot está no modo «público» nas definições da app
- A app tem a permissão
pages_messaging - O utilizador executa a versão 106 ou superior do Messenger
- O botão «Começar» está configurado (sem ele, o menu não aparece)
- Tem a função de administrador da página

1. Menu persistente (persistent_menu)
O menu fica à esquerda do campo de introdução de texto, o utilizador clica no ícone «hambúrguer» e vê uma lista de ações. Isto é navegação de nível superior: «Ajuda», «Catálogo», «Suporte». Até 20 itens, mas a Meta recomenda limitar a cinco para uma melhor experiência de utilizador.
Cada item é um objeto com type (postback ou web_url), title (até 30 caracteres) e payload ou url. Os emojis nos títulos funcionam, copie de getemoji.com.
Configurar o menu. Enviar POST para a Messenger Profile API:
1 curl -X POST -H "Content-Type: application/json" -d '{ 2 "persistent_menu": [ 3 { 4 "locale": "default", 5 "composer_input_disabled": false, 6 "call_to_actions": [ 7 { 8 "type": "postback", 9 "title": "🆘 Help", 10 "payload": "HELP_PAYLOAD" 11 }, 12 { 13 "type": "postback", 14 "title": "📰 News", 15 "payload": "LATEST_POSTS_PAYLOAD" 16 }, 17 { 18 "type": "web_url", 19 "title": "🌐 Website", 20 "url": "https://yoursite.com/", 21 "webview_height_ratio": "full" 22 } 23 ] 24 } 25 ] 26 }' "https://graph.facebook.com/v22.0/me/messenger_profile?access_token=PAGE_ACCESS_TOKEN"
Resposta de sucesso: {"result": "success"}. O menu não aparece imediatamente, a cache do lado do cliente atualiza-se até 24 horas. Ao testar, elimine a conversa e comece de novo para ver as alterações instantaneamente.
Remover o menu. DELETE com o parâmetro fields:
1 curl -X DELETE "https://graph.facebook.com/v22.0/me/messenger_profile?fields=persistent_menu&access_token=PAGE_ACCESS_TOKEN"
Desativar o compositor. Se o bot funcionar apenas através do menu e botões, defina "composer_input_disabled": true. O campo de introdução de texto desaparecerá, o utilizador interage exclusivamente através dos itens do menu e botões de postback. Útil para bots de FAQ e catálogos.
Localização. Adicione objetos com a chave locale para cada idioma. O objeto com "locale": "default" é obrigatório, funciona como fallback:
1 { 2 "persistent_menu": [ 3 { 4 "locale": "default", 5 "call_to_actions": [...] 6 }, 7 { 8 "locale": "ru_RU", 9 "call_to_actions": [...] 10 } 11 ] 12 }
Menu personalizado. Através do endpoint /me/custom_user_settings, pode substituir o menu para um utilizador específico por PSID. Limite: 10 chamadas por utilizador a cada 10 minutos. Após remover o menu personalizado, o menu da página é restaurado.
2. Processar POSTBACK em PHP
Quando um utilizador clica num item de menu com type: "postback", o Facebook envia um evento messaging_postbacks para o seu webhook. No corpo do pedido, um objeto postback com um campo payload que definiu ao configurar o menu.
O handler PHP lê o JSON recebido de php://input, extrai o payload e, através de um switch, determina qual a ação a executar. Abaixo, o código atual para 2026 com o endpoint v22.0:
1 <?php 2 // Read incoming request from Facebook 3 $input = json_decode(file_get_contents('php://input'), true); 4 5 // Extract recipient and sender data 6 $page_id = $input['entry'][0]['id']; 7 $sender = $input['entry'][0]['messaging'][0]['sender']['id']; 8 9 // Determine whether message or postback 10 $message = $input['entry'][0]['messaging'][0]['message']['text'] ?? ''; 11 $postback = $input['entry'][0]['messaging'][0]['postback']['payload'] ?? ''; 12 13 if ($message || $postback) { 14 15 if ($message) { 16 $reply = 'Message received: ' . $message; 17 } else { 18 switch ($postback) { 19 case 'HELP_PAYLOAD': 20 $reply = 'You clicked the "Help" button. How can I help?'; 21 break; 22 23 case 'LATEST_POSTS_PAYLOAD': 24 $reply = 'Here are fresh posts from this week.'; 25 break; 26 27 default: 28 $reply = 'Action not recognized. Try again.'; 29 } 30 } 31 32 // Form response 33 $responseJSON = json_encode([ 34 'recipient' => ['id' => $sender], 35 'message' => ['text' => $reply], 36 ]); 37 38 $access_token = 'YOUR_PAGE_ACCESS_TOKEN'; 39 $url = 'https://graph.facebook.com/v22.0/me/messages?access_token=' . $access_token; 40 41 // Send via cURL 42 $ch = curl_init($url); 43 curl_setopt($ch, CURLOPT_POST, 1); 44 curl_setopt($ch, CURLOPT_POSTFIELDS, $responseJSON); 45 curl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/json']); 46 $result = curl_exec($ch); 47 curl_close($ch); 48 }
O que mudou. A versão da API no URL foi atualizada de v2.7 para v22.0. Em vez da montagem manual de strings JSON, utiliza-se json_encode(), reduzindo a probabilidade de erros de escape. Foi adicionado um bloco default no switch para payloads não reconhecidos. A construção ?? (null coalescing) é mais limpa do que os antigos ternários com isset().
Onde colocar. O código vai no ficheiro apontado pelo URL do webhook da app do Facebook. Normalmente é o webhook.php na raiz do site. Certifique-se de que o método GET no mesmo URL trata a verificação do webhook através do hub_challenge.
Importante. Guarde o token de acesso em variáveis de ambiente ou num ficheiro de configuração, nunca no código. Para desenvolvimento local, utilize um ficheiro .env com PAGE_ACCESS_TOKEN=....
3. Botão Começar (get_started)
O botão aparece no ecrã de boas-vindas, no primeiro contacto com a página. Após o clique, o Facebook envia messaging_postbacks com o payload que especificou. Em resposta, pode cumprimentar o utilizador pelo nome ou mostrar um menu de botões.
Sem um botão «Começar» configurado, o menu persistente não é exibido, sendo este um requisito obrigatório da plataforma.
Configuração:
1 curl -X POST -H "Content-Type: application/json" -d '{ 2 "get_started": { 3 "payload": "GET_STARTED_PAYLOAD" 4 } 5 }' "https://graph.facebook.com/v22.0/me/messenger_profile?access_token=PAGE_ACCESS_TOKEN"
O payload é uma string arbitrária até 1000 caracteres. No handler PHP, adicione case 'GET_STARTED_PAYLOAD' no switch e devolva uma saudação personalizada.
Remoção:
1 curl -X DELETE "https://graph.facebook.com/v22.0/me/messenger_profile?fields=get_started&access_token=PAGE_ACCESS_TOKEN"
4. Texto de saudação (greeting)
A saudação é mostrada num chat vazio, antes da primeira mensagem. Suporta os templates {{user_first_name}}, {{user_last_name}} e {{user_full_name}}. A personalização pelo nome aumenta o envolvimento: o utilizador percebe que o bot se está a dirigir especificamente a ele.
Configuração:
1 curl -X POST -H "Content-Type: application/json" -d '{ 2 "greeting": [ 3 { 4 "locale": "default", 5 "text": "Hi, {{user_first_name}}! I am a helper bot. Ask a question or open the menu on the left." 6 } 7 ] 8 }' "https://graph.facebook.com/v22.0/me/messenger_profile?access_token=PAGE_ACCESS_TOKEN"
O texto de saudação também suporta localização; adicione objetos com a chave locale.
Remoção:
1 curl -X DELETE "https://graph.facebook.com/v22.0/me/messenger_profile?fields=greeting&access_token=PAGE_ACCESS_TOKEN"
5. Ice Breakers: perguntas frequentes antes da primeira mensagem
Os Ice Breakers são uma funcionalidade relativamente recente da Messenger Platform. Trata-se de botões com perguntas prontas que aparecem antes de o utilizador ter escrito algo. O clique envia o texto em nome do utilizador e inicia o diálogo.
Conveniente para integração: em vez de uma janela vazia, a pessoa vê «O que podes fazer?», «Onde está a minha encomenda?», «Falar com o apoio» e inicia o diálogo com um toque.
Configuração:
1 curl -X POST -H "Content-Type: application/json" -d '{ 2 "ice_breakers": [ 3 { 4 "question": "What can you do?", 5 "payload": "ICE_CAPABILITIES" 6 }, 7 { 8 "question": "Where is my order?", 9 "payload": "ICE_ORDER_STATUS" 10 } 11 ] 12 }' "https://graph.facebook.com/v22.0/me/messenger_profile?access_token=PAGE_ACCESS_TOKEN"
Até 4 perguntas, máximo de 80 caracteres por pergunta. O payload é tratado no mesmo handler PHP, através do switch.
⁉️🤔 Perguntas frequentes
Porque é que o menu não aparece, mesmo com o pedido a devolver sucesso?
Principais razões: botão «Get Started» não configurado, página não publicada, aplicação em modo de desenvolvimento, utilizador a usar uma versão antiga do Messenger ou o Navegador Móvel do Facebook. O menu é armazenado em cache localmente, a atualização do lado do cliente pode demorar até 24 horas. Para testar, apague a conversa com o bot e comece de novo. Se o menu continuar sem estar visível, verifique todos os pontos: página publicada, bot público, permissão
pages_messagingobtida, botão «Get Started» configurado.
É possível criar um menu com submenus?
Sim, através do parâmetro
call_to_actionsdentro de um item do menu. A hierarquia suporta um nível, o submenu expande ao clicar no item principal. O formato é semelhante ao menu principal: array de objetos comtype,titleepayload/url. Um item principal com submenu não pode serweb_url, apenaspostback. A profundidade máxima é de um nível. Esta é uma limitação da plataforma, não pode ser contornada.
Em que é que o menu ao nível do utilizador difere do menu ao nível da página?
O menu ao nível da página é igual para todos os utilizadores da página. O menu ao nível do utilizador, através de
/me/custom_user_settings, permite mostrar itens diferentes a pessoas diferentes: novos utilizadores veem «O que posso fazer», utilizadores recorrentes veem «Histórico de encomendas». A atualização ao nível do utilizador é em tempo real, ao nível da página tem um atraso até 24 horas. Limite: 10 chamadas por utilizador a cada 10 minutos. Após remover o menu personalizado, o menu da página é restaurado automaticamente.
Como verificar se o webhook recebe POSTBACK?
Ative o modo de depuração nas definições da aplicação do Facebook e clique num item do menu na conversa com o bot. Os registos mostrarão uma entrada com o campo
postback.payload. Em alternativa, adicioneerror_log(print_r($input, true))no início do manipulador e verifique os registos do servidor. Para desenvolvimento local, use o ngrok: ele cria um túnel com um URL HTTPS público para o seu localhost, com um certificado válido.
É necessário atualizar o código quando a versão da API muda?
Sim, duas vezes por ano. A Meta lança uma nova versão da API a cada seis meses e desativa as antigas 2 anos após o lançamento da versão de substituição. Acompanhe o Changelog da Messenger Platform. No código, basta substituir o número da versão no URL, a lógica das chamadas raramente muda. Descontinuação programada: v19.0, janeiro de 2026; v20.0, maio de 2026; v21.0, outubro de 2026. A versão v22.0 está ativa até maio de 2027. Defina a variável
$api_versionno código.
O que fazer com o bot após a configuração: lista de verificação
O menu, o botão e a saudação são a base, não o fim. Quando a mecânica básica funciona, três passos transformam o bot de um cartão de visita numa ferramenta útil:
Ligar a análise de dados. As Estatísticas do Facebook Messenger mostram aberturas, mensagens enviadas e recebidas, diálogos ativos. Sem estes dados, não saberá que itens do menu estão realmente a ser usados.
Configurar uma resposta de fallback. Quando um utilizador escreve um texto não previsto no cenário, o bot deve responder de forma útil, não ficar em silêncio. Adicione um ramo padrão ao manipulador com uma oferta para abrir o menu ou contactar um humano.
Atualizar o menu sazonalmente. Promoções, novos produtos, vendas de época, altere os itens do menu ao longo do ano. Através da Messenger Profile API, isto é feito com um pedido POST.
Se o bot processar encomendas ou recolher contactos, configure o domínio em whitelisted_domains para o funcionamento correto da WebView dentro do Messenger. E não se esqueça dos limites de taxa: 10 chamadas à Profile API por cada 10 minutos por página. Coloque em fila as atualizações de menu em lote para milhares de utilizadores, com pausas.



