Skip to main content

Observation Webhook

The observation webhook allows you to subscribe to assessment-related events. You can select which specific events to subscribe to, and your system will receive an HTTP request each time one of the selected events occurs.

Events
assessment.created
assessment.completed
assessment.destroyed

Teachstone will POST to https://your-endpoint.com/path

{
"item_type": "assessment",
"item_id": 6252,
"time": "2023-03-07T17:17:37.933Z",
"time_unix": 1678209457,
"event": "assessment.created"
}

Webhook Security

info

Implementing webhook signature verification will ensure the requests are genuinely coming from Teachstone and haven't been tampered with.

How Webhook Signing Works

  1. Provide a Secret Key: Share a secret key with Teachstone when configuring your webhook endpoint
  2. Signature Generation: Teachstone signs each webhook payload using HMAC-SHA512 with your secret key
  3. Signature Header: The signature is sent in the x-teachstone-signature header as a Base64 encoded string
  4. Verification Process:
    • Generate your own HMAC-SHA512 digest using the payload + your secret key
    • Encode your digest to Base64
    • Compare your Base64 string with the received signature
    • Do NOT decode the received signature - always encode yours and compare strings

Example Webhook Request Headers

POST /your-webhook-endpoint HTTP/1.1
Host: your-domain.com
Content-Type: application/json
x-teachstone-signature: Kv6/TyL5BCYJKcF/HRoI7qUHZzrCq9J8mBJCF2Lmqik=
Content-Length: 123

Implementation Example (Node.js)

const crypto = require('crypto');

function verifyWebhookSignature(payload, signature, secretKey) {
// Generate your own HMAC-SHA512 digest
const expectedSignature = crypto
.createHmac('sha512', secretKey)
.update(payload, 'utf8')
.digest('base64');

// Compare Base64 strings
return signature === expectedSignature;
}

// Express.js endpoint
app.post('/webhook', (req, res) => {
const signature = req.headers['x-teachstone-signature'];
const payload = JSON.stringify(req.body);

if (!verifyWebhookSignature(payload, signature, process.env.TEACHSTONE_SECRET)) {
return res.status(401).json({ error: 'Invalid signature' });
}

// Process webhook data
const { event, item_id } = req.body;
console.log(`Received ${event} for assessment ${item_id}`);

res.json({ success: true });
});