Agent skill
Cover Genius Webhooks Skill
Receive and verify Cover Genius (XCover) Offers webhooks. Use when setting up a Cover Genius webhook listener, checking the X-Api-Key header, debugging 401s on Offers webhooks, or handling embedded insurance events like BOOKING_CREATED, BOOKING_CANCELLED and RENEWAL_DUE.
Install this skill
npx skills add hookdeck/webhook-skills --skill cover-genius-webhooks
Cover Genius is an embedded insurance platform. Its Offers API sends an HTTP POST to your listener when a booking or policy renewal changes. The webhook carries no payload signature: Cover Genius sends your authentication key as plain text in the X-Api-Key header, and you verify it by comparing that header with your key.
This skill covers Offers webhooks only. XClaim (XClaim-Signature) and RentalCover (X-Signature plus a timestamp) use other schemes and aren't covered.
When to Use This Skill
- How do I receive Cover Genius webhooks?
- How do I verify the X-Api-Key header on a Cover Genius Offers webhook?
- Does Cover Genius sign webhook payloads? (No: shared key in
X-Api-Key) - How do I handle BOOKING_CREATED, BOOKING_CANCELLED or RENEWAL_DUE events?
- Why does my Cover Genius 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 verifyCoverGeniusRequest(headers, apiKey = process.env.COVER_GENIUS_API_KEY) {
if (!apiKey) return false; // never accept when unconfigured
const received = headers['x-api-key']; // plain text, no prefix
return typeof received === 'string' && safeEqual(received, apiKey);
}
Return 401 when this fails, 400 for a body that isn't a JSON object, and 200 once handled (any other status makes Cover Genius retry up to 3 times). There is no body signature, so the raw body isn't needed for verification, but authenticate before parsing it. In Express, read the body with express.raw({ type: '*/*' }) so every content type is checked.
Cover Genius also sends Authorization: Signature ..., an HMAC-SHA256 over the Date header only. It adds nothing over the key check, so it's optional; see references/verification.md.
For complete handlers with tests, see examples/express/, examples/nextjs/, examples/fastapi/.
Event Types
Every body is { "event": "...", "payload": { ... } }.
| Event | Sent When |
|---|---|
BOOKING_CREATED | An Offer is confirmed through an API request |
BOOKING_UPDATED | A confirmed Offer is updated through an API request |
BOOKING_CANCELLED | A confirmed Offer is cancelled through an API request |
RENEWAL_CREATED | The policy has been renewed |
RENEWAL_NOTIFICATION | A renewal is approaching |
RENEWAL_DUE | The renewal due date arrives (policy active until expiry_date) |
RENEWAL_EXPIRED | The renewal expiry date arrives; no longer renewable |
Environment Variables
COVER_GENIUS_API_KEY=your_cover_genius_api_key # the authentication key you gave your CSE
Local Development
For local webhook testing, run the Hookdeck CLI (no account required):
npx hookdeck-cli listen 3000 cover-genius --path /webhooks/cover-genius
Give the printed URL to your Cover Genius Client Solution Engineer as the listener URL.
Resources
- references/overview.md - Offers events, payload shapes, retries
- references/setup.md - What to send your CSE, key setup, testing
- references/verification.md - X-Api-Key check, optional Authorization signature, gotchas
- examples/ - Runnable Express, Next.js and FastAPI handlers with tests