Synergy Connect

Documentação

Criar um webhook

POST/v1/webhooks

Cadastra uma URL para receber eventos. A URL precisa se provar antes: por padrão (verification: "ping") com um POST de teste assinado que ela responde com 2xx; ou com o handshake hub.challenge da Meta (verification: "meta", com verifyToken), para receptores feitos para a Meta.

A resposta traz o secret que assina as entregas (X-Hub-Signature-256). Ele só aparece aqui e em rotate-secret.

Uma chave limitada a alguns números só cadastra webhooks restritos a números dela (instanceIds). Limite de 20 webhooks por organização. Corpo de até 16 KB.

Requer#

Escopo da chave
Gerenciar webhooks managementComo os escopos funcionam
Recurso do plano
API e webhooks apiVer os planos que incluem
Formato
Próprio do Synergy. Erros em { "error": "…" }.

Parâmetros#

Cabeçalhos#

Cabeçalhos
NomeTipoObrigatórioDescrição
AuthorizationstringobrigatórioSua chave de API, no formato Bearer <chave>. Veja Autenticação.

Corpo#

Tipo de conteúdo: application/json.

Campos do corpo
NomeTipoObrigatórioDescrição
urlstringobrigatórioA URL que recebe os eventos: https, pública, sem usuário e senha, e nunca um endereço da própria Synergy.
fieldsstring[]obrigatórioOs eventos que o webhook recebe: os nomes da Meta, mais statuses (que a Meta entrega dentro de messages e aqui é uma escolha à parte) e synergy_conversations. Veja webhooks neste documento.
statusesstring[] | nullopcionalFiltro dentro de statuses: só estes status chegam. null = todos.
instanceIdsstring[] | nullobrigatórioOs números que o webhook cobre, pelo id do número na Synergy (64 hex; o mesmo de X-Synergy-Instance-Id). null = todos os números da organização, inclusive os conectados depois. Uma chave limitada a alguns números precisa listar números dela.
namestring | nullopcional
verificationstringopcionalping (padrão): a URL responde 2xx a um POST assinado de teste (synergy_ping). meta: a URL responde ao GET hub.challenge da Meta, e verifyToken é obrigatório. Valores: ping, meta.
verifyTokenstringopcionalO token que a URL confere no handshake da Meta (hub.verify_token). Obrigatório com verification: "meta". Não é guardado.
headersobjectopcionalHeaders próprios enviados em toda entrega (por exemplo Authorization): até 10, nomes só com letras, dígitos e hífen (1 a 64 caracteres), sem repetir e fora dos reservados (host, content-length, content-type, transfer-encoding, connection, keep-alive, upgrade, te, trailer, proxy-authorization, proxy-connection, user-agent, x-hub-signature-256, x-hub-signature, x-synergy-*). Os valores nunca voltam em nenhuma resposta: só os nomes, em headerNames.

Respostas#

Respostas
StatusCódigoQuando acontece
201—Webhook criado
400—O corpo não passa na validação (issues traz os problemas, no formato do zod)
400—A URL não é aceita
400—A URL não respondeu à verificação
400—Chave limitada a alguns números
400—Limite de webhooks
401—Chave revogada ou desconhecida
401190Chave malformada ou forjada
403—A chave não tem o escopo management
403—O plano da organização não inclui a API
403—A conta está em modo leitura ou suspensa por falta de pagamento
413—Corpo grande demais
429—Limite de taxa

Os erros no formato da Meta trazem o código em error.code. Ver todos os erros.

Corpo da resposta 201#

Campos da resposta 201
NomeTipoObrigatórioDescrição
rowobjectobrigatório
row.idstringobrigatório
row.urlstringobrigatório
row.fieldsstring[]obrigatório
row.statusesstring[] | nullobrigatório
row.instanceIdsstring[] | nullobrigatório
row.enabledbooleanobrigatório
row.verificationstringobrigatórioValores: meta, ping.
row.headerNamesstring[] | nullobrigatórioOs NOMES dos headers próprios; os valores nunca voltam.
row.disabledReasonstring | nullobrigatório
row.createdBystringobrigatórioO id do usuário que criou, ou key:<id da chave> quando foi pela API.
row.createdAtintegerobrigatórioQuando foi criado (ms desde 1970).
row.updatedAtintegerobrigatórioA versão do webhook: toda alteração muda, e recomeça a saúde dele em cada número (ms desde 1970).
row.namestring | nullobrigatórioUm rótulo seu (o node do n8n usa n8n · <workflow> · prod|test). Opcional.
secretstringobrigatórioA chave do HMAC de X-Hub-Signature-256. Só aparece aqui e em rotate-secret: guarde.
pendingintegerobrigatórioQuantos números ainda não receberam esta alteração. A Synergy repete o envio sozinha; 0 = já vale em todos.

Limites de taxa#

  • Gestão: 30 requisições a cada 60 s por chave (API_MGMT_LIMIT).

Notas#

  • Um corpo que não é JSON é tratado como corpo vazio: responde 400 Invalid body.
  • O Content-Type da requisição não é conferido.
  • As recusas de regra (URL, limite, números, verificação da URL) voltam em 400 com error em português — exceto a de alcance da chave, em inglês.
Requisição

curl

curl -X POST 'https://api.synergyconnect.com.br/v1/webhooks' \
  -H "Authorization: Bearer $SYNERGY_API_KEY" \
  -H 'Content-Type: application/json' \
  -d '{"url":"https://hooks.example.com/synergy","fields":["messages","statuses"],"instanceIds":null,"headers":{"Authorization":"Bearer meu-token"}}'

JavaScript

const res = await fetch('https://api.synergyconnect.com.br/v1/webhooks', {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${process.env.SYNERGY_API_KEY}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    "url": "https://hooks.example.com/synergy",
    "fields": [
      "messages",
      "statuses"
    ],
    "instanceIds": null,
    "headers": {
      "Authorization": "Bearer meu-token"
    }
  }),
});
console.log(res.status, await res.json());

Python

import os

import requests

res = requests.post(
    "https://api.synergyconnect.com.br/v1/webhooks",
    headers={
        "Authorization": f"Bearer {os.environ['SYNERGY_API_KEY']}",
    },
    json={
        "url": "https://hooks.example.com/synergy",
        "fields": [
            "messages",
            "statuses",
        ],
        "instanceIds": None,
        "headers": {
            "Authorization": "Bearer meu-token",
        },
    },
)
print(res.status_code, res.json())
Resposta

201

{
  "row": {
    "id": "7c1f0c7e-4b53-4c7b-9a51-3f6f0a2d9e10",
    "url": "https://hooks.example.com/synergy",
    "fields": [
      "messages",
      "statuses"
    ],
    "statuses": null,
    "instanceIds": null,
    "enabled": true,
    "verification": "ping",
    "headerNames": [
      "Authorization"
    ],
    "disabledReason": null,
    "createdBy": "key:0b9c4d1e-52a7-4f6b-8c3d-1e2f3a4b5c6d",
    "createdAt": 1767225600000,
    "updatedAt": 1767225600000,
    "name": null
  },
  "secret": "9f2c4e6a8b0d1f3a5c7e9b1d3f5a7c9e",
  "pending": 0
}

400

{
  "error": "Invalid body",
  "issues": [
    {
      "code": "invalid_type",
      "expected": "array",
      "path": [
        "fields"
      ],
      "message": "Invalid input: expected array, received undefined"
    }
  ]
}

Há 5 casos com este status; veja a tabela de respostas.

401

{
  "error": "Invalid or revoked key"
}

Há 2 casos com este status; veja a tabela de respostas.

403

{
  "error": "This key lacks the management scope"
}

Há 3 casos com este status; veja a tabela de respostas.

413

{
  "error": "The body is too large (16 KB max)"
}

429

{
  "error": "Rate limit hit"
}

Ficou com dúvida? Escreva para suporte@synergyconnect.com.br.