Get Started

This document explains how to set up a Webhook that will notify you whenever your app's data publish any changes.
Setting up the Webhook requires you to: 1. Create an endpoint on a secure server that can process HTTPS requests. 2. Decrypt the data received from webhook.
These steps are explained in detail below.
      

Create an endpoint

Your endpoint must be able to process POST HTTPS request. Since the request use HTTPs, your server must have a valid TLS or SSL certificate correctly configured and installed. Self-signed certificates are not supported.
Whenever there's a change in the data, we will send your endpoint a POST request with a JSON payload describing the change.
For example, when a user book an appointment, we would send you a POST request that would look something like this:
POST / HTTPS/1.1 Host: your-clever-domain-name.com/webhooks Content-Type: application/json X-Hub-Signature-256: sha256={super-long-SHA256-signature} Content-Length: 311 { "data": "encrypted-data" }
      

Payload Contents

Payloads will contain an encrypted object describing the change. We format all payloads with JSON, so after decrypt the data you can parse the payload using common JSON parsing methods or packages.
Appointment created payload example { _id: { type: Schema.Types.ObjectId }, Client: { type: Schema.Types.ObjectId }, Title: String, Status: String, Type: String, Note: String, StartDateTime: { type: Date }, EndDateTime: { type: Date }, CreatedDate: { type: Date }, Service: { type: Schema.Types.ObjectId }, Deleted: { type: Boolean }, Location: { type: Schema.Types.ObjectId }, }
      

Decrypt the data

After registed for a webhook service, we will provide user a secret key which use to decrypt the data payload. The example codes below explain how to decrypt the data with the key provided
      

NodeJS

import { AES, enc, mode, pad } from "crypto-js"; const decrypt = (encryptedString: string, secretKey: string) => { try { if (!encryptedString || !secretKey) { return null; } const key = enc.Utf8.parse(secretKey); let decryptedBytes = AES.decrypt(encryptedString, key, { mode: mode.ECB, padding: pad.Pkcs7 }); let decryptedText = decryptedBytes.toString(enc.Utf8); return JSON.parse(decryptedText); } catch (e) { console.log(e); return null; } };
      

Java

import java.util.Base64; import javax.crypto.Cipher; import javax.crypto.spec.SecretKeySpec; public static String decrypt(final String cipherString, final String secretKey) { try { if (cipherString == null || cipherString.isEmpty()) { return null; } if (secretKey == null || secretKey.isEmpty()) { return null; } // Get Key byte[] key = secretKey.getBytes("UTF-8"); SecretKeySpec secretKeySpec = new SecretKeySpec(key, "AES"); Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5PADDING"); cipher.init(Cipher.DECRYPT_MODE, secretKeySpec); return new String(cipher.doFinal(Base64.getDecoder() .decode(cipherString))); } catch (Exception e) { System.out.println("Error while decrypting: " + e.toString()); } return null; }
      

.NET

using System.Security.Cryptography; using System.Text; public static string? Decrypt(string cipherString, string secretKey) { if (string.IsNullOrEmpty(secretKey)) { return null; } if (string.IsNullOrEmpty(cipherString)) { return null; } byte[] key = Encoding.UTF8.GetBytes(secretKey); byte[] cipherBytes = Convert.FromBase64String(cipherString); byte[] decryptedBytes = null; // Set up the encryption objects using (Aes aes = Aes.Create()) { aes.Key = key; aes.Mode = CipherMode.ECB; aes.Padding = PaddingMode.None; // Decrypt the input ciphertext using the AES algorithm using (ICryptoTransform decryptor = aes.CreateDecryptor()) { decryptedBytes = decryptor.TransformFinalBlock(cipherBytes, 0, cipherBytes.Length); } } string decryptedText = Encoding.UTF8.GetString(decryptedBytes); return decryptedText; }

Webhook events

        

Patient create payload data:

{ type: "patient.create", data: { _id: "", Client: "", FirstName: "Open", LastName: "API", MiddleName: "", CreatedDate: "2022-12-05T02:50:12.359Z", Email: "openapi@pteverywhere.com", Phone: "", } }
        

Patient update payload data:

{ type: "patient.update", data: { _id: "", Client: "", FirstName: "Open", LastName: "API", MiddleName: "", CreatedDate: "2022-12-05T02:50:12.359Z", Email: "openapi@pteverywhere.com", Phone: "", } }
        

Appointment create payload data:

{ type: "appointment.created", data: { _id: "", Client: "", Title: undefined, Status: "New Appointment", Type: "Standard", Note: undefined, StartDateTime: "2024-02-24T03:45:00.000Z", EndDateTime: "2024-02-24T04:45:00.000Z", CreatedDate: "2024-02-23T04:52:21.657Z", Service: "", Deleted: false, Location: "", Attendee: "", Booker: "", } }
        

Appointment update payload data:

{ type: "appointment.update", data: { _id: "", Client: "", Title: undefined, Status: "New Appointment", Type: "Standard", Note: undefined, StartDateTime: "2024-02-24T03:45:00.000Z", EndDateTime: "2024-02-24T04:45:00.000Z", CreatedDate: "2024-02-23T04:52:21.657Z", Service: "", Deleted: false, Location: "", Attendee: "", Booker: "", } }
        

Patient Invoice create payload data:

{ type: "patient_invoice.created", data: { _id: "637c75ecc8d3870a767523ba", Client: "637c75ecc8d3870a767523bb", Note: "", PaymentStatus: "unpaid", IsDeleted: "N", Patient: "", Therapists: [ ], Collect: undefined, Balance: 200, Service: "637c75ecc8d3870a767523b7", Location: "637c75ecc8d3870a767523c2", CreatedAt: "2024-02-23T07:11:14.248Z", } }
        

Patient Invoice update payload data:

{ type: "patient_invoice.updated", data: { _id: "637c75ecc8d3870a767523ba", Client: "637c75ecc8d3870a767523bb", Note: "", PaymentStatus: "unpaid", IsDeleted: "N", Patient: "", Therapists: [ ], Collect: undefined, Balance: 200, Service: "637c75ecc8d3870a767523b7", Location: "637c75ecc8d3870a767523c2", CreatedAt: "2024-02-23T07:11:14.248Z", } }