Webhooks bei Legalesign
Was sind Webhooks
Webhooks sind Ihre URLs, an die Legalesign Echtzeit-Status-Updates sendet. Sie können eigene URLs erstellen oder Automatisierungssysteme (wie MS Power Automate) können diese generieren, um einen Workflow zu starten.
Zum Beispiel erstellen wir in dieser Demo eine URL mit Microsoft Power Automate. Wir fügen diese URL als Webhook in Legalesign hinzu, wenn Dokumente unterschrieben werden. Der Power Automate-Flow wird ausgelöst, wenn ein Dokument unterschrieben wird, und speichert automatisch die neu unterschriebenen PDFs auf Sharepoint. Mehr über MS Power Automate erfahren.
Wichtiger Hinweis – Sie müssen über Admin-Rechte im Team verfügen, um Team-Events an Ihren Webhook senden zu lassen.
Warum Sie Webhooks brauchen
Webhooks ermöglichen es Ihnen, ein ereignisgesteuertes System zu pflegen. Webhooks informieren Sie über alle Ereignisse innerhalb Ihrer Gruppen. Sie können sie verwenden, um ein eigenes Live-Dashboard zu erstellen und/oder um mit Ihrer eigenen Datenbank zu synchronisieren.
Wie oben erwähnt, ermöglichen generierte Webhooks aus Automatisierungssystemen wie Power Automate das Auslösen von Speicherverfahren, E-Mails, Aufzeichnungen usw., was zusammen mit der API Ihnen alles bietet, was Sie für die Prozessautomatisierung benötigen.
Ein Echtzeit-Websocket-Abonnement-Feed ist ebenfalls verfügbar. Dies kann besser geeignet sein, wenn Sie clientseitige Live-Updates wünschen, ohne einen Webhook-Endpunkt offenzulegen. Der Websocket bietet eine breitere Palette von Ereignissen als Webhooks.
Ja, Webhooks fühlen sich vielleicht umständlich an, sind aber sehr lohnenswert und großartig für Ihre Integration. Lesen Sie weiter.
Arten von Webhooks
- Echtzeit-Ereignisse
- Alle Ereignisse alle 6 Minuten (Legacy)
- Bei [Ereignis] (Legacy)
Für Legacy-Webhooks siehe: Legacy-Webhooks
Webhooks werden am häufigsten verwendet, um ein unterschriebenes PDF herunterzuladen. Wenn Sie den Webhook erstellen, wenden Sie den Ereignisfilter 'Final PDF created' an. In Ihrem Code ist der eingehende request.body JSON, parsen Sie ihn und extrahieren documentId = ['data']['uuid']. Jetzt führen Sie die API-Anfrage zum Herunterladen des PDFs aus - GET https://eu-api.legalesign.com/api/v1/pdf/${documentId}/.
So fügen Sie einen Webhook hinzu oder entfernen ihn
Webhook über die Web-App hinzufügen oder entfernen
Gehen Sie zum API-Dashboard und klicken Sie auf den Bereich Webhooks. Das Formular hat einfache Steuerelemente zum Hinzufügen oder Entfernen von Webhooks. Sie können optional Webhook-Ereignisse auf bestimmte Teams und/oder Ereignisse beschränken.

Ihre Webhooks empfangen Ereignisse von allen Konten, bei denen Sie Admin sind, sowohl Dev als auch Prod. Verwenden Sie den Gruppenfilter, um verschiedene Webhooks für Ihre verschiedenen Gruppen zu erstellen.
Webhook über die REST API hinzufügen oder entfernen
Siehe den Abschnitt 'webhook' am unteren Rand der linken Navigation innerhalb der API-Dokumentation: REST API Webhooks
Webhook über GraphQL hinzufügen oder entfernen
Neu! Wenn Sie SRP-Authentifizierung und die GraphQL-Oberfläche verwenden, haben Sie volle CRUD-Rechte. Schauen Sie sich den Legalesign GraphiQL Explorer an. Webhooks können als Attribut des Benutzertyps (User) gelistet werden, und es gibt Mutationen zum createWebhook, updateWebhook und deleteWebhook.
Was ist in einem Webhook?
Der schnellste Weg, Ihre Daten zu inspizieren, ist, einen Webhook hinzuzufügen, einige Testdokumente in der Web-App zu senden/unterzeichnen/ablehnen und dann das Webhook-Protokoll im Legalesign API Dashboard anzusehen.
Wenn Sie eine temporäre Webhook-URL zum Testen benötigen, sehen Sie sich ngrok an.
Kurzanleitung zu ngrok: Sobald Sie ngrok heruntergeladen haben, starten Sie es im Terminal mit ./ngrok http 80 und es gibt Ihnen eine https-Adresse. Geben Sie diese als Ihren Webhook ein. Öffnen Sie dann http://127.0.0.1:4040. Das war's, Sie sehen jetzt alle Webhooks und deren Daten. Beginnen Sie, Testdokumente zu senden und zu unterzeichnen. Hinweis: Ngrok kann einen 5XX-Fehler zurückgeben, daher können mehrere Versuche und Fehlermeldungen erwartet werden, da das System den 5XX-Status als fehlgeschlagenen Versuch betrachtet.
Stellen Sie sicher, dass Ihr empfangender Webhook-Code eine 2XX-Erfolgsantwort zurückgibt. Wenn Sie mehrere mögliche Ausnahmen in Ihrem Code haben, geben Sie verschiedene 5XX-Statuscodes zurück. Die Webhook-Protokolle im API-Dashboard zeigen dann an, welche Ausnahme ausgelöst wurde.
Das Format des Echtzeit-Webhooks
Das Datenformat kann eines von zwei Schemata sein, entweder ein 'document'-Schema oder ein 'recipient'-Schema. Prüfen Sie das Attribut 'object', um zu bestimmen, mit welchem Schema Sie es zu tun haben.
Beide Schemata haben auch ein 'event'-Attribut. Sie können beim Erstellen des Webhooks nach Objekt und optional Ereignis filtern.
Eine Tabelle aller möglichen Objekte und Ereignisse ist unten. Dieses Bild zeigt ein Document-Objekt (für ein 'created'-Ereignis). Die vollständigen JSON-Schemata finden Sie am Ende dieses Artikels.

Anfragen kommen als POST-Anfrage mit JSON. Bitte beachten Sie, dass der Inhalt von 'data' im Laufe der Zeit erweitert werden kann.
Verwenden Sie 'tag'-Attribute. Sie können bis zu 3 Tags setzen, wenn Sie ein Dokument erstellen. Durch die Verwendung von Tags müssen Sie möglicherweise keine Legalesign-IDs speichern. Sie können auch ein Tag verwenden, um ein Geheimnis zu speichern, um die eingehende Anfrage zu verifizieren (Danke an Themis für diesen Vorschlag).
Tabelle der möglichen Kombinationen für 'object' und 'event':
| Objekt | Ereignis |
|---|---|
| document | created |
| document | rejected |
| document | finalPdfCreated |
| recipient | completed |
| recipient | rejected |
| recipient | emailOpened |
| recipient | visiting |
| recipient | bounced |
| recipient | autoReminderEmail |
| recipient | emailNotification |
Die meisten Ereignisse treten nur einmal auf. Die Ausnahmen sind visiting, bounced, emailNotification und autoReminderEmail, die mehrfach auftreten können.
Vergessen Sie nicht, den CSRF-Schutz für Ihre Ansicht, die diese POST-Anfragen empfängt, zu deaktivieren.
Hier ist ein Beispiel für ein 'recipient'-Objekt mit dem Ereignis 'bounced':

Beachten Sie emailBounce und emailBounceMessage in 'data'. 'emailBounceMessage' gibt die Art des Bounce wie folgt an:
- Hard Bounce: "Message hard bounced"
- Soft Bounce: "Email soft bounced (either out of office or a timeout)"
- Verzögert: "Message delayed (check email domain exists)"
Dem Schema können jederzeit neue Attribute hinzugefügt werden.
Webhooks im API-Dashboard debuggen
Alle Webhooks werden protokolliert, und Sie können deren Inhalt und den HTTP-Statuscode in Ihrem API-Dashboard prüfen. Weitere Informationen finden Sie im Dashboard-Tutorial
Manueller Auslöser für Webhook
Lösen Sie manuell einen Webhook mit dem Formular unten auf der Webhooks-Seite in Ihrem Developer Portal aus.
Verwenden Sie unbedingt eine echte Empfänger- oder Dokumenten-ID, je nach Ereignis.
Statuscodes
Klicken Sie auf diese Links, um die Referenztabellen für Dokumentenstatus und Empfängerstati zu sehen.
Webhook verifizieren
Der Webhook signiert das Datenpaket mit einem privaten Schlüssel. Sie können es mit dem öffentlichen Schlüssel verifizieren - öffentlichen Schlüssel herunterladen.
- Der Ort der Signaturzeichenfolge befindet sich im Header X-Signed-SHA256.
- Die signierten Daten sind der gesamte request.body (als String).
Die 'Signature' ist base64-codiert. Hier ist ein Beispiel für Verifizierungscode in node.js:
const crypto = require('crypto');
const fs = require('fs');
const cert = fs.readFileSync('/location/of/downloadedCert.crt', 'utf8');
const c = new crypto.X509Certificate(cert);
const k = c.publicKey
let verifier = crypto.createVerify('SHA256');
let rawdata = 'sentdata' //JSON stringify data in request.body
let sha256signature = 'xxx' //value of 'X-Signed-Sha256' request header.
verifier.update(rawdata);
return verifier.verify(k, sha256signature, 'base64');
Optional ist auch eine HMAC-basierte Verifizierung verfügbar. Für HMAC wird Ihnen ein geheimer Schlüssel für Ihre Webhooks mitgeteilt. Der signierte Wert wird im Header X-HMAC-SHA256 ankommen.
Es gibt viele Online-Ressourcen, die zeigen, wie man einen HMAC-Wert verifiziert. Beispielhafte Verifizierung in Python wäre:
import hmac, hashlib
sentdata = 'sentdata' # JSON stringify data in request.body
hmacvalue = 'xxx' # value of 'X-HMAC-Sha256' in request header.
v = hmac.new('your secret value'.encode(), 'sentdata'.encode(), hashlib.sha256)
isValid = v.hexdigest() == hmacvalue
Oder Beispielcode in Salesforce Apex, um einen HMAC zu verifizieren, ist:
String message = 'JSONstring'; //sent in request.body
String privatekey = 'privateKey'; //shared value you have been given
String hmacvalue = 'xxx'; //value of 'X-HMAC-Sha256' in request header.
Boolean verified = Crypto.verifyHMac('HmacSHA256', Blob.valueOf(message), Blob.valueOf(privatekey), EncodingUtil.convertFromHex(hmacvalue));
Weitere Webhooks?
Wenn Sie mehr Webhooks für verschiedene Ereignisse oder mehr Daten darin benötigen, kontaktieren Sie uns und bringen Sie Ihren Wunsch in die Entwicklungspipeline ein.
Schema-Referenz
Es gibt zwei mögliche Schemata, eines für Objekt 'document' und eines für Objekt 'recipient'. Beide Schemata haben auf oberster Ebene die Schlüssel 'object' und 'event'. Prüfen Sie das Attribut 'object', um das Schema zu bestimmen, mit dem Sie es zu tun haben. Oder verwenden Sie einen Webhook-Filter, um nur Dokument- oder nur Empfängerobjekte zurückzugeben.
Bitte beachten Sie, dass dem Schema jederzeit neue Attribute hinzugefügt werden können (aber keine entfernt).
1. JSON Schema für das Objekt 'document'
{
"$schema": "http://json-schema.org/draft-04/schema#",
"type": "object",
"properties": {
"version": {
"type": "string",
"default": "1.0.0"
},
"object": {
"type": "string",
"default": "document"
},
"created": {
"type": "integer",
"description": "unix timestamp"
},
"id": {
"type": "string",
"format": "uuid"
},
"event": {
"type": "string",
"pattern": "^(created|rejected|finalPdfCreated)$"
},
"data": {
"type": "object",
"properties": {
"tag1": {
"type": "string"
},
"recipients": {
"type": "array",
"items": [
{
"type": "object",
"properties": {
"uuid": {
"type": "string",
"format": "uuid"
},
"email": {
"type": "string",
"format": "email"
},
"order": {
"type": "integer"
},
"status": {
"type": "integer"
"pattern": "^(4|5|10|15|20|30|35|39|40|50|60)$"
},
"lastname": {
"type": "string"
},
"roleText": {
"type": "string",
"pattern": "^(signer|approver|witness)$"
},
"firstname": {
"type": "string"
},
"statusText": {
"type": "string",
"pattern": "^(unsent|scheduled|sent|email opened|visited|fields complete|fields complete excluding signature|witnessing required|completed|download final document|rejected|withdrawn)$"
},
"resourceUri": {
"type": "string",
"format": "uri-reference"
},
"rejectReason": {
"type": "string"
}
},
"required": [
"uuid",
"email",
"order",
"status",
"lastname",
"roleText",
"firstname",
"statusText",
"resourceUri",
"rejectReason"
]
}
]
},
"groupResourceUri": {
"type": "string",
"format": "uri-reference"
},
"statusText": {
"type": "string",
"pattern": "^(available|fields complete|completed|removed|rejected|unknown)$"
},
"name": {
"type": "string"
},
"tag": {
"type": "string"
},
"resourceUri": {
"type": "string",
"format": "uri-reference"
},
"uuid": {
"type": "string",
"format": "uuid"
},
"tag2": {
"type": "string"
},
"group": {
"type": "string"
},
"status": {
"type": "integer",
"pattern": "^(10|20|30|40|50)$"
}
},
"required": [
"tag1",
"recipients",
"groupResourceUri",
"statusText",
"name",
"tag",
"resourceUri",
"uuid",
"tag2",
"group",
"status"
]
}
},
"required": [
"version",
"object",
"data",
"created",
"id",
"event"
]
}
2. JSON Schema für das Objekt 'recipient'
{
"$schema": "http://json-schema.org/draft-04/schema#",
"type": "object",
"properties": {
"version": {
"type": "string",
"default": "1.0.0"
},
"object": {
"type": "string",
"default": "recipient"
},
"created": {
"type": "integer",
"format": "date-time"
},
"id": {
"type": "string",
"format": "uuid"
},
"event": {
"type": "string",
"pattern": "^(emailOpened|bounced|visiting|rejected|completed|autoReminderEmail|emailNotification)$"
},
"data": {
"type": "object",
"properties": {
"tag": {
"type": "string"
},
"tag1": {
"type": "string"
},
"tag2": {
"type": "string"
},
"uuid": {
"type": "string",
"format": "uuid"
},
"email": {
"type": "string",
"format": "email"
},
"group": {
"type": "string",
"format": "uuid"
},
"order": {
"type": "integer"
},
"status": {
"type": "integer",
"pattern": "^(4|5|10|15|20|30|35|39|40|50|60|70)$"
},
"document": {
"type": "string"
},
"documentName": {
"type": "string"
},
"lastname": {
"type": "string"
},
"roleText": {
"type": "string"
},
"firstname": {
"type": "string"
},
"statusText": {
"type": "string",
"pattern": "^(unsent|scheduled|sent|email opened|visited|fields complete|fields complete excluding signature|witnessing required|completed|download final document|rejected|withdrawn)$"
},
"emailBounce": {
"type": "integer"
},
"resourceUri": {
"type": "string",
"format": "uri-reference"
},
"rejectReason": {
"type": "string"
},
"groupResourceUri": {
"type": "string",
"format": "uri-reference"
},
"emailBounceMessage": {
"type": "string"
},
"documentResourceUri": {
"type": "string",
"format": "uri-reference"
}
},
"required": [
"tag",
"tag1",
"tag2",
"uuid",
"email",
"group",
"order",
"status",
"document",
"documentName",
"lastname",
"roleText",
"firstname",
"statusText",
"emailBounce",
"resourceUri",
"rejectReason",
"groupResourceUri",
"emailBounceMessage",
"documentResourceUri"
]
}
},
"required": [
"version",
"object",
"data",
"created",
"id",
"event"
]
}