# Teachfloor Webhooks

[Teachfloor](https://teachfloor.com) 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.

```javascript
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](https://github.com/hookdeck/webhook-skills/blob/main/skills/teachfloor-webhooks/references/verification.md).

> **For complete handlers with tests**, see [examples/express/](https://github.com/hookdeck/webhook-skills/tree/main/skills/teachfloor-webhooks/examples/express/),
> [examples/nextjs/](https://github.com/hookdeck/webhook-skills/tree/main/skills/teachfloor-webhooks/examples/nextjs/), [examples/fastapi/](https://github.com/hookdeck/webhook-skills/tree/main/skills/teachfloor-webhooks/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](https://github.com/hookdeck/webhook-skills/blob/main/skills/teachfloor-webhooks/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](https://github.com/hookdeck/webhook-skills/blob/main/skills/teachfloor-webhooks/references/overview.md).

## Environment Variables

```bash
TEACHFLOOR_WEBHOOK_SECRET=your_signing_secret   # Developers > Webhooks > endpoint > Reveal Signing Secret

```

## Local Development

```bash
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](https://github.com/hookdeck/webhook-skills/blob/main/skills/teachfloor-webhooks/references/overview.md) - How Teachfloor webhooks work, events, payloads, retries
* [references/setup.md](https://github.com/hookdeck/webhook-skills/blob/main/skills/teachfloor-webhooks/references/setup.md) - Add the endpoint, reveal the signing secret
* [references/verification.md](https://github.com/hookdeck/webhook-skills/blob/main/skills/teachfloor-webhooks/references/verification.md) - HMAC-SHA256 check, gotchas, debugging
* [examples/](https://github.com/hookdeck/webhook-skills/tree/main/skills/teachfloor-webhooks/examples/) - Runnable Express, Next.js and FastAPI handlers with tests