# Firstbase Webhooks

Firstbase (remote-employee equipment) sends a thin JSON webhook when an order, return order or
inventory order is created, updated or deleted. The notification carries an `eventType` and the
resource id; you fetch the details from the Firstbase API. Webhooks are **not signed**. You
authenticate them with a secret header that Firstbase adds when you choose **Custom header**
authentication.

> Use Custom header authentication, not Auth token or OAuth.

Auth token doesn't document which header it sends, and OAuth client credentials need a token
server, so this skill covers only Custom header.

## When to Use This Skill

* How do I receive Firstbase webhooks?
* How do I authenticate Firstbase webhook requests with a custom header?
* Does Firstbase sign webhook payloads? (No: use the secret header)
* How do I handle `CREATED`, `UPDATED` and `DELETED` order notifications?
* Why does my Firstbase webhook endpoint return 401?

## Verification (core)

```javascript
const crypto = require('crypto');

// Hash both sides: equal-length buffers, so timingSafeEqual never throws.
function safeEqual(a, b) {
  const ha = crypto.createHash('sha256').update(String(a)).digest();
  const hb = crypto.createHash('sha256').update(String(b)).digest();
  return crypto.timingSafeEqual(ha, hb);
}

function verifyFirstbaseRequest(headers,
    name = process.env.FIRSTBASE_WEBHOOK_HEADER || 'Authorization',
    secret = process.env.FIRSTBASE_WEBHOOK_SECRET) {
  if (!secret) return false;                    // never accept when unconfigured
  const received = headers[name.toLowerCase()]; // Node lowercases header names
  return typeof received === 'string' && received !== '' && safeEqual(received, secret);
}

```

* The header name is whatever you typed in Firstbase, so it is read from
  `FIRSTBASE_WEBHOOK_HEADER` (default `Authorization`) and looked up case-insensitively.
* `FIRSTBASE_WEBHOOK_SECRET` is the exact, **whole** header value, including any `Bearer ` prefix
  you typed. Compare the whole value; don't strip or parse a prefix.
* Python: `hmac.compare_digest(received.encode(), secret.encode())` on bytes, never `str`
  (non-ASCII `str` raises).
* Missing header or mismatch: `401`. Bad body: `400`. Handled: any `2xx`.
* Read the body raw (`express.raw({ type: '*/*' })`) and authenticate before parsing it.

**Security note:** a static shared credential authenticates the sender, not the body, and gives
no replay protection (no signature, no timestamp). Use HTTPS and rotate the credential if it
leaks.

> **For complete handlers with tests**, see [examples/express/](https://github.com/hookdeck/webhook-skills/tree/main/skills/firstbase-webhooks/examples/express/), [examples/nextjs/](https://github.com/hookdeck/webhook-skills/tree/main/skills/firstbase-webhooks/examples/nextjs/), [examples/fastapi/](https://github.com/hookdeck/webhook-skills/tree/main/skills/firstbase-webhooks/examples/fastapi/).

## Event Types

Firstbase sends one notification per change, per resource type (orders, return orders,
inventory orders). The `eventType` field is one of:

| eventType | Sent When |
| --- | --- |
| `CREATED` | An order, return order or inventory order is created |
| `UPDATED` | One of those resources changes |
| `DELETED` | One of those resources is deleted |

The body is thin: the `eventType` plus the id of the resource. Fetch the full record from the
Firstbase API.

## Environment Variables

```bash
FIRSTBASE_WEBHOOK_HEADER=Authorization       # header name from Firstbase Custom header auth
FIRSTBASE_WEBHOOK_SECRET=your-header-value   # exact, whole value, incl. any "Bearer " prefix

```

## Local Development

Firstbase can't reach `localhost`. Tunnel with the Hookdeck CLI (no account required):

```bash
npx hookdeck-cli listen 3000 firstbase --path /webhooks/firstbase

```

Use the printed URL as the webhook URL in Firstbase. The endpoint must be HTTPS with a valid
certificate and accept `POST`.

## Resources

* [references/overview.md](https://github.com/hookdeck/webhook-skills/blob/main/skills/firstbase-webhooks/references/overview.md) - What Firstbase webhooks are, events and payload shape
* [references/setup.md](https://github.com/hookdeck/webhook-skills/blob/main/skills/firstbase-webhooks/references/setup.md) - Configure the webhook with Custom header authentication
* [references/verification.md](https://github.com/hookdeck/webhook-skills/blob/main/skills/firstbase-webhooks/references/verification.md) - Header check details, gotchas, debugging 401s
* [examples/](https://github.com/hookdeck/webhook-skills/tree/main/skills/firstbase-webhooks/examples/) - Runnable Express, Next.js and FastAPI handlers with tests