Uma URL de webhook que a Meta aceita de verdade.
A Meta verifica a URL de callback antes de salvá-la e depois para de tentar após 36 horas se ninguém confirmar o recebimento. O AnyHook responde à verificação, armazena cada evento e tenta de novo entregar ao seu handler segundo o próprio cronograma, com cada evento disponível para replay enquanto o seu plano o guarda.
O problema do tempo
A Meta envia um GET para sua URL de callback com hub.mode=subscribe e um challenge, e não salva a URL a menos que você devolva esse challenge como o corpo inteiro da resposta. Um túnel resolve isso uma vez. Na próxima vez que o ngrok der a você um novo hostname, você volta ao App Dashboard para fazer tudo de novo, e a inscrição que você já criou fica apontando para o nada.
Quando os eventos começam a chegar, o prazo não é por requisição: é de 36 horas. A Meta tenta de novo com frequência decrescente nessa janela e depois descarta tudo o que nunca teve o recebimento confirmado. Para um bot de resposta automática, essa janela é a diferença entre responder a um comentário e nunca saber que ele existiu.
Aponte o callback para o AnyHook e verifique um cabeçalho
A URL de entrada nunca muda, então o App Dashboard vira uma etapa única. O AnyHook verifica o X-Hub-Signature-256 da Meta na edge, armazena o evento e depois assina de novo a entrega para o seu handler.
// 1. In AnyHook: set the app's source to Meta, paste your App Secret.
// Optionally set a Verify Token. You invent that string, it is not
// something you copy out of Meta.
//
// 2. In Meta App Dashboard -> Webhooks:
// Callback URL: https://in.anyhook.net/{user-slug}/{app-slug}
// Verify Token: the same string you chose
//
// AnyHook answers the GET handshake, so the URL saves first time.
import { verifyWebhook } from "anyhook-verify";
export async function POST(req: Request) {
const ok = await verifyWebhook(req, process.env.ANYHOOK_SIGNING_SECRET!);
if (!ok) return new Response("invalid signature", { status: 401 });
const event = await req.json();
const change = event.entry?.[0]?.changes?.[0];
// Meta already has its acknowledgement. Take as long as you need here.
if (change?.field === "comments") {
await replyToComment(change.value); // an LLM call, a few seconds
}
return new Response("ok", { status: 200 });
}Perguntas que as equipes fazem
- A Meta diz que minha URL de callback não pôde ser validada. Por quê?
- Essa verificação é um GET com hub.mode=subscribe e hub.challenge, e ela falha a menos que sua URL devolva o challenge como o corpo inteiro, sem envelope JSON e sem quebra de linha no final. O AnyHook responde a ela, então uma URL de entrada é salva na primeira tentativa. Se você definir um Verify Token no AnyHook, digite a mesma string no App Dashboard.
- Instagram, Facebook e Threads precisam de três configurações separadas?
- Não. Eles seguem um único contrato de webhook da Graph API, com a mesma assinatura X-Hub-Signature-256, então um único app do AnyHook (uma URL de entrada para uma origem) cobre os três. Escolha as inscrições que você quer no App Dashboard.
- O que acontece com comentários e DMs durante o redeploy do meu bot?
- O AnyHook armazena o evento assim que ele chega e tenta de novo no seu endpoint com backoff, então um deploy ou um crash não faz você perder a mensagem. A Meta vê uma confirmação de recebimento e para de se preocupar com isso.
- O Verify Token é o mesmo que o App Secret?
- Não, e eles não devem ser a mesma string. O App Secret assina cada payload e nunca viaja numa URL. O Verify Token é uma string que você inventa: ele chega na query string do handshake de configuração e só é usado nesse momento. Colocar seu App Secret numa query string o espalharia por todos os logs no caminho.
Troque uma URL. Mantenha seu handler de Instagram.
O plano Free cobre 10 mil eventos / mês. Sem SDK: aponte os webhooks de Instagram para sua URL de entrada do AnyHook.