Synergy Connect

Documentação

Instagram

A conta do Instagram conectada à Synergy usa a mesma API, a mesma chave e o mesmo formato de erro do WhatsApp. O que muda é o id do caminho (o ig-user-id da conta, no lugar do phone_number_id), o corpo do envio (o do Instagram, não o da Cloud API) e os eventos de webhook (os nomes da Meta para o Instagram). Este guia cobre o envio de mensagens diretas, a resposta privada a um comentário, as regras da janela de 24 horas e os webhooks de saída.

Antes de começar, a organização precisa de uma conta do Instagram conectada (pela tela Conectar Instagram do app) e de um plano com os recursos api e instagram. A chave de API é a de sempre (Autenticação), com o escopo messages.

O id do caminho#

Em POST /{version}/{id}/messages, {id} é o ig-user-id da conta (só dígitos, de 1 a 32). A {version} segue o formato de sempre (v25.0) e não muda o comportamento.

A chave syn_… carrega só a organização, então a Synergy descobre o canal pelo id:

  1. Um número de WhatsApp da organização que ela já resolveu vai pelo caminho do WhatsApp, como sempre.
  2. Uma conta do Instagram que já respondeu antes vai direto para a conta.
  3. Um id novo é tentado como conta do Instagram uma vez. Se a conta não existe, ou é de outra organização, a resposta é igual à de um id que não existe (404, código 100): ninguém descobre de quem é uma conta.

O terceiro passo tem um limite por chave: 30 ids novos por minuto, por servidor. Passando disso, a Synergy pula a tentativa e segue o caminho do WhatsApp. Se o id for um número seu, o envio acontece normalmente. Se não for, a resposta é 429 com Retry-After: 1, nunca um 404: sem a tentativa, a Synergy não sabe dizer que o id não existe. Repita depois de 1 segundo.

Uma chave restrita a alguns números e contas (instanceIds) só alcança esses: numa conta fora da restrição ela responde 401 (código 190), como num número de WhatsApp fora dela. Uma conta de outra organização responde 404.

Enviar uma mensagem direta#

O corpo é estrito: um campo desconhecido é recusado com 400 (código 100). Escolha um destinatário e uma mensagem.

CampoO que é
recipient.idO IGSID da pessoa (só dígitos). A pessoa precisa já ter uma conversa com a conta
recipient.comment_idO id de um comentário, para uma resposta privada
message.textO texto, de até 1.000 bytes
message.quick_repliesDe 1 a 13 respostas rápidas (content_type: "text", title de até 20 caracteres, payload de até 100), junto com text
message.attachmentUma mídia (image, video, audio ou file) com payload.url, ou um template de botões (template_type: "button", text e de 1 a 3 botões web_url ou postback)
sender_actiontyping_on, typing_off ou mark_seen, no lugar de message

Toda URL (attachment.payload.url, web_url dos botões) precisa ser https:, sem usuário e senha. O corpo inteiro tem até 64 KB.

A resposta, quando a Meta aceita, tem o formato dela:

Mais exemplos de corpo:

Idempotência#

Idempotency-Key funciona como no WhatsApp (Enviar mensagens): repetir a requisição com a mesma chave responde o mesmo message_id e a mensagem sai uma vez só. Enquanto o primeiro envio está em andamento, a repetição recebe 409 (código 1390002); reusar a chave para outra pessoa recebe 422 (código 1390003).

De quem é a conversa depois do envio#

Como no WhatsApp, a conversa passa para a automação (status automated, dona: a chave). Com uma chave notify, a resposta da pessoa vai para a fila dos atendentes; com bot, continua com a integração. Uma chave bot não envia para uma conversa que está com um atendente (409, código 1390001).

Exemplo

curl

curl -X POST 'https://api.synergyconnect.com.br/v25.0/17841400000000001/messages' \
  -H "Authorization: Bearer $SYNERGY_API_KEY" \
  -H 'Content-Type: application/json' \
  -H 'Idempotency-Key: pedido-42-saiu' \
  -d '{"recipient":{"id":"17841400000000099"},"message":{"text":"Seu pedido saiu para entrega!"}}'

JavaScript

const res = await fetch('https://api.synergyconnect.com.br/v25.0/17841400000000001/messages', {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${process.env.SYNERGY_API_KEY}`,
    'Content-Type': 'application/json',
    'Idempotency-Key': 'pedido-42-saiu',
  },
  body: JSON.stringify({
    recipient: { id: '17841400000000099' },
    message: { text: 'Seu pedido saiu para entrega!' },
  }),
});
const { recipient_id, message_id } = await res.json();

Python

import os

import requests

res = requests.post(
    "https://api.synergyconnect.com.br/v25.0/17841400000000001/messages",
    headers={
        "Authorization": f"Bearer {os.environ['SYNERGY_API_KEY']}",
        "Idempotency-Key": "pedido-42-saiu",
    },
    json={
        "recipient": {"id": "17841400000000099"},
        "message": {"text": "Seu pedido saiu para entrega!"},
    },
)
data = res.json()  # {"recipient_id": "...", "message_id": "..."}
JSON
{
  "recipient_id": "17841400000000099",
  "message_id": "aWdfZAG1faXRlbToxOklHTWVzc2FnZAUlEOjE3ODQxNDAw"
}
JSON
{
  "recipient": { "id": "17841400000000099" },
  "message": {
    "text": "Quer ver o catálogo?",
    "quick_replies": [
      { "content_type": "text", "title": "Sim", "payload": "catalogo.sim" },
      { "content_type": "text", "title": "Agora não", "payload": "catalogo.nao" }
    ]
  }
}
JSON
{
  "recipient": { "id": "17841400000000099" },
  "message": {
    "attachment": {
      "type": "image",
      "payload": { "url": "https://cdn.exemplo.com.br/promocao.jpg" }
    }
  }
}
JSON
{
  "recipient": { "id": "17841400000000099" },
  "message": {
    "attachment": {
      "type": "template",
      "payload": {
        "template_type": "button",
        "text": "Acompanhe o seu pedido:",
        "buttons": [{ "type": "web_url", "title": "Rastrear", "url": "https://loja.exemplo.com.br/pedidos/42" }]
      }
    }
  }
}
JSON
{ "recipient": { "id": "17841400000000099" }, "sender_action": "typing_on" }

Resposta privada a um comentário#

Com recipient.comment_id, a mensagem é a resposta privada da conta a um comentário (a pessoa recebe uma DM, mesmo sem ter escrito antes). A Meta permite uma resposta privada por comentário, em até 7 dias.

O envio não acontece na hora: o pedido entra na mesma fila das Jornadas, que respeita o ritmo que a Meta permite, e a resposta é 202:

O resultado final (enviada, recusada, vencida na fila) é o evento synergy_comment_actions do webhook (abaixo). Regras da fila:

  • O comment_id é só numérico.
  • A API usa no máximo 10 % da fila e da vazão: uma Jornada com muitos comentários não é atrasada por ela, e ela não é bloqueada por uma Jornada.
  • Uma segunda tentativa no mesmo comentário recebe 400 (código 100, This comment already has a private reply.).
  • Depois de 20 respostas seguidas a comentários que a Meta não aceita (comment_ineligible: o comentário é antigo, foi apagado, já tem resposta), a chave fica 1 hora sem resposta privada: 429 com Retry-After em segundos.
  • Fila cheia: 429, Retry-After: 60.
Exemplo
curl -X POST 'https://api.synergyconnect.com.br/v25.0/17841400000000001/messages' \
  -H "Authorization: Bearer $SYNERGY_API_KEY" \
  -H 'Content-Type: application/json' \
  -d '{"recipient":{"comment_id":"17900000000000001"},"message":{"text":"Oi! Te mandei os detalhes por aqui."}}'
JSON
{ "queued": true, "comment_id": "17900000000000001" }

A janela de 24 horas#

A conta só envia mensagem livre dentro de 24 horas da última mensagem da pessoa. Diferente do WhatsApp, a Synergy confere a janela antes de chamar a Meta: fora dela a resposta é imediata e nenhuma mensagem é enviada. A API nunca usa a etiqueta Human Agent (a janela estendida de 7 dias da Meta), que fica reservada aos atendentes na plataforma. Veja Janela de atendimento de 24 horas.

Erros#

Todos no formato da Graph API (Erros).

StatusCódigoQuando
400100Corpo inválido, campo desconhecido, URL que não é https, texto acima de 1.000 bytes, recipient com id e comment_id juntos ou nenhum dos dois
400100, subcódigo 2534014A pessoa não tem conversa com a conta (a API não inicia conversa)
400100Segunda resposta privada ao mesmo comentário
40010, subcódigo 2534022Fora da janela de 24 horas
401190Chave inválida ou revogada, ou que não alcança esta conta (instanceIds)
403200A chave não tem o escopo messages, ou é uma chave de assistente: conexões de assistente só enviam pelo WhatsApp
4031390004O plano não tem api ou instagram
4031390005Conta em modo leitura ou suspensa
4031390014A conta foi congelada pela plataforma
404100O id não é uma conta nem um número desta organização
4091390001, 1390002A conversa está com um atendente (chave bot), ou a Idempotency-Key ainda está em andamento
4221390003A Idempotency-Key já foi usada para outra pessoa
429130429Vazão da conta, borda da chave, fila de respostas privadas, ou o id novo sem tentativa disponível (veja acima). Sempre com Retry-After
5032Falha temporária: repita com espera
JSON
{
  "error": {
    "message": "(#10) This message is sent outside of allowed window.",
    "type": "OAuthException",
    "code": 10,
    "error_subcode": 2534022,
    "fbtrace_id": "syn-3f9a1c0b"
  }
}

Webhooks do Instagram#

Os eventos da conta chegam nos mesmos webhooks do WhatsApp (Webhooks): o mesmo cadastro (POST /v1/webhooks), a mesma assinatura (Assinatura dos webhooks), o mesmo X-Synergy-Delivery-Id. O envelope imita o da Meta: object é "instagram" e entry[].id é o ig-user-id da conta.

fieldsQuando dispara
messagesMensagem direta recebida. Vale também para o WhatsApp
messaging_postbacksA pessoa tocou num botão postback
message_reactionsReação a uma mensagem
messaging_seenA pessoa leu uma mensagem
messaging_referralA conversa veio de um link ig.me, anúncio ou código QR
message_editA pessoa editou uma mensagem
messaging_optinsA pessoa aceitou receber mensagens
commentsComentário em uma publicação da conta
live_commentsComentário durante uma transmissão ao vivo
mentionsA conta foi mencionada
synergy_comment_actionsO resultado de uma ação sobre um comentário (resposta privada, pública ou a uma menção)
synergy_journeysEventos de uma Jornada (Jornadas)

Exceto os dois synergy_*, o value é o da Meta, repassado como chegou. Um comentário:

Uma mensagem direta:

Regras da entrega:

  • O plano na hora do evento. O evento só é encaminhado se o plano da organização tem o recurso instagram quando ele chega. Sem o recurso, a Synergy continua guardando as mensagens e não envia nada ao seu endpoint (e não guarda para enviar depois).
  • Um envelope por chamada. Todos os comentários de uma mesma entrega da Meta saem juntos, em um envelope por endpoint, em vez de um POST por comentário.
  • Teto por endpoint. Uma conta entrega no máximo 60 envelopes por minuto a cada endpoint. O que passa disso, enquanto o endpoint está saudável, é descartado e contado (o total aparece como "eventos descartados" na saúde do webhook). Se o endpoint está fora do ar, os eventos esperam na fila de retentativa e saem no ritmo do teto.
  • URL revalidada, nada de segredo. A URL é conferida de novo em cada envio, sem seguir redirecionamentos. Nenhum envelope leva token da Meta, link de mídia nem o segredo do webhook.
  • Assinatura. Toda tentativa leva X-Hub-Signature-256 e X-Synergy-Signature.
  • Filtro por conta. instanceIds limita o webhook a contas e números específicos, como no WhatsApp.
JSON
{
  "object": "instagram",
  "entry": [{
    "id": "17841400000000001",
    "time": 1767225600,
    "changes": [{
      "field": "comments",
      "value": {
        "id": "17900000000000001",
        "text": "eu quero",
        "from": { "id": "17841400000000099", "username": "maria.souza" },
        "media": { "id": "17950000000000001", "media_product_type": "FEED" }
      }
    }]
  }]
}
JSON
{
  "object": "instagram",
  "entry": [{
    "id": "17841400000000001",
    "time": 1767225600,
    "changes": [{
      "field": "messages",
      "value": {
        "sender": { "id": "17841400000000099" },
        "recipient": { "id": "17841400000000001" },
        "timestamp": 1767225600000,
        "message": { "mid": "aWdfZAG1faXRlbToxOklHTWVzc2FnZAUlEOjE3ODQxNDAw", "text": "oi, quero comprar" }
      }
    }]
  }]
}

Limites#

Os limites do Instagram estão em Limites de taxa: a borda por chave e conta, a vazão da conta, a fila de respostas privadas e o teto de envelopes por endpoint.

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