Escute eventos da sua organização no Autentique através de seus endpoints de webhooks
Porque usar webhooks?
Ao desenvolver integrações com a Autentique, pode ser interessante que suas aplicações recebam eventos conforme eles ocorrem nas suas organizações.
Para começar a receber webhooks, é necessário registrar seus endpoints no painel. Após o registro, o Autentique pode enviar dados de eventos em tempo real para seus endpoints de webhook sempre que ocorrerem eventos na sua organização. O Autentique utiliza HTTPS para enviar esses eventos como um payload JSON que inclui um objeto Event.
Receber eventos de webhook é especialmente útil para acompanhar eventos assíncronos, como quando um signatário assina um documento, um documento é completado, ou quando ações relacionadas ao processamento de documentos são concluídas.
Objeto do Evento
O evento a seguir mostra um `update` no nome de um documento.
Todos os webhooks enviados são referentes à um evento de determinado recurso. Esse é informado pelo campo type. Da mesma forma, o campo data.object corresponde ao recurso do evento.
Objeto data e previous_attributes
Para os eventos *.updated, o payload do evento inclui o campo data.previous_attributes que permite que você inspecione o que mudou no referente recurso. No evento document.updated usado como exemplo acima, é indicado que o documento possuía o nome "teste" anteriormente.
Como Começar
Adicione seu Endpoint no Painel de desenvolvedor do Autentique, selecionando os eventos que deseja escutar.
Configure uma função de HTTPS que aceite solicitações de webhooks com um método POST.
Processe solicitações POST com um conteúdo JSON que consiste em um objeto do evento.
Retorne rapidamente um código de status de êxito (2xx) antes de qualquer lógica complexa que possa esgotar um tempo limite. Por exemplo, você precisa retornar uma resposta 200 antes de atualizar os dados do document no seu sistema.
$payload = @file_get_contents('php://input');
$webhook = null;
//Antes de processar o payloa
try {
$webhook = json_decode($payload, true);
} catch(\UnexpectedValueException $e) {
// Invalid payload
http_response_code(400);
exit();
}
$event = $webhook['event'];
// processa o event
switch ($event['type']) {
case 'document.created':
$document = $event['data']['object']; // Contém um objeto de documento
// Então defina um método para processar esse documento
// handleDocumentCreated($document);
break;
case 'signature.accepted':
$signature = $event['data']['object']; // contém um objeto de assinatura
// Então defina um método para processar essa assinatura
// handleSignatureAccepted($signature);
break;
// ... processe outros tipos de evento
default:
echo 'Received unknown event type '.$event['type'];
}
http_response_code(200);
package main
import (
"encoding/json"
"fmt"
"io/ioutil"
"net/http"
)
type WebhookPayload struct {
ID string `json:"id"`
Object string `json:"object"`
Name string `json:"name"`
Format string `json:"format"`
URL string `json:"url"`
Event Event `json:"event"`
}
type Event struct {
ID string `json:"id"`
Object string `json:"object"`
Organization int `json:"organization"`
Type string `json:"type"`
Data map[string]interface{} `json:"data"`
CreatedAt string `json:"created_at"`
}
func webhookHandler(w http.ResponseWriter, r *http.Request) {
payload, err := ioutil.ReadAll(r.Body)
if err != nil {
http.Error(w, "Invalid payload", http.StatusBadRequest)
return
}
var webhook WebhookPayload
if err := json.Unmarshal(payload, &webhook); err != nil {
http.Error(w, "Invalid payload", http.StatusBadRequest)
return
}
event := webhook.Event
eventData := event.Data
eventObject := eventData["object"].(map[string]interface{})
switch event.Type {
case "document.created":
// handleDocumentCreated(eventObject)
fmt.Println("Document created:", eventObject)
case "document.updated":
// handleDocumentUpdated(eventObject)
fmt.Println("Document updated:", eventObject)
case "signature.accepted":
// handleSignatureAccepted(eventObject)
fmt.Println("Signature accepted:", eventObject)
default:
fmt.Printf("Received unknown event type: %s\n", event.Type)
}
w.WriteHeader(http.StatusOK)
}
func main() {
http.HandleFunc("/webhook", webhookHandler)
http.ListenAndServe(":8080", nil)
}
class WebhooksController < ApplicationController
skip_before_action :verify_authenticity_token
def webhook
begin
payload = JSON.parse(request.body.read)
event = payload['event']
event_type = event['type']
event_data = event['data']
event_object = event_data['object']
case event_type
when 'document.created'
# handle_document_created(event_object)
puts "Document created: #{event_object}"
when 'document.updated'
# handle_document_updated(event_object)
puts "Document updated: #{event_object}"
when 'signature.accepted'
# handle_signature_accepted(event_object)
puts "Signature accepted: #{event_object}"
else
puts "Received unknown event type: #{event_type}"
end
render json: { status: 'success' }, status: :ok
rescue => e
render json: { error: 'Invalid payload' }, status: :bad_request
end
end
end
Ordem de eventos
O Autentique não garante a entrega dos eventos na ordem em que foram gerados. Por exemplo, a criação de um documento pode gerar os seguintes eventos:
document.updated
document.created
signature.created
signature.viewed (se o autor for um signatário ao criar o documento)
Seu endpoint não deve esperar a entrega desses eventos nesta ordem e deve processá-la de acordo. Você também pode usar a API para recuperar objetos ausentes (por exemplo, você pode obter as assinaturas, pastas e organizações usando as informações de document.created se receber esse evento primeiro).
Práticas Recomendadas para Uso de Webhooks
Revise essas práticas recomendadas para garantir que seus webhooks permaneçam seguros e funcionem bem com sua integração.
Retornar rapidamente uma resposta 2xx
O endpoint precisa retornar rapidamente um código de status de êxito (2xx) antes de qualquer lógica complexa que possa esgotar um tempo limite. Por exemplo, ao receber um document.finished você precisa retornar uma resposta 200 antes de atualizar os dados do documento no seu sistema.
Gerencie Eventos de Forma Assíncrona
Configure o gerenciador para processar eventos recebidos com uma fila assíncrona. Processar eventos de forma síncrona pode causar problemas de escalabilidade, especialmente durante picos de entregas de webhook.
Uso de Filas: Utilize filas assíncronas para processar eventos simultâneos a uma taxa que seu sistema consiga suportar.
Gerenciar Eventos Duplicados
Ocasionalmente, os endpoints de webhook podem receber o mesmo evento mais de uma vez. Para se proteger contra recibos de eventos duplicados:
Registre os IDs de Evento: Armazene os IDs dos eventos que você processou e ignore eventos já registrados.
Identificação de Duplicatas: Em alguns casos, dois webhooks do mesmo evento podem ser enviados para seu endpoint, use o ID do objeto em event.data junto com o event.type.
Ouça Apenas os Tipos de Eventos Necessários
Configure seus endpoints de webhook para receber somente os tipos de eventos exigidos pela sua integração. Escutar eventos adicionais ou todos os eventos pode sobrecarregar seu servidor e não é recomendável.
Configuração de Eventos: Você pode alterar os eventos que um endpoint de webhook recebe no Painel.
Rota de Webhook Isenta de Proteção contra CSRF
Se estiver usando frameworks como Rails, Django ou Laravel, seu site pode verificar automaticamente se cada solicitação POST contém um token CSRF. Esse é um recurso de segurança importante que protege contra tentativas de falsificação de solicitações entre sites, mas pode impedir que seu site processe eventos legítimos de webhooks. Para resolver isso, você pode isentar a rota dos webhooks da proteção contra CSRF.
<?php
use Illuminate\Foundation\Application;
use Illuminate\Foundation\Configuration\Middleware;
# No Laravel,
# você pode adicionar a rota de webhook como exceção
# middleware VerifyCsrfToken no arquivo `bootstrap/app.php`
return Application::configure(basePath: dirname(__DIR__))
->withRouting(
web: __DIR__.'/../routes/web.php',
commands: __DIR__.'/../routes/console.php',
channels: __DIR__.'/../routes/channels.php',
health: '/up',
)
->withMiddleware(function (Middleware $middleware) {
$middleware->validateCsrfTokens(except: [
'webhooks/*' // <-- remove a rota da validação
]);
})->create();
from django.views.decorators.csrf import csrf_exempt
from django.http import JsonResponse
# No Django, você pode isentar uma view específica
# da verificação CSRF sando o decorator @csrf_exempt
@csrf_exempt
@require_POST
def webhook_endpoint(request):
# Processar o webhook
# No Rails, você pode isentar uma ação específica do protect_from_forgery
class WebhooksController < ApplicationController
protect_from_forgery except: :webhook
def webhook
# Process webhook data in `params`
end
end
Verificar se eventos são enviados pelo Autentique
Para garantir que os eventos recebidos realmente provêm do Autentique, é fundamental validar as assinaturas HMAC presentes nos cabeçalhos dos webhooks. A seguir, alguns exemplos de como fazer isso:
public function verifySignature(array $headers, string $payload, string $secret): bool
{
if (!isset($headers['x-autentique-signature'])) {
return false;
}
$signature = $headers['x-autentique-signature'];
$calculatedSignature = hash_hmac('sha256', $payload, $secret);
return hash_equals($calculatedSignature, $signature);
}
A API do Autentique utiliza eventos específicos disparados quando certas ações ocorrem.
Todos os webhooks enviados estão relacionados a um evento de um determinado recurso, definido pelo campo “type”. O conteúdo dos webhooks varia apenas entre os diferentes tipos de eventos.
Esses eventos são classificados em três grandes categorias:
Document: Eventos relacionados à criação, modificação e conclusão de
documentos.
Signature: Eventos relacionados ao fluxo de assinaturas nos documentos.
Member: Eventos relacionados aos membros pertencentes à organização.
Eventos de Document
Evento
Descrição
document.created
Disparado quando um novo documento é criado na aplicação.
document.updated
Disparado quando um documento existente é atualizado ou editado (exemplo: alteração nas configurações adicionais).
document.deleted
Disparado quando um documento é removido definitivamente da aplicação.
document.finished
Disparado quando todas as assinaturas ou etapas associadas ao documento são concluídas com sucesso, encerrando formalmente o ciclo de vida do documento.
Eventos de Signature
Evento
Descrição
signature.created
Disparado quando uma nova solicitação de assinatura é criada para um signatário em um documento.
signature.updated
Disparado quando ocorre uma alteração ou atualização na solicitação de assinatura, como mudança nas condições ou na situação da assinatura Exemplo: posicionar uma assinatura invisível.
signature.deleted
Disparado quando uma assinatura pendente é removida do documento.
signature.viewed
Disparado quando o signatário visualiza o documento pela primeira vez, indicando que ele acessou o conteúdo, mas ainda não realizou nenhuma ação definitiva.
signature.accepted
Disparado quando o signatário conclui o processo de assinatura com sucesso.
signature.rejected
Disparado quando o signatário recusa explicitamente a assinatura.
signature.biometric_approved
Disparado quando a verificação biométrica do signatário é validada com sucesso pelo criador do documento ou uma validação automática.
signature.biometric_unapproved
Disparado quando a assinatura de um documento tem verificações a se fazer ainda, como na validação manual que fica em um estado de aprovação que tem que ser feita pelo responsável pelo documento.
signature.biometric_rejected
Disparado quando a biometria é rejeitada pelo autor do documento.
Eventos de Member
member.created
Disparado quando um novo membro é adicionado à organização.
member.deleted
Disparado quando um membro é removido da organização.