Integrações nativas
Google Sheets, Google Agenda, Notion e HubSpot, conectados por OAuth no painel e movidos pelo mesmo catálogo de eventos dos webhooks.
O modelo
Uma conexão é uma concessão OAuth a uma conta externa. Um vínculo diz “quando order.created acontecer, rode sheets.append_rowcom esta configuração”. Cada evento que casa com um vínculo produz uma sincronização, e o histórico delas é consultável.
curl https://api.zapyflow.com.br/api/integrations \
-H "Authorization: Bearer $ZAPYFLOW_API_KEY"Google — uma conexão, duas capacidades
Sheets e Agenda aparecem como duas capacidades de uma únicaconexão Google, não duas conexões. Revogar qualquer token de uma concessão do Google revoga a concessão inteira, então duas conexões separadas fariam “desconectar o Sheets” matar em silêncio a sincronização da sua Agenda. Acrescentar a segunda capacidade dispara consentimento incremental.
Para o Sheets pedimos drive.file, não acesso completo a planilhas: ele alcança só os arquivos que você escolhe explicitamente, o que basta para acrescentar uma linha.
Retentativa não duplica o seu dado
Essa é a propriedade que decide se uma integração é usável, e cada provedor recebe o mecanismo mais forte que ele de fato oferece — não um genérico.
| Ação | Como a retentativa fica segura |
|---|---|
calendar.upsert_event | O Google aceita id de evento fornecido pelo cliente, então derivamos um do agendamento. Uma inserção duplicada devolve 409 e trocamos para patch. Criação idempotente de verdade, sem leitura extra. |
hubspot.upsert_contact / upsert_deal | Criamos as propriedades personalizadas zapyflow_lead_id e zapyflow_order_id com hasUniqueValue e usamos o upsert nativo em lote do HubSpot. Isso também casa o lead de WhatsApp que tem telefone e não tem e-mail — a maioria aqui. |
sheets.append_row | O Sheets não tem upsert, então a planilha precisa de uma coluna zapyflow_event_id. O caminho feliz é um append só; a coluna só é varrida numa retentativa ambígua (falha depois de a requisição ter saído). |
notion.create_page | Mesma forma: uma propriedade ZapyFlow ID na base, consultada só numa retentativa ambígua. |
Atualização encontra o registro que a criação fez: a referência é chaveada pela entidade (pedido, lead, agendamento), não pelo evento. Sem isso, order.updated abriria um negócio novo no seu funil toda vez.
Tratamento de falha
Sincronizações retentam no mesmo calendário dos webhooks — seis tentativas ao longo de ~31 horas — mas só para falhas que o tempo conserta. Concessão revogada ou alvo apagado é terminal.
| Status | Significado |
|---|---|
| SUCCEEDED | Gravado no provedor. externalRef guarda o id do lado de lá. |
| SKIPPED | Deliberadamente não gravado — por exemplo, a planilha não tem a coluna de id. O motivo fica na sincronização. |
| FAILED | Falha terminal. Conserte a causa e retente. |
| EXHAUSTED | As seis tentativas acabaram. |
Depois de 20 falhas consecutivas, o vínculo é desligado — não a conexão. Uma planilha quebrada não pode derrubar uma sincronização de Agenda que funciona na mesma conta.
Conexões revogadas
Quando alguém revoga o acesso lá no provedor, nada nos avisa. Uma sonda diária detecta em até 24 horas e move a conexão para REVOKED, o que faz aparecer o pedido de reconexão no painel e pausa os vínculos em vez de queimar retentativas.
Desconectar
DELETE /api/integrations/{installationId} apaga a credencial que guardamos e desliga os vínculos. A resposta diz se conseguimos também revogar no provedor — o Notion não tem endpoint de revogação, e nós devolvemos revokedAtProvider: false em vez de dar a entender um corte de acesso que não fizemos.