Agent skill
Firstbase Webhooks Skill
Receive and authenticate Firstbase webhooks. Use when setting up a Firstbase webhook endpoint with Custom header authentication, checking the secret header, debugging 401s, or handling order, return order and inventory order notifications with eventType CREATED, UPDATED or DELETED.
Install this skill
npx skills add hookdeck/webhook-skills --skill 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,UPDATEDandDELETEDorder notifications? - Why does my Firstbase webhook endpoint return 401?
Verification (core)
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(defaultAuthorization) and looked up case-insensitively. FIRSTBASE_WEBHOOK_SECRETis the exact, whole header value, including anyBearerprefix you typed. Compare the whole value; don't strip or parse a prefix.- Python:
hmac.compare_on bytes, neverdigest(received.encode(), secret.encode()) str(non-ASCIIstrraises). - Missing header or mismatch:
401. Bad body:400. Handled: any2xx. - 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/, examples/nextjs/, 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
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):
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 - What Firstbase webhooks are, events and payload shape
- references/setup.md - Configure the webhook with Custom header authentication
- references/verification.md - Header check details, gotchas, debugging 401s
- examples/ - Runnable Express, Next.js and FastAPI handlers with tests