Skip to main content

Webhooks

After a document has been signed it can be delivered back to your system.

Definition of terms​

The following keys are needed to work with webhooks.

  • companyKey the baseKey used to identify a company.
  • flowKey There can be many flows each with its own delivery methods registered.
  • webhookSignatureKey The key used to validate that Taktikal sends the webhook data.

Webhook​

The data Taktikal sends via webhook are wrapped in a WebhookEventPayload object that has an Id, EventData, and EventSignature See example data below.

  • EventSignature is used to validate that Taktikal is the one who sends the data. TimeStamp and GUID hashed with the webhookSignatureKey to create a Signature. If the Signature that is calculated is not a match to the value in the event, it was not sent by Taktikal. For convenience we also supply the SignedData property which has already concatenated TimeStamp and Guid into a single value
  • EventData contains all signee that signed the document and all their personal information provided in this process. The signed document is stored as a base64 string in the field SignedDocument

Taktikal will send a POST request to the registered URL when an event occurs and expects an HTTP Status code 200 Response. For all other response codes, Taktikal Will retry two more times. Unless an HTTP Status code 406 (not accepted) is received that marks that we will not try again.

Webhook event types​

Taktikal sents out webhook events for Created, SignedDocument, AllSigned, Canceled or Expired,

Event nameEvent descriptioncontains documentinteger value
CreatedThis is an event that is triggerd when a new signing process is created.πŸ”΄11
SignedDocumentThis is an event that is run for each signing except the last one.πŸ”΄1
AllSignedThis is an event triggered on the last signature.βœ…2
CanceledThis is an event that is run when a signing process is canceled.πŸ”΄5
Expiredeach signing process needs to be signed within 30 days. If it expires this event will be triggeredβœ…6

Register a webhook​

Webhooks can be managed via the API. All routes can be viewed in Swagger here.

AttachmentReferences​

A signing process can have AttachmentReferences. Each AttachmentReference has AttachmentType. That can be any of the values in the table

AttachmentTypeValueDescription
Unspecified0this is the most common value. It's used for all regular attachments.
EvidencePage10for standart signatures and advanced signatures, an EvidencePage is generated and seald by Taktikal
PepPdf20a PDF file contaning PEP and sactions results for a signee in an AML process that is seald by Taktikal
PepJson30a JSON file contaning PEP and sactions results for a signee in an AML process
Verification40for advanced signatures all attachments related to identify the signee have this attachment type.
XmlForSealing50an xml attachment that is selead and added as an embedded attachment to the PDF when it's signed
VerificationMedia60images that are collected during the ID verification process
CompanyInfo70Company report used in AML processes. compare the answeres to the official company data from the goverment

When you receive a webhook event, we recommend that you offload it to your own message queue service for further processing and respond to us with Http status code 200.

This minimizes the risk of data loss as any error during processing of message can be seen and replayed within your own infrastructure.

Code examples​

Example webhook event​

{
"Id": "3e9922f5fd7f4a9baa75a3fa90cb9caf",
"EventData": {
"ProcessKey": "sp231f52f87d6f4caaa2e29ecac92d055b",
"CompanyKey": "fae93sfa4sh4",
"Signees": [
{
"Name": "Test User",
"Ssn": "1234567890",
"PhoneNumber": "1234567",
"Email": "testUser@taktikal.com",
"Address": "Address 5",
"City": "ReykjavΓ­k",
"Key": "si7abef56540bd49f9a9b8a33969a9cf8c",
"Signed": true,
"SignedAt": "yyyy-MM-ddTHH:mm:ss.fffffZ",
"ProcessKey": "sp231f52f87d6f4caaa2e29ecac92d055b",
"CommunicationDeliveryType": "Email"
}
],
"FlowKey": "722989cac3fx",
"FlowName": "Non-disclosure agreement",
"SignedDocument": "JVBERi0xLjQ...",
"SignedDocumentDownloadUrl": "https://app.taktikal.is/sp231f52f87d6f4caaa2e29ecac92d055b/si7abef56540bd49f9a9b8a33969a9cf8c.pdf"
"AttachmentReferences": [
{
"Id": "at3357",
"FileName": "pep-Test User-63f-1.pdf",
"ContentLength": 90570,
"ContentType": "application/pdf",
"Url": "https://app.taktikal.is/attachment/sp231f52f87d6f4caaa2e29ecac92d055b/at3357/pep-Test User-64f-1.pdf",
"Description": "PEP for Test User",
"ProcessKey": "sp231f52f87d6f4caaa2e29ecac92d055b",
"AttachmentType": 20,
"SigneeKey": "si7abef56540bd49f9a9b8a33969a9cf8c"
}
],
"EventType": 2, // "AllSigned",
"Meta": {
"pdfUrl": "https://fill.dropandsign.is/api/flow/665a62b4a97a/pdf",
"pdfFieldData": "{\"Nafn\":\"Test User\",\"userInfo\":\"info\",\"ssn\":\"123456-7890\"}"
}
},
"EventSignature": {
"TimeStamp": 637030223561542290,
"Guid": "2065b6c0-934f-4d18-81d3-46c29b913311",
"Signature": "5qN29xaZHKZ65PLMB6ajRgpcxUU9dFRAXhkw36C2d38="
"SignedData": "6370302235615422902065b6c0-934f-4d18-81d3-46c29b913311"
}
}
using System;
using System.Collections.Generic;
using System.Security.Cryptography;
using System.Text;

namespace Webhook
{
public class WebhookEventPayload
{
public Guid Id { get; set; }
public SignedDocumentEventData EventData { get; set; }
public EventSignature EventSignature { get; set; }
}

/// <summary>
/// The signature section that will be in all webhook payloads. Used to validate the payload
/// </summary>
public class EventSignature
{
public long TimeStamp { get; set; }
public string Guid { get; set; }
public string Signature { get; set; }
public string SignedData { get; set; }
}

public class SignedDocumentEventData
{
public string ProcessKey { get; set; }
public List<Signee> Signees { get; set; }
public string SignedDocument { get; set; }
public List<AttachmentReference> AttachmentReferences { get; set; }
public EventType EventType { get; set; }
public Dictionary<string, string> Meta { get; set; }
}

public class AttachmentReference
{
public string Id { get; set; }
public string FileName { get; set; }
public long ContentLength { get; set; }
public string ContentType { get; set; }
public string Url { get; set; }
public string Description { get; set; }
public string ProcessKey { get; set; }

public AttachmentType AttachmentType { get; set; } = AttachmentType.Unspecified;
public string SigneeKey { get; set; }
}

public enum AttachmentType
{
Unspecified = 0,
EvidencePage = 10,
PepPdf = 20,
PepJson = 30,
Verification = 40,
XmlForSealing = 50,
VerificationMedia = 60, // additional data collected during verification
CompanyInfo = 70
}

public enum EventType
{
SignedDocument = 1,
AllSigned = 2,
Canceled = 5,
Expired = 6,
/// <summary>
/// This is an event that is triggered when all jobs have finished running for a process
/// </summary>
Completed = 10,

/// <summary>
/// This is an event that is triggered when a process is created to trigger all signingRequests
/// </summary>
Created = 11
}

public class Signee
{
public string Name { get; set; }
public string Ssn { get; set; }
public string PhoneNumber { get; set; }
public string Email { get; set; }
public string Address { get; set; }
public string PostalCode { get; set; }
public string City { get; set; }
public string Key { get; set; }
public bool Signed { get; set; }
public string ProcessKey { get; set; }
public string CommunicationDeliveryType { get; set; }
}

public static class WebhookHelpers
{
/// <summary>
/// Verifies that signature matches your webhook signature key
/// </summary>
public static bool ValidateSignature(this WebhookEventPayload webhookEvent, string yourWebhookSignatureKey)
{
var encoding = new UTF8Encoding();
byte[] keyByte = encoding.GetBytes(yourWebhookSignatureKey);
byte[] messageBytes = encoding.GetBytes(webhookEvent.EventSignature.SignedData);
using (var hmacsha256 = new HMACSHA256(keyByte))
{
byte[] hashmessage = hmacsha256.ComputeHash(messageBytes);
return Convert.ToBase64String(hashmessage) == webhookEvent.EventSignature.Signature;
}
}
}
}