Agent skill
Teachfloor Webhooks Skill
Receive and verify Teachfloor webhooks. Use when setting up a Teachfloor webhook endpoint, verifying the teachfloor-signature header (HMAC-SHA256 of the raw body), debugging signature failures, or handling events like course.join, course.completed, element.completed and member.login.
Install this skill
npx skills add hookdeck/webhook-skills --skill teachfloor-webhooks
Teachfloor is a cohort-based learning platform. Its webhooks send a JSON event to your URL when something happens to a course, module, element or member. Each request carries a teachfloor-signature header: the hex HMAC-SHA256 of the raw request body, keyed with the endpoint's signing secret.
When to Use This Skill
- How do I receive Teachfloor webhooks?
- How do I verify the
teachfloor-signatureheader? - Why is my Teachfloor webhook signature verification failing?
- How do I handle
course.join,course.completed,element.completedormember.loginevents?
Verification (core)
teachfloor-signature is the bare lowercase hex HMAC-SHA256 of the raw request body: no prefix, no timestamp. The key is the endpoint's signing secret, used as a UTF-8 string (not hex- or base64-decoded). Check the header is exactly 64 hex characters before decoding, because Buffer.from(x, 'hex') silently truncates invalid input. Hex is case-insensitive.
const crypto = require('crypto');
function verifyTeachfloorSignature(rawBody, signature, secret = process.env.TEACHFLOOR_WEBHOOK_SECRET) {
if (!secret || typeof signature !== 'string') return false;
if (!/^[0-9a-f]{64}$/i.test(signature)) return false; // also guards the hex decode
const expected = crypto.createHmac('sha256', secret).update(rawBody).digest();
return crypto.timingSafeEqual(expected, Buffer.from(signature, 'hex'));
}
// rawBody: Buffer from express.raw({ type: '*/*' }); signature: req.headers['teachfloor-signature']
Return 401 when this fails, 400 for a body that isn't a JSON object, and 200 once handled. In Python use hmac.compare_digest on bytes (encode both sides) so a non-ASCII header gives 401, not 500. Details in references/verification.md.
For complete handlers with tests, see examples/express/, examples/nextjs/, examples/fastapi/.
Setup
Add an endpoint under Developers > Webhooks, choose the events, then use Reveal Signing Secret on the endpoint to copy the secret into TEACHFLOOR_. Full steps in references/setup.md. When you use a Teachfloor source in Hookdeck, put the same signing secret in the source's verification settings; Hookdeck's source verifies the signature before forwarding.
Payload and Event Types
Every event shares one envelope: id, type, created_at and data. Dispatch on the top-level type. Treat every field as untrusted until you've checked its type.
type | Triggered When |
|---|---|
course.created / course.updated | A course is created or updated |
course.join | A member joins a course |
course.completed | A member completes a course |
module.created / module.updated | A module is created or updated |
element.created / element.updated / element.deleted | An element is created, updated or deleted |
element.completed | A member completes an element |
member.login | A member logs in |
More detail and payload shapes are in references/overview.md.
Environment Variables
TEACHFLOOR_WEBHOOK_SECRET=your_signing_secret # Developers > Webhooks > endpoint > Reveal Signing Secret
Local Development
npx hookdeck-cli listen 3000 teachfloor --path /webhooks/teachfloor
No account required. Use the printed URL as the endpoint URL in Teachfloor.
Resources
- references/overview.md - How Teachfloor webhooks work, events, payloads, retries
- references/setup.md - Add the endpoint, reveal the signing secret
- references/verification.md - HMAC-SHA256 check, gotchas, debugging
- examples/ - Runnable Express, Next.js and FastAPI handlers with tests