Skip to content
Ravisign

Webhooks

Webhooks notify your system the moment something happens (a signer signed, the envelope was completed), without you having to query the API repeatedly. You register an HTTPS address and Ravisign sends a JSON POST for each event, signed with HMAC-SHA256.

Webhooks can be registered through the API (actions below) or in the panel, in Settings > Webhooks.

In the examples, the key is in the RAVISIGN_CHAVE environment variable and the responses were shortened where indicated:

BASH
export RAVISIGN_CHAVE="rsg_..."
API="https://ravisign.com.br/api/v1"

webhooks/criar#

POST, scope envelopes.escrever. Parameters url (https, public address, up to 500 characters) and eventos (list or comma-separated text; empty = all events). Up to 10 webhooks per account (409 webhook_limite).

BASH
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"]}'
JSON
{
    "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
    }
}

The segredo appears only in this response: keep it to verify the signature of deliveries (see Webhooks). Errors: 400 webhook_url_invalida (no https, internal or invalid address), 400 webhook_eventos_invalidos.

webhooks/listar#

GET, scope envelopes.ler. The account's webhooks, without the secret, with the last delivery.

BASH
curl -sS "$API/webhooks/listar" -H "Authorization: Bearer $RAVISIGN_CHAVE"
JSON
{
    "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 is null while there has been no delivery.

webhooks/testar#

POST, scope envelopes.escrever. Parameter id. Immediately sends a webhook.teste event to the address and returns the result.

BASH
curl -sS "$API/webhooks/testar" -H "Authorization: Bearer $RAVISIGN_CHAVE" \
  -H "Content-Type: application/json" -d '{"id":1}'
JSON
{ "ok": true, "id": 1, "entregue": true, "situacao": "entregue", "http_status": 200 }

If the destination does not respond 2xx, entregue is false, situacao is pendente (the delivery follows the new attempts described in Webhooks) and http_status contains the status received (or null with no response). Statuses of a delivery: pendente, entregue and falhou (attempts exhausted).

webhooks/remover#

POST, scope envelopes.escrever. Parameter id.

BASH
curl -sS "$API/webhooks/remover" -H "Authorization: Bearer $RAVISIGN_CHAVE" \
  -H "Content-Type: application/json" -d '{"id":1}'
JSON
{ "ok": true, "id": 1, "removido": true }

Events and deliveries#

Ravisign notifies your system with a JSON POST for each event the webhook is subscribed to.

Event When dados
envelope.enviado the envelope was sent to the signers {}
signatario.visualizou the signer opened the document signatario
signatario.assinou the signer signed signatario
signatario.recusou the signer declined (the envelope becomes recusado) signatario
envelope.concluido everyone signed and the final copy is ready hash_final
envelope.expirado the deadline passed without all signatures {}
envelope.cancelado the envelope was canceled {}
signatario.otp_solicitado on the conversation channel, the signer requested a new code on the page signatario, codigo, validade_minutos, expira_em
webhook.teste webhooks/testar (the body's envelope is null) mensagem

signatario in the data is { "uuid", "papel", "ordem" }. The body never includes name, email address, phone number or CPF: use the uuids to match with what your system already has.

Example body (envelope.concluido):

JSON
{
    "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" }
}

Example body (signatario.otp_solicitado):

JSON
{
    "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"
    }
}

Headers of each delivery:

Header Content
Content-Type application/json
User-Agent Ravisign-Webhook/1
X-Ravisign-Evento the event (same as evento in the body)
X-Ravisign-Entrega delivery identifier; the same in all attempts (use it to ignore repeats)
X-Ravisign-Tentativa attempt number (1 to 8)
X-Ravisign-Assinatura sha256= followed by the HMAC-SHA256 of the body, in hexadecimal, with the webhook secret

Delivery and retries:

  • Respond with any 2xx status within 10 seconds. Process the event after responding, if it takes long.
  • Without 2xx (or without a response), Ravisign tries again after 1, 5, 15, 60 and 240 minutes and, from then on, every 240 minutes, up to 8 attempts in total. Redirects are not followed.
  • The destination must be https with a public address.
  • The order of arrival is not guaranteed: use ocorrido_em and, if in doubt, confirm with envelopes/detalhe.

Signature verification (PHP)#

Calculate the HMAC over the RAW body received (before decoding the JSON) and compare in constant time:

PHP
<?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;
}
Did not find what you were looking for?

Contact Ravi Systems support at the e-mail below.

contato@ravisystems.com.br