Integração
Webhooks
Em vez de a sua integração perguntar de tempo em tempo se algo mudou, o NewGestor avisa no momento em que acontece.
Um webhook é um endereço seu que o NewGestor chama com POST assim
que um evento ocorre — um cliente cadastrado, uma fatura paga. A requisição vai
assinada, então dá para ter certeza de que veio daqui.
Webhook e API resolvem problemas opostos e se completam. A API é você perguntando ao NewGestor; o webhook é o NewGestor avisando você. Cobrança automática costuma usar os dois: o webhook avisa que a fatura foi paga, a API busca o resto do que você precisa.
Como ativar
-
Abra a tela de webhooks
No painel, vá em Integração → Webhooks.
-
Informe a sua URL
Precisa ser pública, em
https, e aceitarPOSTcom corpo JSON. -
Escolha os eventos
Marque só o que a sua integração usa. Menos evento, menos chamada à toa.
-
Guarde a chave
Ela aparece uma única vez, igual ao token da API. É com ela que você confere a assinatura.
-
Clique em Testar
Um evento
pingé enviado na hora e a tela mostra o que o seu sistema respondeu.
Cada empresa pode ter até dois endereços cadastrados.
Pela API
O mesmo cadastro existe na API — útil quando a sua integração se configura sozinha, sem ninguém entrar no painel. As regras são as mesmas da tela.
curl -X POST "https://npanel.newgestor.com/api/v1/webhooks" \
-H "Authorization: Bearer SEU_TOKEN_AQUI" \
-H "Accept: application/json" \
-H "Content-Type: application/json" \
-d '{
"url": "https://seu-servidor.com/webhook",
"description": "Integração do financeiro",
"events": ["invoice.paid", "customer.created"]
}'{
"success": true,
"message": "Webhook criado. Guarde o secret agora: ele não será mostrado de novo.",
"data": {
"id": 14,
"url": "https://seu-servidor.com/webhook",
"events": ["invoice.paid", "customer.created"],
"active": true,
"secret": "whsec_b9Bb…"
}
}O secret aparece só nesta resposta. Guarde na hora:
nenhuma consulta depois devolve ele. Perdeu? Apague o webhook e crie outro.
A URL precisa usar https e não pode apontar para endereço interno
— localhost, 127.0.0.1, 192.168.x.x e afins são
recusados (proteção contra SSRF). Ela é conferida de novo a cada envio, não só no
cadastro: se o domínio passar a apontar para a rede interna depois, o envio para.
| Método | Endereço | O que faz |
|---|---|---|
| GET | /webhooks/events | Catálogo de eventos |
| GET | /webhooks | Lista os webhooks |
| POST | /webhooks | Cria — devolve o secret |
| GET | /webhooks/ | Busca um |
| PUT | /webhooks/ | Altera; active: true religa |
| DEL | /webhooks/ | Exclui |
| POST | /webhooks/ | Envia um ping e mostra a resposta |
| GET | /webhooks/ | Histórico de entregas |
| POST | /webhooks/deliveries/ | Reenvia uma entrega |
Aviso de uma fatura só: notification_url
Nem sempre compensa cadastrar um webhook para a empresa inteira. Ao gerar o PIX de
uma fatura, você pode mandar junto um notification_url: quando
aquela fatura for paga, o NewGestor avisa naquele endereço.
curl -X POST "https://npanel.newgestor.com/api/v1/invoices/1033077/pix" \
-H "Authorization: Bearer SEU_TOKEN_AQUI" \
-H "Accept: application/json" \
-H "Content-Type: application/json" \
-d '{ "notification_url": "https://seu-servidor.com/pagou" }'O aviso chega no mesmo formato de um invoice.paid, com os mesmos
cabeçalhos, as mesmas 6 tentativas e o mesmo tratamento de falha. A diferença é o
segredo: ele não vem de um webhook cadastrado, e sim de um segredo único da empresa,
que você consulta em GET /webhooks/callback-secret. A conferência da
assinatura é a mesma descrita abaixo.
A URL precisa usar https e não pode apontar para rede interna
(proteção SSRF). Ela é conferida antes de falar com o gateway:
um endereço recusado não deixa cobrança criada para trás.
Pedir de novo com o mesmo endereço não duplica o aviso — sai uma vez só.
Eventos disponíveis
| Evento | Quando dispara |
|---|---|
customer.created | Cliente cadastrado |
customer.updated | Dados do cliente alterados |
customer.deleted | Cliente removido |
customer.renewed | Acesso do cliente renovado |
customer.expired | Cliente venceu e não renovou |
invoice.created | Fatura gerada |
invoice.paid | Fatura paga |
Cabeçalhos que enviamos
POST /seu-endpoint HTTP/1.1
Content-Type: application/json
User-Agent: NewGestor-Webhooks/1.0
X-NewGestor-Event: invoice.paid
X-NewGestor-Delivery: evt_DLOKSFF1XM0AOLDPWOWCQFWJ
X-NewGestor-Timestamp: 1787836462
X-NewGestor-Signature: sha256=bf05efce91300ca3fdd2dd0027e9f38...Formato do corpo
O envelope é sempre o mesmo. Só o conteúdo de data muda conforme o evento.
{
"event": "invoice.paid",
"platform": "newgestor",
"id": "evt_DLOKSFF1XM0AOLDPWOWCQFWJ",
"api_version": "v1",
"occurred_at": "2026-08-22T19:59:18-03:00",
"company_id": 1290,
"data": { }
}invoice.paid
"data": {
"invoice": { "id": 1033077, "total_amount": "99.90", "status": "Pago" },
"customer": { "uuid": "9f3c...", "name": "Maria Souza" }
}customer.updated
O campo changed diz o que mudou — use para ignorar o que não interessa.
"data": {
"customer": { "uuid": "9f3c...", "name": "Maria Souza", "whatsapp": "5511988887777" },
"changed": ["name", "whatsapp"]
}customer.created
"data": {
"customer": {
"uuid": "9f3c...",
"name": "Maria Souza",
"username": "maria.souza",
"whatsapp": "5511988887777",
"email": "[email protected]",
"status": "Ativo",
"due_date": "2026-10-05",
"created_at": "2026-09-05T14:22:00-03:00",
"plan": { "name": "Mensal", "value": "50.00" },
"product": { "name": "Plano Full HD" }
}
}Conferir a assinatura
Toda requisição vai assinada com a sua chave. Confira antes de processar — é o que garante que o aviso veio do NewGestor e não de outra pessoa que descobriu o seu endereço.
A assinatura é o HMAC-SHA256 de timestamp + "." + corpo bruto.
Use o corpo exatamente como chegou, antes de qualquer conversão
para objeto — reserializar muda os espaços e a assinatura deixa de bater.
$corpo = file_get_contents('php://input');
$timestamp = $_SERVER['HTTP_X_NEWGESTOR_TIMESTAMP'] ?? '';
$assinatura = str_replace('sha256=', '', $_SERVER['HTTP_X_NEWGESTOR_SIGNATURE'] ?? '');
$esperado = hash_hmac('sha256', $timestamp . '.' . $corpo, SUA_CHAVE);
if (! hash_equals($esperado, $assinatura)) {
http_response_code(401);
exit;
}
if (abs(time() - (int) $timestamp) > 300) { // 5 minutos
http_response_code(408);
exit;
}
$evento = json_decode($corpo, true);
// ... trate $evento['event'] ...
http_response_code(200);const crypto = require('crypto');
app.post('/webhook', express.raw({ type: 'application/json' }), (req, res) => {
const corpo = req.body.toString('utf8');
const timestamp = req.get('X-NewGestor-Timestamp');
const assinatura = (req.get('X-NewGestor-Signature') || '').replace('sha256=', '');
const esperado = crypto.createHmac('sha256', SUA_CHAVE)
.update(timestamp + '.' + corpo)
.digest('hex');
if (!crypto.timingSafeEqual(Buffer.from(esperado), Buffer.from(assinatura))) {
return res.sendStatus(401);
}
const evento = JSON.parse(corpo);
res.sendStatus(200); // responda rapido
});import hmac, hashlib, time
from flask import request, abort
@app.post("/webhook")
def webhook():
corpo = request.get_data() # bytes, como chegou
timestamp = request.headers.get("X-NewGestor-Timestamp", "")
assinatura = request.headers.get("X-NewGestor-Signature", "").replace("sha256=", "")
esperado = hmac.new(
SUA_CHAVE.encode(),
f"{timestamp}.".encode() + corpo,
hashlib.sha256,
).hexdigest()
if not hmac.compare_digest(esperado, assinatura):
abort(401)
if abs(time.time() - int(timestamp)) > 300:
abort(408)
evento = request.get_json()
return "", 200Cuidados
Responda rápido
Desistimos após 10 segundos. Se o seu processamento for
demorado, guarde o evento e responda 200 na hora — processe depois.
Qualquer código 2xx confirma o recebimento.
Trate repetição pelo id
Se o seu sistema demorar ou falhar, reenviamos o mesmo
id. Guarde os que já processou e ignore os repetidos.
Sem esse cuidado, uma reentrega vira cobrança dobrada do seu lado. É o problema mais caro de quem integra webhook pela primeira vez.
Tentamos 6 vezes
Na hora e, se falhar, depois de 1 minuto, 5 minutos, 30 minutos, 2 horas e 6 horas.
Códigos 4xx — fora de 408 e 429 — são
tratados como recusa e não repetimos. Após 20 falhas seguidas o
webhook é desativado e o aviso aparece na tela do painel.