Webhooks
Webhooks avisam o seu sistema na hora em que algo acontece (um signatário assinou, o envelope foi concluído), sem que você precise consultar a API repetidamente. Você cadastra um endereço HTTPS e o Ravisign envia um POST JSON a cada evento, assinado com HMAC-SHA256.
Os webhooks podem ser cadastrados pela API (ações abaixo) ou pelo painel, em Configurações > Webhooks.
Nos exemplos, a chave está na variável de ambiente RAVISIGN_CHAVE e as respostas foram encurtadas onde indicado:
export RAVISIGN_CHAVE="rsg_..."
API="https://ravisign.com.br/api/v1"webhooks/criar#
POST, escopo envelopes.escrever. Parâmetros url (https, endereço público, até 500 caracteres) e eventos
(lista ou texto separado por vírgula; vazio = todos os eventos). Até 10 webhooks por conta (409 webhook_limite).
curl -sS "$API/webhooks/criar" -H "Authorization: Bearer $RAVISIGN_CHAVE" \
-H "Content-Type: application/json" \
-d '{"url":"https://integrador.exemplo.com.br/ravisign","eventos":["envelope.concluido","signatario.otp_solicitado"]}'{
"ok": true,
"segredo": "rsgw_48e39ee70a218e351b7020ec4016abc4f917c72ca44356c8",
"webhook": {
"id": 1,
"url": "https://integrador.exemplo.com.br/ravisign",
"eventos": ["envelope.concluido", "signatario.otp_solicitado"],
"ativo": true,
"criado_em": "2026-10-09T20:28:25-03:00",
"ultima_entrega": null
}
}O segredo aparece só nesta resposta: guarde-o para verificar a assinatura das entregas (veja Webhooks). Erros: 400
webhook_url_invalida (sem https, endereço interno ou inválido), 400 webhook_eventos_invalidos.
webhooks/listar#
GET, escopo envelopes.ler. Webhooks da conta, sem o segredo, com a última entrega.
curl -sS "$API/webhooks/listar" -H "Authorization: Bearer $RAVISIGN_CHAVE"{
"ok": true,
"webhooks": [
{
"id": 1,
"url": "https://integrador.exemplo.com.br/ravisign",
"eventos": ["envelope.concluido", "signatario.otp_solicitado"],
"ativo": true,
"criado_em": "2026-10-09T20:28:25-03:00",
"ultima_entrega": {
"situacao": "entregue",
"http_status": 200,
"tentativas": 1,
"criada_em": "2026-10-09T20:31:02-03:00",
"entregue_em": "2026-10-09T20:31:03-03:00"
}
}
]
}ultima_entrega é null enquanto não houver entrega.
webhooks/testar#
POST, escopo envelopes.escrever. Parâmetro id. Envia na hora um evento webhook.teste ao endereço e devolve o
resultado.
curl -sS "$API/webhooks/testar" -H "Authorization: Bearer $RAVISIGN_CHAVE" \
-H "Content-Type: application/json" -d '{"id":1}'{ "ok": true, "id": 1, "entregue": true, "situacao": "entregue", "http_status": 200 }Se o destino não responder 2xx, entregue vem false, situacao vem pendente (a entrega segue as novas
tentativas descritas em Webhooks) e http_status traz o status recebido (ou null sem resposta). Situações de uma entrega:
pendente, entregue e falhou (tentativas esgotadas).
webhooks/remover#
POST, escopo envelopes.escrever. Parâmetro id.
curl -sS "$API/webhooks/remover" -H "Authorization: Bearer $RAVISIGN_CHAVE" \
-H "Content-Type: application/json" -d '{"id":1}'{ "ok": true, "id": 1, "removido": true }Eventos e entregas#
O Ravisign avisa o seu sistema com um POST JSON a cada evento em que o webhook está inscrito.
| Evento | Quando | dados |
|---|---|---|
envelope.enviado |
o envelope foi enviado aos signatários | {} |
signatario.visualizou |
o signatário abriu o documento | signatario |
signatario.assinou |
o signatário assinou | signatario |
signatario.recusou |
o signatário recusou (o envelope fica recusado) |
signatario |
envelope.concluido |
todos assinaram e a via final está pronta | hash_final |
envelope.expirado |
o prazo venceu sem todas as assinaturas | {} |
envelope.cancelado |
o envelope foi cancelado | {} |
signatario.otp_solicitado |
no canal conversa, o signatário pediu um código novo na página | signatario, codigo, validade_minutos, expira_em |
webhook.teste |
webhooks/testar (o envelope do corpo vem null) |
mensagem |
signatario nos dados é { "uuid", "papel", "ordem" }. O corpo nunca traz nome, e-mail, telefone ou CPF: use os
uuids para cruzar com o que o seu sistema já tem.
Exemplo de corpo (envelope.concluido):
{
"evento": "envelope.concluido",
"ocorrido_em": "2026-10-09T23:31:02Z",
"envelope": {
"uuid": "157b650a-75e0-4eaa-a32c-b92b5a432ee4",
"referencia_externa": "PEDIDO-1042",
"situacao": "concluido",
"origem": "chatisp"
},
"dados": { "hash_final": "7ced225baf8e20d34cb09a713c4454a632f749ecf31645aa3a640e1660e2a880" }
}Exemplo de corpo (signatario.otp_solicitado):
{
"evento": "signatario.otp_solicitado",
"ocorrido_em": "2026-10-09T23:40:00Z",
"envelope": {
"uuid": "157b650a-75e0-4eaa-a32c-b92b5a432ee4",
"referencia_externa": "PEDIDO-1042",
"situacao": "enviado",
"origem": "chatisp"
},
"dados": {
"signatario": { "uuid": "7eb90fca-1488-4a17-84c4-0b01f4acb9f1" },
"codigo": "815204",
"validade_minutos": 30,
"expira_em": "2026-10-10T00:10:00Z"
}
}Cabeçalhos de cada entrega:
| Cabeçalho | Conteúdo |
|---|---|
Content-Type |
application/json |
User-Agent |
Ravisign-Webhook/1 |
X-Ravisign-Evento |
o evento (igual ao evento do corpo) |
X-Ravisign-Entrega |
identificador da entrega; o mesmo em todas as tentativas (use para ignorar repetições) |
X-Ravisign-Tentativa |
número da tentativa (1 a 8) |
X-Ravisign-Assinatura |
sha256= seguido do HMAC-SHA256 do corpo, em hexadecimal, com o segredo do webhook |
Entrega e novas tentativas:
- Responda com qualquer status 2xx em até 10 segundos. Processe o evento depois de responder, se for demorado.
- Sem 2xx (ou sem resposta), o Ravisign tenta de novo após 1, 5, 15, 60 e 240 minutos e, dali em diante, a cada 240 minutos, até 8 tentativas no total. Redirecionamentos não são seguidos.
- O destino precisa ser https com endereço público.
- A ordem de chegada não é garantida: use
ocorrido_eme, na dúvida, confirme comenvelopes/detalhe.
Verificação da assinatura (PHP)#
Calcule o HMAC sobre o corpo BRUTO recebido (antes de decodificar o JSON) e compare em tempo constante:
<?php
$segredo = getenv('RAVISIGN_WEBHOOK_SEGREDO'); // o "segredo" devolvido por webhooks/criar
$corpo = file_get_contents('php://input');
$recebida = $_SERVER['HTTP_X_RAVISIGN_ASSINATURA'] ?? '';
$esperada = 'sha256=' . hash_hmac('sha256', $corpo, $segredo);
if (!hash_equals($esperada, $recebida)) {
http_response_code(401);
exit;
}
$entrega = $_SERVER['HTTP_X_RAVISIGN_ENTREGA'] ?? '';
// se esta entrega já foi processada (mesmo X-Ravisign-Entrega), apenas responda 200
$evento = json_decode($corpo, true);
http_response_code(200); // responda logo; o trabalho pesado vai para depois
switch ($evento['evento']) {
case 'envelope.concluido':
// baixar a via final com documentos/baixar e guardar $evento['dados']['hash_final']
break;
case 'signatario.otp_solicitado':
// entregar $evento['dados']['codigo'] na conversa do signatário $evento['dados']['signatario']['uuid']
break;
}Fale com o suporte da Ravi Systems pelo e-mail abaixo.