Persona webhooks events
Skill jeremylongshore/claude-code-plugins-plus-skills/skills/.curated/persona-webhooks-events
'Handle Persona webhook events for inquiry and verification status changes.From its SKILL.md
npx -y skills add jeremylongshore/claude-code-plugins-plus-skills --skill persona-webhooks-eventsAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
What its file declares
Copied from the file, not written here
The file declares its own license as MIT. That is the author’s claim about this one file, and it is not the same thing as the license GitHub reports for the repository, which is listed with the other numbers below.
SKILL.md
4.1 KB, 811 tokens by cl100k_base, as published. Nobody here has run it
persona webhooks events | sed 's/\b(.)/\u\1/g'
Overview
HMAC signature verification, inquiry.completed/approved/declined events, idempotent processing.
Prerequisites
- Completed
persona-install-authsetup - Valid Persona API key (sandbox or production)
Instructions
Step 1: Configure Webhook in Dashboard
1. Dashboard > Settings > Webhooks > Add Webhook
2. URL: https://your-app.com/webhooks/persona
3. Events: inquiry.completed, inquiry.approved, inquiry.declined,
verification.passed, verification.failed
4. Copy the webhook secret for signature verification
Step 2: Webhook Endpoint with HMAC Verification
import express from 'express';
import crypto from 'crypto';
const app = express();
app.post('/webhooks/persona',
express.raw({ type: 'application/json' }),
async (req, res) => {
const signature = req.headers['persona-signature'] as string;
const secret = process.env.PERSONA_WEBHOOK_SECRET!;
// Verify HMAC-SHA256 signature
const expectedSig = crypto
.createHmac('sha256', secret)
.update(req.body)
.digest('hex');
if (!crypto.timingSafeEqual(Buffer.from(signature || ''), Buffer.from(expectedSig))) {
return res.status(401).json({ error: 'Invalid signature' });
}
const event = JSON.parse(req.body.toString());
await handlePersonaEvent(event);
res.status(200).json({ received: true });
}
);
Step 3: Event Handlers
async function handlePersonaEvent(event: any) {
const { type, data } = event;
switch (type) {
case 'inquiry.completed':
const inquiryId = data.attributes.payload.data.id;
const referenceId = data.attributes.payload.data.attributes['reference-id'];
console.log(`Inquiry completed: ${inquiryId} for user ${referenceId}`);
// Update user KYC status in your database
await updateUserKycStatus(referenceId, 'completed');
break;
case 'inquiry.approved':
await updateUserKycStatus(data.attributes.payload.data.attributes['reference-id'], 'approved');
break;
case 'inquiry.declined':
await updateUserKycStatus(data.attributes.payload.data.attributes['reference-id'], 'declined');
break;
case 'verification.passed':
console.log(`Verification passed: ${data.attributes.payload.data.id}`);
break;
case 'verification.failed':
console.log(`Verification failed: ${data.attributes.payload.data.id}`);
break;
default:
console.log(`Unhandled event: ${type}`);
}
}
Step 4: Idempotent Processing
const processedEvents = new Set<string>();
async function idempotentHandle(event: any) {
const eventId = event.data.id;
if (processedEvents.has(eventId)) {
console.log(`Skipping duplicate: ${eventId}`);
return;
}
await handlePersonaEvent(event);
processedEvents.add(eventId);
}
Output
- Webhook endpoint with HMAC signature verification
- Event handlers for inquiry and verification lifecycle
- Idempotent processing preventing duplicates
Error Handling
| Issue | Cause | Solution |
|---|---|---|
| Invalid signature | Wrong webhook secret | Re-copy secret from Dashboard |
| Missing events | Events not selected | Check webhook configuration |
| Duplicate processing | Retry delivery | Use event ID deduplication |
Resources
Next Steps
For common errors, see persona-common-errors.
What ships with it
Read from the repository
Just SKILL.md. No reference files, no scripts.
Gives 0 of the 12 instructions most ux research skills give in 811 tokens
Counted across 242 of the 261 authors here whose files we hold, read 2026-09-06
- Fall back to prompt text when image generation failsin 16 of 242, across 7 files
- Offer three name candidates with reasonsin 16 of 242, across 7 files
- Comment on each result before asking the userin 16 of 242, across 7 files
- Check for an approved image-generation skill before auto-generatingin 15 of 242, across 6 files
- Degrade gracefully instead of interrupting on errorsin 14 of 242, across 5 files
- Guide the user to write SOUL.md and IDENTITY.mdin 13 of 242, across 6 files
- Derive two to four boundary rules in character voicein 11 of 242, across 4 files
- Report SXO score separately from SEO Health Scorein 11 of 242, across 6 files
- Run gacha.py for random drawsin 11 of 242, across 4 files
- Score the page across seven gap dimensionsin 11 of 242, across 6 files
- Derive three to five user stories citing SERP signalsin 11 of 242, across 6 files
- Confirm DataForSEO cost estimates before calling its APIsin 11 of 242, across 6 files
Said here and by no other author read
- Configure the webhook in the Persona Dashboard
- Subscribe to inquiry and verification lifecycle events
- Copy the webhook secret from the Dashboard
- Verify the HMAC-SHA256 signature of each request
- Return 401 for invalid signatures
- Read the raw request body before parsing
Grouped from the skills themselves: near-identical wordings counted once, and counted by distinct author, so one author publishing three of these counts once. Length counted with cl100k_base; the agent that loads this file may tokenize it differently.