Pular para o conteúdo principal

Webhooks

Um webhook é uma URL da sua aplicação que o Signer chama quando algo acontece com um documento da sua organização. Por exemplo, o Signer envia um POST para essa URL quando um participante assina um documento ou quando o fluxo termina.

Use webhooks para acompanhar documentos. Sem webhooks, sua aplicação precisa consultar GET /api/documents/{id} repetidas vezes até o estado mudar. Essa técnica se chama polling (consulta periódica). Com webhooks, o Signer avisa a sua aplicação logo depois do evento.

Como funciona​

O diagrama mostra o caminho de um evento, desde a ação do participante até a sua aplicação:

Participante Signer Sua aplicação
| | |
|-- assina -------->| |
| |-- POST https://sua-url ---------->| 1. Verifica o cabeçalho de autenticação
| | { "type": ..., "data": ... } |
| |<-- 200 OK ------------------------| 2. Responde na hora
| | | 3. Processa o evento em segundo plano
| | |

Se a sua aplicação não responder 2xx, o Signer tenta enviar o evento de novo mais tarde. A seção Entrega, retentativas e ordem explica as regras de envio.

Para integrar webhooks, faça estes passos:

  1. Cadastre a URL do webhook na sua organização.
  2. Escolha como o Signer autentica a chamada.
  3. Crie o endpoint que recebe os eventos.
  4. Use a página Referência dos eventos para ler os dados de cada tipo de evento.

Cadastrar um webhook​

  1. No menu lateral, clique em Organizações e selecione a sua organização.
  2. Na seção Integração, ative Habilitar webhooks.
  3. No campo URL, informe a URL que vai receber os eventos. Use HTTPS.
  4. Em Tipo de autenticação, escolha como o Signer autentica a chamada. Veja Autenticar a chamada.
  5. Se você escolheu um tipo diferente de Sem autenticação, informe o segredo em Token de Autenticação.
  6. Clique em Salvar.

Seção Integração da tela de Organizações, com a opção Habilitar webhooks e o campo URL

Limites
  • Uma organização pode ter vários webhooks. Todos os webhooks recebem todos os eventos.
  • A configuração MaxWebhooksPerOrganization da instância define o limite de webhooks por organização. O padrão é 5. Se a organização já está no limite, o Signer não aceita um novo webhook.
  • Organizações pessoais não têm webhooks.

Autenticar a chamada​

O Signer não assina o corpo da requisição. Para mostrar que a chamada vem do Signer, ele envia um cabeçalho com o token que você cadastrou. O Tipo de autenticação define qual cabeçalho o Signer envia:

Tipo de autenticaçãoCabeçalho enviado
Sem autenticaçãoNenhum
BasicAuthorization: Basic <token>
BearerAuthorization: Bearer <token>
X-Api-KeyX-Api-Key: <token>
aviso

Use HTTPS e um tipo de autenticação diferente de Sem autenticação. Verifique o cabeçalho em toda requisição antes de processar o evento. Sem essa verificação, qualquer pessoa que conheça a sua URL pode enviar eventos falsos.

Modo Basic

O Signer envia o token exatamente como você cadastrou e não codifica nada. No modo Basic, cadastre o valor já codificado em Base64, no formato usuario:senha.

Receber webhooks no código​

Os exemplos abaixo mostram um endpoint mínimo em cada linguagem. Cada endpoint faz quatro coisas, na mesma ordem dos números nos comentários do código:

  1. Verifica o cabeçalho de autenticação.
  2. Responde 200 imediatamente.
  3. Ignora eventos repetidos.
  4. Consulta o documento antes de agir.

Os exemplos são versões reduzidas do WebhookEndpointScenario do repositório SignerSamples. Eles não usam framework web. O C# usa HttpListener, o Java usa o HttpServer do JDK, o Node.js usa o módulo http e o PHP usa o servidor embutido. Os cenários completos também mostram como testar o endpoint com curl.

using Lacuna.Signer.Api;
using Newtonsoft.Json.Linq;

// "Bearer <token>": o token cadastrado no webhook, com authType Bearer
private static readonly string ExpectedAuthorization = "Bearer " + Environment.GetEnvironmentVariable("SIGNER_WEBHOOK_TOKEN");
// Chaves dos eventos já recebidos; em produção, use armazenamento durável, como uma tabela com chave única
private readonly ConcurrentDictionary<string, bool> receivedEvents = new ConcurrentDictionary<string, bool>();

// Chamado para cada requisição de um HttpListener iniciado em http://localhost:8080/
private async Task HandleRequestAsync(HttpListenerContext context)
{
var request = context.Request;
var response = context.Response;

// 1. Verifique o cabeçalho de autenticação: o Signer não assina o corpo
if (!IsAuthorized(request.Headers["Authorization"]))
{
response.StatusCode = 401;
response.Close();
return;
}

// O corpo é { "type": "...", "data": { ... } }. Leia-o como JSON, e não como WebhookModel,
// que rejeita os tipos de evento que o seu enum WebhookTypes não lista.
string body;
using (var reader = new StreamReader(request.InputStream, Encoding.UTF8))
{
body = await reader.ReadToEndAsync();
}
var webhook = JObject.Parse(body);

// 3. Seja idempotente. O GetEventKey (do exemplo) junta o type, o id do documento e o flowActionId.
var isNew = receivedEvents.TryAdd(GetEventKey(webhook), true);

// 2. Responda 200 imediatamente (também a um evento repetido, para o Signer parar de enviá-lo) e só então processe
response.StatusCode = 200;
response.Close();
if (!isNew)
{
return;
}

// 4. Não confie na ordem dos eventos: consulte o documento antes de agir
if ((string)webhook["type"] == nameof(WebhookTypes.DocumentConcluded))
{
var document = await signerClient.GetDocumentDetailsAsync((Guid)webhook["data"]["id"]);
if (document.Status == DocumentStatus.Concluded)
{
// Baixe o arquivo assinado, atualize os seus registros...
}
}
}

private static bool IsAuthorized(string authorization)
{
// Compare hashes SHA-256, para que o tempo da comparação não revele quanto do token coincidiu
using (var sha256 = SHA256.Create())
{
var expected = sha256.ComputeHash(Encoding.UTF8.GetBytes(ExpectedAuthorization));
var actual = sha256.ComputeHash(Encoding.UTF8.GetBytes(authorization ?? ""));
return actual.SequenceEqual(expected);
}
}

Veja os endpoints completos: C# · Java · PHP · Node.js. Para criar o cliente usado nos exemplos, veja Criar documentos.

Tipos de evento nas bibliotecas cliente

O enum WebhookTypes do cliente .NET e do cliente PHP não tem DocumentDeleted. Isso vale para o Lacuna.Signer.Api 1.67.0, que o Lacuna.Signer.Client 1.24.0 instala, e para o cliente PHP 1.4.10. Os enums dos clientes Java e Node.js têm DocumentDeleted.

Se o enum da sua biblioteca não lista um tipo de evento, compare o type do corpo como texto. Os exemplos C# e PHP acima fazem essa comparação.

Eventos​

O corpo de toda requisição tem o formato { "type": ..., "data": ... }. O campo type diz o tipo do evento, como DocumentSigned ou DocumentConcluded. O conteúdo de data muda conforme o tipo.

Para ver a lista dos tipos, os campos de cada evento e exemplos de corpo, veja a página Referência dos eventos.

Entrega, retentativas e ordem​

Esta seção explica como o Signer envia os eventos. A maior parte dos problemas de integração vem dessas regras.

Entrega assíncrona​

O Signer não envia o evento no mesmo instante da ação do usuário. Um processo em segundo plano envia cada evento, em uma fila de baixa prioridade. Por isso, um pequeno atraso é normal.

Se a organização tem mais de um webhook, o Signer envia o evento para cada webhook separadamente. Uma falha em um webhook não afeta os outros.

Retentativas​

Sua aplicação deve responder com um código 2xx. Se ela responder com outro código, ou se a conexão falhar, o Signer marca a entrega como falha. Depois, o Signer tenta enviar o evento de novo, até 10 vezes. O tempo de espera aumenta a cada tentativa:

Nova tentativaEspera depois da falha anterior
1ª15 a 45 segundos
2ª15 segundos a 1 minuto e 15 segundos
3ª30 segundos a 2 minutos
4ª1 minuto e 35 segundos a 3 minutos e 30 segundos
5ª4 minutos e 30 segundos a 7 minutos
6ª10 minutos e 40 segundos a 13 minutos e 30 segundos
7ª22 a 25 minutos
8ª40 a 44 minutos
9ª1 hora e 8 minutos a 1 hora e 13 minutos
10ª1 hora e 50 minutos a 1 hora e 55 minutos

As 10 novas tentativas levam, no total, de 4 horas e 20 minutos a 4 horas e 45 minutos depois da primeira falha. O tempo exato de cada espera tem uma parte aleatória. Por isso, a tabela mostra faixas. Depois da 10ª falha, o Signer não envia mais aquele evento.

Em cada nova tentativa, o Signer monta o evento de novo, com os dados atuais do documento. A verificação de estado descrita em Ordem dos eventos também vale para cada nova tentativa.

O Signer registra no log o status e o corpo da resposta de cada falha. Se você investigar um problema de entrega, peça esses registros ao administrador da instância.

Entregas repetidas​

Por causa das retentativas, o mesmo evento pode chegar mais de uma vez. Torne o processamento idempotente, isto é, seguro para executar mais de uma vez com o mesmo evento. Para reconhecer um evento já processado, use o type, o id do documento e, se existir, o flowActionId.

Ordem dos eventos​

O Signer não garante a ordem dos eventos, porque processos independentes fazem as entregas. Por exemplo, o DocumentConcluded de um documento pode chegar antes do DocumentSigned do mesmo documento.

Antes de enviar alguns eventos, o Signer verifica se o documento ainda está no estado do evento. Se o estado mudou, o Signer descarta o evento. Por exemplo, se alguém pausar e retomar um documento logo em seguida, sua aplicação pode receber só o DocumentResumed, sem o DocumentPaused. Essa verificação vale para DocumentConcluded, DocumentCanceled, DocumentPaused, DocumentResumed e DocumentExpired.

Boas práticas​

  • Responda 200 imediatamente e processe o evento depois, em segundo plano. Se o endpoint demorar, a chamada passa do tempo limite (timeout) e o Signer tenta de novo sem necessidade.
  • Verifique o cabeçalho de autenticação em toda requisição.
  • Mantenha a URL estável e acessível. O Signer precisa chegar à URL pela internet. Em instalações on-premises, o Signer precisa chegar à URL pela rede onde o servidor dele está.
  • Registre os eventos recebidos. Esse registro ajuda a encontrar diferenças entre o seu sistema e o Signer.

Solução de problemas​

Se você precisar de mais detalhes sobre uma falha de entrega, peça os logs do Signer ao administrador da instância. Para cada falha, o log mostra o código de status, o corpo da resposta e a URL chamada.

Se você corrigir a URL ou o token de um webhook, as próximas tentativas de um evento que falhou já usam o valor novo. O Signer lê a configuração do webhook a cada tentativa.

Sua aplicação não recebe nenhum evento​

Causa possívelComo resolver
A opção Habilitar webhooks está desativada.Em Organizações, seção Integração, ative Habilitar webhooks e clique em Salvar.
O webhook foi cadastrado depois da ação no documento.O Signer envia o evento só para os webhooks que existem no momento da ação. Ele não envia eventos de ações anteriores ao cadastro.
O documento está em uma organização pessoal.Organizações pessoais não têm webhooks. Crie o documento em uma organização que tenha o webhook cadastrado.
O Signer não consegue se conectar à URL. Por exemplo, o nome do servidor não existe, um firewall bloqueia a porta ou a URL só funciona na sua rede interna.Verifique se a URL responde a partir de uma máquina fora da sua rede, por exemplo com curl -X POST <url>. Em instalações on-premises, faça o teste a partir do servidor do Signer.
O certificado HTTPS da URL não é válido. Por exemplo, ele é autoassinado, expirou ou não traz a cadeia completa.O Signer recusa a conexão quando o certificado não é válido. Use um certificado emitido por uma autoridade certificadora confiável e configure a cadeia completa no servidor.

Sua aplicação responde 401 ou 403​

Causa possívelComo resolver
O Tipo de autenticação do webhook não é o que o seu endpoint espera. Por exemplo, o webhook usa X-Api-Key e o endpoint lê o cabeçalho Authorization.Escolha no webhook o tipo que o endpoint lê. Veja os cabeçalhos de cada tipo em Autenticar a chamada.
O token cadastrado no webhook é diferente do token que o endpoint compara.Cadastre de novo o token no webhook e no endpoint. Verifique se não há espaço ou quebra de linha no começo ou no fim do token.
No modo Basic, o token não está codificado em Base64.O Signer envia o token sem codificar. Cadastre o valor de usuario:senha já codificado em Base64.
Um proxy ou gateway entre o Signer e a sua aplicação remove ou troca o cabeçalho de autenticação.Verifique a configuração do proxy ou do gateway. Ele deve passar o cabeçalho Authorization ou X-Api-Key para a sua aplicação.

O mesmo evento chega várias vezes​

Causa possívelComo resolver
Sua aplicação respondeu com um código diferente de 2xx.Responda 200 também para um evento que você já processou. Se você responder com erro, o Signer tenta de novo.
Sua aplicação demorou mais de 100 segundos para responder.O Signer cancela a chamada depois de 100 segundos e tenta de novo. Responda 200 logo que receber o evento e processe o evento depois, em segundo plano.
As retentativas são normais.Torne o processamento idempotente. Veja Entregas repetidas.

Sua aplicação recebe um GET ou um corpo vazio​

Causa possívelComo resolver
A URL cadastrada responde com um redirecionamento (301 ou 302). Ao seguir esse redirecionamento, o Signer troca o POST por um GET, sem corpo.Cadastre a URL final, que responde sem redirecionar. Confira o protocolo (https), o domínio (com ou sem www) e a barra no fim do caminho.
A URL redireciona de https para http.O Signer não segue esse redirecionamento, e a entrega falha. Cadastre a URL https final.

Um evento esperado não chegou​

Causa possívelComo resolver
O estado do documento mudou antes do envio. Por exemplo, alguém pausou e retomou o documento logo em seguida.O Signer descarta o evento quando o documento já não está no estado do evento. Veja Ordem dos eventos.
Alguém removeu o webhook antes do envio.O Signer não envia o evento para um webhook removido.
As 10 novas tentativas falharam.O Signer não envia mais esse evento. Corrija a causa da falha para que os próximos eventos cheguem. Veja Retentativas.

Outros problemas​

ProblemaCausa e solução
O Signer não aceita um novo webhook.A organização chegou ao limite de webhooks, definido pela configuração MaxWebhooksPerOrganization (5 por padrão). Remova um webhook ou peça ao administrador da instância para mudar o limite.
A lista documents de um DocumentDeleted não traz todos os documentos excluídos.Em exclusões da organização ou de uma pasta, a lista traz no máximo 100 documentos. Veja Referência dos eventos.

Veja também​

Ver em Markdown