Comportamento de entrega

O payload padrão, o limite de 5 segundos, por que não há novas tentativas e o que significa cada status de entrega.

A entrega de webhooks é simples por decisão de projeto, e essa simplicidade tem consequências para o seu receptor: uma tentativa HTTP, cinco segundos, nenhuma nova tentativa. Leia esta página antes de decidir quanto trabalho seu handler executará de forma síncrona.

O payload padrão

Todos os eventos, exceto listing.submission, chegam com a mesma estrutura no nível superior, com os campos específicos do evento dentro de data.

JSON
{  "event": "connection.location_connected",  "timestamp": "2026-08-25T14:32:10Z",  "account_id": 11073,  "location_id": "279381",  "data": {    "platform": "google",    "connected_account_id": "ba03bc4b-9f8c-4d3b-8e93-9628034c63cc"  }}
CampoTipoObservações
eventstringO nome do evento, com partes separadas por pontos. Use esse valor para determinar qual lógica executar.
timestampstringISO-8601 em UTC, registrado quando a entrega foi preparada, não quando a alteração que a originou ocorreu.
account_idintegerA conta à qual o evento pertence.
location_idstringUma string numérica: "279381", não 279381. Não há conversão de tipo em interaction.*; veja a exceção abaixo.
dataobjectCampos específicos do evento. Documentados para cada evento na referência de eventos.
agency_account_idintegerPresente apenas quando a conta é gerenciada por uma conta de agência superior.

Os campos opcionais dentro de data são omitidos quando estão vazios, em vez de serem enviados como null. Programe de forma defensiva: trate uma chave ausente e um null explícito da mesma maneira e nunca presuma que uma chave documentada como opcional estará presente.

Duas exceções

O limite de 5 segundos

Cada entrega consiste em um único POST com timeout de conexão de 5 segundos e timeout de leitura de 5 segundos. Se o seu endpoint não responder dentro do prazo, a tentativa será abandonada e registrada como timeout.

Esse limite se aplica à execução completa do seu handler. A única implementação segura é:

  1. Verifique a assinatura.
  2. Grave o payload em um armazenamento persistente: uma fila, uma tabela ou um log.
  3. Retorne 200.

Todo o restante (enriquecimento, distribuição para múltiplos destinos, chamadas de volta à REST API, qualquer operação que envolva terceiros) deve ser executado após o consumo dessa fila.

Não há novas tentativas

Cada entrega é tentada exatamente uma vez. Não há backoff, fila de novas tentativas nem fila de mensagens não entregues. Se o seu endpoint ficar indisponível por dois minutos, os eventos disparados nesses dois minutos serão perdidos. Eles não chegarão depois.

Duas consequências que precisam ficar explícitas:

  • Redirecionamentos não são seguidos. Os redirecionamentos são totalmente desativados, portanto, um 301 ou 302 retornado pelo seu endpoint é registrado como falha na entrega, sem que o redirecionamento para uma segunda URL seja seguido. Configure a URL dos seus webhooks com a URL final. Fique atento aos redirecionamentos do domínio sem subdomínio para www e aos redirecionamentos que acrescentam uma barra final, que muitos servidores web adicionam por padrão.
  • Somente um 2xx conta como entrega concluída. 3xx, 4xx e 5xx são todos registrados como falhas.

Duplicatas e ordenação

  • Você pode receber o mesmo evento duas vezes e o mesmo id para duas alterações diferentes. Os identificadores em data (um id de interação, um id de item de publicação, um id de conta conectada) identificam o recurso, não a alteração. interaction.review é disparado novamente com o mesmo id de interação sempre que a avaliação muda, e nenhum payload contém uma versão ou um campo de data da última atualização, portanto, um handler que descarta permanentemente eventos com base no id + event elimina edições reais silenciosamente. Em vez disso, detecte duplicatas exatas: calcule o hash dos bytes brutos do corpo e ignore repetições do mesmo hash dentro de uma janela curta e limitada (minutos, não para sempre). Um corpo diferente para o mesmo id é uma nova alteração, não uma duplicata. Em seguida, consulte novamente o recurso pela API REST e considere essa leitura como a fonte de referência; use o id do recurso como chave da gravação em vez de ignorá-la.
  • A ordenação não é garantida, e timestamp não resolve isso. Os eventos vêm de vários fluxos independentes e são entregues conforme chegam, portanto, um local_post.published pode chegar antes do local_post.created que você esperava receber primeiro. Não ordene duas alterações no mesmo recurso por timestamp: ele é registrado quando a entrega é montada, não quando a alteração ocorreu, e não há versão nem número de sequência em nenhuma parte do payload. Quando a ordem for relevante, consulte novamente o recurso e use o que a API retornar.
  • profile.updated é limitado por debounce a uma entrega por local a cada 60 segundos, no início da janela. Isso é uma supressão efetiva, não um atraso: a primeira edição abre a janela e é entregue, todas as edições dentro da janela são descartadas e nunca chegam, e changed_fields descreve apenas a edição que abriu a janela. Portanto, o evento chega até você no início da janela, de modo que uma nova leitura disparada pela chegada dele só consegue ver essa primeira edição. Agende uma segunda leitura após o fechamento da janela, pelo menos 60 segundos após o evento, e também reconcilie os locais em intervalos regulares, pois a própria notificação pode se perder: uma tentativa, sem nova tentativa. Nenhum outro evento está sujeito a debounce.

Recuperação após a perda de um evento

Não há novas tentativas nem reenvio, portanto, cada família precisa de uma leitura de referência à qual você possa recorrer. Reconcilie em intervalos programados, não apenas quando algo parecer errado.

FamíliaConsulte novamente comIntervalo sugeridoO que uma leitura não consegue recuperar
listing.submissionGET /locations/{locationId}/listings/premium, uma vez com listingType=premium e outra com additional: os valores de syncStatus e listingUrl por site que o evento informa.Diariamente por local e após uma edição de locais em massa.O payload legado não tem timestamp nem account_id, portanto, não é possível determinar quando um evento perdido ocorreu nem atribuí-lo a uma conta. Nenhuma leitura expõe error_message em um envio incomplete.
profile.*GET /locations, GET /locations/search ou GET /locations-by-ids. O valor de updatedAt em cada local informa quais sofreram alterações.A cada hora, além da nova leitura após o fechamento da janela descrita acima.source (user / api / bulk_edit) e changed_fields: uma leitura mostra o estado atual, nunca quem alterou o quê. As edições suprimidas pelo debounce de 60 segundos não deixam nenhum registro, e o estado de um local anterior à sua exclusão deixa de estar disponível.
connection.*GET /connected-accounts e GET /connected-accounts/{connectedAccountId}/details para conexão, desconexão e integridade da autenticação. Para o par de eventos de verificação do Google, leia googleVerificationStatus { status, message } no resultado de qualquer leitura de local.A cada hora; a cada poucos minutos enquanto uma verificação estiver em andamento.failure_type (rejected versus transient) e a string reason. As oscilações são invisíveis: uma conexão que caiu e foi restabelecida aparece como conectada na leitura.
interaction.*GET /locations/{locationId}/reviews por local, GET /rollup_interactions entre locais, GET /reviewDetails por id.A cada 15 minutos para novas avaliações, diariamente para uma consulta mais abrangente.O fato de que algo mudou. Os campos de interação documentados não contêm uma data da última atualização, portanto, uma avaliação editada parece exatamente igual a uma que você já armazenou: compare os campos que você mantém.
local_post.*GET /locations/{locationId}/posts, GET /locations/{locationId}/bulk-posts, GET /posts/{postId} para o status atual de publicação por site.A cada hora enquanto as publicações estiverem em andamento.rejection_reason conforme entregue e a sequência de estados pelos quais um item de publicação passou. As leituras fornecem o status atual, não as transições.
review_analytics.*GET /locations/{locationId}/review-analytics-overview com startDate e endDate do período.Diariamente após a janela de agregação, semanalmente para a família semanal.Os números referentes ao momento do registro. A visão geral é recalculada no momento da leitura, portanto, uma avaliação que chega com atraso ou é excluída faz com que ela difira dos valores do instantâneo.

Resultados da entrega

Cada tentativa, incluindo aquelas que nem chegam a ser enviadas, é registrada com um status. Estas são as strings exatas.

Os quatro resultados e as strings de status que os registram. 'Bloqueada' e 'Limitada por taxa' significam que nenhuma requisição HTTP foi feita, por isso é importante distingui-las de uma falha real.
StatusResultadoO que significaO que fazer
successEntregueSeu endpoint retornou um 2xx.Nada.
um código HTTP como string, e.g. "404", "500"FalhaSeu endpoint retornou esse código fora da faixa 2xx. 3xx também se enquadra aqui, porque os redirecionamentos não são seguidos.Verifique o caminho, a cadeia de redirecionamentos e a taxa de erros do seu handler.
999FalhaUma resposta foi recebida sem um código de status utilizável.Geralmente, a causa é um proxy ou balanceador de carga que fica à frente do seu endpoint.
timeoutFalhaNenhuma resposta foi recebida dentro do prazo de 5 segundos.Retire o processamento do fluxo da requisição e confirme o recebimento mais rapidamente.
network_errorFalhaNão foi possível resolver o nome do host ou se conectar a ele.Verifique o DNS e se o nome do host pode ser resolvido publicamente.
errorFalhaA tentativa gerou uma exceção que não se enquadra nos casos acima, como uma falha no handshake TLS.Verifique sua cadeia de certificados e os logs do servidor.
blocked_urlBloqueadaA URL não passou na verificação de segurança no momento da conexão: não usa HTTPS, não tem host ou foi resolvida para um endereço privado, de loopback, de link local ou de metadados.Aponte a URL para um host HTTPS público. Essa verificação é refeita a cada entrega, então uma alteração no DNS pode fazer com que uma URL que funcionava antes passe a ser bloqueada.
endpoint_unverifiedBloqueadaA conta tem um segredo de assinatura, mas o endpoint não passou na verificação ou a verificação foi redefinida.Execute Verificar endpoint novamente pelo painel.
rate_limitedLimitada por taxaO limite por minuto ou por dia foi excedido. O evento foi descartado.Reduza o volume ou mude para um plano com um limite maior. Consulte planos e limites.

Lista de verificação para o receptor

  • Verifique a assinatura de cada requisição; retorne 401 e não processe nada se ela não corresponder à assinatura esperada.
  • Calcule o hash dos bytes brutos do corpo, nunca de um objeto serializado novamente.
  • Retorne 2xx em bem menos de 5 segundos; coloque o processamento na fila.
  • Use os IDs contidos em data como chaves em cada operação de gravação do handler para que uma repetição produza o mesmo resultado, mas nunca considere que um ID repetido significa que não há nada a fazer.
  • Não deduza a ordem dos eventos pela ordem de chegada e não ordene por timestamp.
  • Normalize location_id para uma string ao recebê-lo.
  • Ignore os valores de event que você não reconhecer e, ainda assim, retorne 200.
  • Disponibilize a URL dos webhooks como uma URL final, sem redirecionamentos.
  • Faça a reconciliação periodicamente com a API REST; não há novas tentativas para recuperar entregas malsucedidas.