Agent skill
Partnero Webhooks Skill
Receive and verify Partnero webhooks. Use when setting up a Partnero outgoing webhook endpoint, debugging `Signature` header verification failures, or handling affiliate and referral program events like partner.created, transaction.created and reward.approved.
Install this skill
npx skills add hookdeck/webhook-skills --skill partnero-webhooks
Partnero (affiliate, referral and partner program platform) sends an HTTP POST with a JSON body to your endpoint when partners, customers, transactions or rewards change. Every request carries a Signature header: the hex HMAC-SHA256 of the raw request body, keyed with the webhook's signing secret.
When to Use This Skill
- How do I receive Partnero webhooks?
- How do I verify the Partnero
Signatureheader? - Why does my Partnero webhook signature verification fail?
- How do I handle
partner.created,transaction.createdorreward.approvedevents? - How do I test Partnero outgoing webhooks locally?
Verification (core)
- Header:
Signature(literally that name). Value: bare lowercase hex digest, no prefix. - Signed content: the raw body bytes only (no timestamp, no id).
- Key: the webhook's signing secret as UTF-8 bytes. Compare the whole header value as one digest.
const crypto = require('crypto');
function verifyPartneroSignature(rawBody, signatureHeader, secret) {
if (!signatureHeader || !secret) return false;
if (!/^[0-9a-f]{64}$/i.test(signatureHeader)) return false; // check shape before comparing
const expected = crypto.createHmac('sha256', secret).update(rawBody).digest('hex');
return crypto.timingSafeEqual(
Buffer.from(signatureHeader.toLowerCase()),
Buffer.from(expected)
);
}
- Missing, malformed or mismatched signature:
401. Bad JSON after a valid signature:400. Otherwise200. - Read the body raw (
express.raw({ type: '*/*' }),request.arrayBuffer(),await request.body()) and parse JSON only after the check. Partnero signs PHPjson_encodeoutput (escaped\/and\uXXXX), soJSON.stringify(req.body)never matches. - In Python use
hmac.compare_digeston bytes;strraisesTypeErroron non-ASCII input. - No timestamp is signed, so there is no replay window to check. Deduplicate on your own keys.
For complete handlers with tests, see examples/express/, examples/nextjs/, examples/fastapi/.
Event Types
Body: {event, url, webhook_. Dispatch on event; data holds the event-specific fields. No header names the event type.
| Event | Sent When |
|---|---|
partner.created | A new partner signs up or is created |
partner.updated | Partner information is updated |
partner.approved | A partner application is approved |
partner.rejected | A partner application is rejected |
partner.archived | A partner is archived |
partner.deleted | A partner is deleted |
customer.created | A new customer is created |
customer.updated | Customer information is updated |
customer.deleted | A customer is deleted |
transaction.created | A new transaction is recorded |
transaction.updated | A transaction is updated |
transaction.deleted | A transaction is deleted (refund) |
reward.created | A commission/reward is created |
reward.approved | A reward is approved for payout |
reward.paid | A reward is marked as paid |
Environment Variables
PARTNERO_WEBHOOK_SECRET=your_webhook_signing_secret # shown when you create the webhook
Local Development
Partnero can't reach localhost. Tunnel with the Hookdeck CLI (no account required):
npx hookdeck-cli listen 3000 partnero --path /webhooks/partnero
Use the printed URL as the webhook URL in Partnero (Program Settings > Webhooks).
Resources
- references/overview.md - What the webhooks are, events, payloads and delivery
- references/setup.md - Create the webhook and copy the signing secret
- references/verification.md - Signature details, gotchas, debugging
- examples/ - Runnable Express, Next.js and FastAPI handlers with tests