Pular para o conteúdo principal

Integrações por API e SGP

Este guia descreve como sistemas externos, como o SGP, podem enviar mensagens pelo FlashChat usando credenciais de API.

O endpoint principal é:

POST /api/chat/sms/add/{webhook_token}

webhook_token é o UUID do canal que será usado para o envio.

Autenticação

A API usa credenciais client_id e client_secret.

As credenciais podem ser enviadas no corpo da requisição, query string ou headers:

client_id: flash_xxxxxxxxx
client_secret: secret_xxxxxxxxx

Exemplo com headers:

curl -X POST "https://seudominio.com/api/chat/sms/add/00000000-0000-0000-0000-000000000000" \
-H "Content-Type: application/json" \
-H "client_id: flash_xxxxxxxxx" \
-H "client_secret: secret_xxxxxxxxx" \
-d '{"to":"558288094777","message":"Olá!"}'

ACL das credenciais API

Em Configurações > API Credentials, cada credencial pode ter ACL por:

  • Domínios permitidos.
  • IPs ou CIDRs permitidos.
  • Status ativo/inativo.

Listas vazias significam que não existe restrição naquele critério.

Se allowed_ips estiver preenchido, o IP da requisição precisa estar liberado.

Se allowed_domains estiver preenchido, a requisição precisa trazer Origin ou Referer compatível. Chamadas server-to-server, como python-requests, normalmente não enviam esses headers. Nesse caso, prefira ACL por IP/CIDR.

Quando a ACL bloqueia uma requisição, o sistema registra em APIRequestHistory:

  • Motivo do bloqueio.
  • client_id mascarado.
  • IP detectado.
  • Domínio detectado por Origin ou Referer, quando existir.
  • Headers como X-Forwarded-For, X-Real-IP e CF-Connecting-IP.
  • Body sanitizado, sem expor client_secret.

Exemplo de bloqueio:

{
"error": "api_acl_denied",
"reason": "ip_not_allowed",
"client_id": "flas******************************************ebQw",
"origin_domain": "",
"ip_address": "10.42.0.1",
"allowed_domains": [],
"allowed_ips": ["177.52.37.211"],
"user_agent": "python-requests/2.24.0",
"x_forwarded_for": "10.42.0.1, 10.42.0.223"
}

Respostas assíncronas

Os envios são processados por fila Celery.

Quando aceito, o endpoint retorna:

{
"status": "queued",
"task_id": "uuid-da-task"
}

Para templates:

{
"status": "queued",
"type": "template",
"task_id": "uuid-da-task"
}

Para fatura interativa:

{
"status": "queued",
"type": "invoice_template",
"task_id": "uuid-da-task"
}

Envio de mensagem simples

Contrato:

{
"to": "558288094777",
"message": "Olá, tudo bem?"
}

Também é aceito contact como alias de to:

{
"contact": "558288094777",
"message": "Olá, tudo bem?"
}

Quebra de mensagem

Use {quebrar_mensagem} para dividir o envio em partes.

{
"to": "558288094777",
"message": "Primeira parte{quebrar_mensagem}Segunda parte"
}

O intervalo entre partes usa a variável de sistema:

INTERVALO_MENSAGENS_SMS

Se não estiver configurada, o padrão é 3 segundos.

Envio de mídia

Contrato:

{
"to": "558288094777",
"message": "Segue o boleto em PDF.",
"media_url": "https://demo.sgp.net.br/boleto/100633-LGZI8TJOOZ.pdf"
}

A URL precisa ser pública e acessível pelo canal.

Para WhatsApp Cloud API, arquivos são enviados como document, image, video ou audio, de acordo com o tipo detectado.

Template Meta simples

Use type: "template" para enviar um template Meta aprovado com variáveis posicionais.

Contrato:

{
"type": "template",
"to": "558288094777",
"template": {
"name": "congrulations_user",
"language": "pt_BR",
"parameters": ["Cliente Nome"]
},
"metadata": {
"source": "sgp"
}
}

Esse contrato gera um payload Meta com parâmetros no BODY:

{
"type": "body",
"parameters": [
{
"type": "text",
"text": "Cliente Nome"
}
]
}

Template com header de imagem

Se o template foi criado na Meta com HEADER do tipo IMAGE, informe template.header.

{
"type": "template",
"to": "558288094777",
"template": {
"name": "congrulations_user",
"language": "pt_BR",
"header": {
"type": "image",
"link": "https://seudominio.com/aniversario.jpg"
},
"parameters": ["Cliente nome"]
}
}

Tipos de header suportados:

  • image
  • video
  • document

Para documento, é possível informar filename:

{
"header": {
"type": "document",
"link": "https://seudominio.com/arquivo.pdf",
"filename": "arquivo.pdf"
}
}

Fatura interativa Meta Payments BR

Use type: "invoice_template" para enviar fatura no formato especial da Meta com PDF no header e botão order_details.

Contrato:

{
"type": "invoice_template",
"to": "558288094777",
"template": {
"name": "invoice_request_user",
"language": "pt_BR"
},
"invoice": {
"customer_name": "Cliente nome",
"due_date": "2026-06-11",
"amount": "61.27",
"contract_id": "791",
"invoice_id": "100633",
"pdf_url": "https://demo.sgp.net.br/boleto/100633-LGZI8TJOOZ.pdf",
"digitable_line": "75691336010107152800203998430015814740000006127",
"pix_code": "000201010212...",
"pix_merchant_name": "Fibramais Telecom",
"pix_key": "27511969000183",
"pix_key_type": "CNPJ"
},
"metadata": {
"source": "sgp"
}
}

Campos obrigatórios

Campos obrigatórios do contrato:

  • type
  • to
  • template.name
  • template.language
  • invoice.customer_name
  • invoice.due_date
  • invoice.amount
  • invoice.contract_id
  • invoice.pdf_url

Pelo menos um dos campos abaixo deve existir:

  • invoice.pix_code
  • invoice.digitable_line

Quando pix_code for informado, estes campos também são obrigatórios:

  • invoice.pix_merchant_name
  • invoice.pix_key
  • invoice.pix_key_type

invoice_id é opcional. Quando informado, ele é usado como referência da cobrança. Quando não informado, o sistema usa contract_id.

aviso

O contrato é estrito. Placeholders não resolvidos, como {fatura_id} ou {cliente}, geram erro e não são enviados ao cliente.

Exemplo de integração SGP

O SGP pode enviar o contrato no campo message como JSON string.

Exemplo:

{
"contact": "558288094777",
"message": "{\"type\":\"invoice_template\",\"template\":{\"name\":\"invoice_request_user\",\"language\":\"pt_BR\"},\"invoice\":{\"customer_name\":\"Cliente Nome\",\"due_date\":\"31/05/2026\",\"amount\":\"93.79\",\"contract_id\":\"2577\",\"pdf_url\":\"https://demo.sgp.net.br/boleto/100634-TNZLQ8GDBF/\",\"digitable_line\":\"75691.30001 01071.528002 03998.500015 9 14700000009379\",\"pix_code\":\"000201010212...\",\"pix_merchant_name\":\"Fibramais Telecom\",\"pix_key\":\"00.000.000/0001-00\",\"pix_key_type\":\"CNPJ\"}}"
}

O endpoint detecta o type dentro do JSON e usa o contrato correto.

Se o conteúdo parecer um contrato de template, mas o JSON estiver inválido, a API retorna erro 400 e não envia como mensagem simples.

Validações importantes

O canal precisa suportar envio de template Meta. Atualmente, esse envio é suportado para:

  • whatsapp_cloud_api

Se o canal não suportar templates, a API retorna erro antes de enfileirar.

Erros comuns

Parameter format does not match format in the created template

Exemplo:

{
"message": "(#132012) Parameter format does not match format in the created template",
"details": "header: Format mismatch, expected IMAGE, received UNKNOWN"
}

Esse erro acontece quando o template aprovado na Meta possui header, mas o payload enviado não informa esse header.

Solução para header de imagem:

{
"template": {
"name": "congrulations_user",
"language": "pt_BR",
"header": {
"type": "image",
"link": "https://seudominio.com/imagem.jpg"
},
"parameters": ["Cliente Nome"]
}
}

Parameter value is not valid

Normalmente ocorre quando algum campo enviado à Meta contém valor inválido, vazio ou placeholder não resolvido.

Exemplo inválido:

{
"invoice_id": "{fatura_id}"
}

O FlashChat bloqueia esse caso antes de enviar à Meta.

Checklist para produção

Antes de liberar a integração:

  • Criar credencial em Configurações > API Credentials.
  • Configurar ACL por IP/CIDR quando a origem for server-to-server.
  • Confirmar que o Kubernetes/Traefik preserva IP real, se ACL por IP público for usada.
  • Confirmar que o canal usado é whatsapp_cloud_api.
  • Confirmar que o template Meta está aprovado.
  • Enviar todos os parâmetros do template já resolvidos.
  • Usar URLs públicas para PDF, imagem, vídeo ou documento.