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_idmascarado.- IP detectado.
- Domínio detectado por
OriginouReferer, quando existir. - Headers como
X-Forwarded-For,X-Real-IPeCF-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:
imagevideodocument
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:
typetotemplate.nametemplate.languageinvoice.customer_nameinvoice.due_dateinvoice.amountinvoice.contract_idinvoice.pdf_url
Pelo menos um dos campos abaixo deve existir:
invoice.pix_codeinvoice.digitable_line
Quando pix_code for informado, estes campos também são obrigatórios:
invoice.pix_merchant_nameinvoice.pix_keyinvoice.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.
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.