NodeJS examples in this document are largely pulled from one of our test scripts, which may be a useful reference for more examples or sophisticated usage
Webhooks only need to be configured once, but can be updated later to (un)subscribe to different models or actions. Use the Create Webhook endpoint initially and then the Update Webhook endpoint later as needed.
<aside> 💡 You will provide a URL as part of the subscription configuration process that will receive all POST Webhooks from Tellescope. You must also provide a secret (randomly generated) that can be used to verify that requests come from Tellescope.
</aside>
const sdk = new Session({ apiKey: "API_KEY_GOES_HERE" })
await sdk.api.webhooks.configure({ url: "/YOUR_WEBHOOK_URL", secret: "YOUR_SECRET" })
<aside> 💡 Calling the configure endpoint again will replace your existing configuration with the newly provided information
</aside>
You specify each model (e.g. endusers, tickets) and each type of action (create, read, update) that you want to be notified about.
// NodeJS - Add subscription for created and updated endusers
const sdk = new Session({ apiKey: "API_KEY_GOES_HERE" })
await sdk.api.webhooks.update({ subscriptionUpdates: { endusers: { create: true, update: true }} }),
import express from "express"
import bodyParser from 'body-parser'
import crypto from "crypto"
import {
WebhookRecord,
WebhookCall,
} from "@tellescope/types-models"
const app = express()
app.use(bodyParser.urlencoded({ extended: true, limit: '25mb' }))
app.use(bodyParser.json({ limit: "25mb" }))
const sha256 = (s: string) => crypto.createHash('sha256').update(s).digest('hex')
const verify_integrity = ({ type, message, event, records, timestamp, integrity } : {
type: string,
message: string,
event?: CalendarEvent,
records: WebhookRecord[],
timestamp: string,
integrity: string,
}) => (
sha256(
type === "automation"
? message + timestamp + TEST_SECRET
: type === 'calendar_event_reminder'
? event?.id + timestamp + TEST_SECRET
: records.map(r => r.id).join('') + timestamp + TEST_SECRET
) === integrity
)
const handledEvents: WebhookCall[] = []
app.post("/YOUR_WEBHOOK_URL", (req, res) => {
const body = req.body as WebhookCall
// console.log('got hook', body.records, body.timestamp, body.integrity)
if (!verify_integrity(body)) {
console.error("Integrity check failed for request", JSON.stringify(body, null, 2))
process.exit(1)
}
handledEvents.push(req.body)
res.status(204).end()
})
type WebhookRecord = {
id: string,
[index: string]: any,
}
type WebhookUpdates = {
recordBeforeUpdate: WebhookRecord,
update: Partial<WebhookRecord>,
}[]
interface WebhookCall {
model: string,
description?: string,
message?: string,
type: "create" | "update" | "delete",
event?: CalendarEvent & { id: string },
records: WebhookRecord[],
updates?: WebhookUpdates,
relatedRecords: { [index: string]: WebhookRecord },
timestamp: string,
integrity: string,
}
{
model: "endusers",
type: "create"
records: [ // includes multiple endusers on bulk create
{ id: string, /* other enduser fields here */ }
],
timestamp: string,
integrity: string,
}