Documentation Index
Fetch the complete documentation index at: https://docs.prudra.dev/llms.txt
Use this file to discover all available pages before exploring further.
Test locally
Prudra webhooks require a publicly reachable HTTPS endpoint. In local development, use ngrok to expose your local server via a public tunnel URL.
Setup with ngrok
# 1. Install ngrok
brew install ngrok # macOS
# or download from https://ngrok.com/download
# 2. Start your local server
npx tsx example-05-webhooks.ts
# Server running on :4005
# 3. In a new terminal, start ngrok
ngrok http 4005
# Forwarding: https://abc123.ngrok-free.app -> http://localhost:4005
# 4. Register the ngrok URL as your webhook endpoint
curl -X POST https://api.prudra.dev/webhooks \
-H "Authorization: Bearer prv_test_sk_..." \
-H "Content-Type: application/json" \
-d '{
"url": "https://abc123.ngrok-free.app/webhooks/prudra",
"events": ["*"]
}'
# Save the returned secret
export PRUDRA_WEBHOOK_SECRET=whsec_...
Triggering test events
Trigger a payment to generate a payment.received webhook:
# 1. Make a payment (stub mode)
curl -X POST http://localhost:4005/your-endpoint \
-H "X-PAYMENT: stub_payment_accepted" \
-H "Content-Type: application/json" \
-d '{}'
# 2. Watch your terminal for the webhook delivery
# [Webhook] Received: payment.received (evt_clx1abc123)
Webhook receiver example
The full webhook server from example-05:
import express from 'express';
import { verifyWebhook } from '@prudra/webhooks';
const app = express();
app.post(
'/webhooks/prudra',
express.raw({ type: '*/*' }),
async (req, res) => {
res.sendStatus(200);
const isValid = verifyWebhook({
payload: req.body as Buffer,
signature: req.headers['x-prudra-signature'] as string,
timestamp: req.headers['x-prudra-timestamp'] as string,
secret: process.env.PRUDRA_WEBHOOK_SECRET!,
});
if (!isValid) {
console.warn('[Webhook] Invalid signature');
return;
}
const event = JSON.parse((req.body as Buffer).toString());
console.log(`[Webhook] ${event.type} (${event.eventId})`);
switch (event.type) {
case 'payment.received':
console.log(' Amount:', event.payload.amount);
break;
case 'vault.sealed':
console.log(' Summary:', event.payload.summary);
break;
}
}
);
app.use(express.json());
app.listen(4005);
Replay deliveries
If you miss a webhook (e.g., ngrok wasn’t running), replay it from the API:
# List recent delivery attempts
curl "https://api.prudra.dev/webhooks/wh_clx1abc123/attempts" \
-H "Authorization: Bearer prv_test_sk_..."
# Replay a specific delivery
curl -X POST https://api.prudra.dev/webhooks/wh_clx1abc123/replay \
-H "Authorization: Bearer prv_test_sk_..." \
-d '{ "deliveryId": "del_clx1abc123" }'
Updating your URL
When ngrok restarts, it generates a new URL. Update your webhook URL:
curl -X PATCH https://api.prudra.dev/webhooks/wh_clx1abc123 \
-H "Authorization: Bearer prv_test_sk_..." \
-d '{ "url": "https://new-url.ngrok-free.app/webhooks/prudra" }'