Agent skill
TheirStack Webhooks Skill
Receive and verify TheirStack webhooks. Use when setting up TheirStack webhook handlers, debugging X-TheirStack-Signature-256 signature verification, or handling job and technographic events like job.new, company.new, job.closed, or tech.new.
Install this skill
npx skills add hookdeck/webhook-skills --skill theirstack-webhooks
When to Use This Skill
- How do I receive TheirStack webhooks?
- How do I verify the X-TheirStack-Signature-256 header?
- How do I handle job.new, company.new, job.closed, or tech.new events?
- Why is my TheirStack webhook signature verification failing?
- Why does TheirStack send no signature header?
Verification (core)
TheirStack signs the raw request body with HMAC-SHA256 keyed on the webhook's signing secret (minimum 16 characters, set or generated on the webhook) and sends X-TheirStack-Signature-256: sha256=<hex>. There is no SDK, so verify manually: require and strip the sha256= prefix, compute the HMAC over the raw body (before JSON parsing), and compare in constant time.
The header is only sent when a signing secret is configured. Without one, deliveries are unsigned and fail verification, so always set a secret.
Node (check for exactly 64 hex chars first: Buffer.from(x, 'hex') silently truncates invalid input):
const crypto = require('crypto');
function verifyTheirStackWebhook(rawBody, signatureHeader, secret) {
if (!secret || typeof signatureHeader !== 'string') return false;
if (!signatureHeader.startsWith('sha256=')) return false;
const received = signatureHeader.slice('sha256='.length);
if (!/^[0-9a-f]{64}$/i.test(received)) return false;
const expected = crypto.createHmac('sha256', secret).update(rawBody).digest();
return crypto.timingSafeEqual(Buffer.from(received, 'hex'), expected);
}
Python (compare bytes so a non-ASCII header gives 401, not a 500 TypeError):
import hmac, hashlib
def verify_theirstack_webhook(raw_body: bytes, signature_header: str | None, secret: str | None) -> bool:
if not secret or not signature_header or not signature_header.startswith("sha256="):
return False
expected = hmac.new(secret.encode(), raw_body, hashlib.sha256).hexdigest()
received = signature_header[len("sha256="):].lower().encode()
return hmac.compare_digest(received, expected.encode())
Express: read the body with express.raw({ type: '*/*' }) so any content type verifies.
For complete handlers with route wiring, event dispatch, and tests, see:
Setup with Hookdeck
Set a signing secret on the TheirStack webhook (Signing Secret field, or secret via the Webhooks API). Without one, deliveries are unsigned and fail verification. Use the same secret in your receiver or in the Hookdeck source's webhook secret. See references/setup.md.
Common Event Types
The event name is in the body, not a header. Every delivery is one record in the envelope { "id": ..., "type": "<event>", "payload": {...} }.
Event (type) | Triggered When | Payload |
|---|---|---|
job.new | A new job matching the saved search is discovered | Full Job record |
company.new | A company matches the saved search for the first time (once per webhook) | Full Company record |
job.closed | A matching job is closed or removed by the source | { id, closed_at } |
tech.new | A company adopts a new technology (access on request) | Technology change record |
For the full event reference, see TheirStack webhook docs.
Important Headers
| Header | Description |
|---|---|
X-TheirStack-Signature-256 | sha256=<hex> HMAC-SHA256 of the raw body. Only sent when a signing secret is set |
Environment Variables
THEIRSTACK_WEBHOOK_SECRET=your_signing_secret_here # Signing secret on the TheirStack webhook (min 16 chars)
Delivery Behavior
- Return any 2xx to acknowledge. Failed deliveries are retried every hour for 48 hours.
- Be ready for at least 2 concurrent requests and for duplicates; deduplicate on the record
id.
Local Development
# Start tunnel (no account needed)
npx hookdeck-cli listen 3000 theirstack --path /webhooks/theirstack
Reference Materials
- references/overview.md - TheirStack webhook concepts and events
- references/setup.md - Webhook and signing secret configuration
- references/verification.md - Signature verification details