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-signature header?
  • Why is my Teachfloor webhook signature verification failing?
  • How do I handle course.join, course.completed, element.completed or member.login events?

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_WEBHOOK_SECRET. 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.

typeTriggered When
course.created / course.updatedA course is created or updated
course.joinA member joins a course
course.completedA member completes a course
module.created / module.updatedA module is created or updated
element.created / element.updated / element.deletedAn element is created, updated or deleted
element.completedA member completes an element
member.loginA 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


Repository

hookdeck/webhook-skills

v0.1.0 · MIT · Updated Nov 13, 2026

View on GitHub →