Create Your First Webhook
Webhooks allow your application to receive real-time notifications when events happen in PUGUH — such as user signups, organization changes, or billing events.
How Webhooks Work
- You register an endpoint URL in PUGUH
- You subscribe to specific event types (e.g.,
user.created) - When an event occurs, PUGUH sends an HTTP POST to your endpoint
- Your server processes the event and returns
200 OK
Creating a Webhook Endpoint
Via API
bash
curl -X POST https://api-puguh.arsaka.io/webhooks/endpoints \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "X-Organization-ID: YOUR_ORG_ID" \
-H "Content-Type: application/json" \
-d '{
"url": "https://your-app.com/webhooks/puguh",
"events": ["user.created", "member.invited", "auth.login"],
"description": "My first webhook"
}' Response:
json
{
"id": "wh-uuid",
"url": "https://your-app.com/webhooks/puguh",
"events": ["user.created", "member.invited", "auth.login"],
"description": "My first webhook",
"secret": "whsec_xxxxxxxxxxxxxxxx",
"is_active": true,
"created_at": "2026-02-20T10:00:00Z"
} Important
The secret is only shown once at creation time. Save it securely — you'll need it to verify webhook signatures.
Available Events
| Event | Description |
|---|---|
user.created | New user registered |
user.updated | User profile updated |
member.invited | Member invited to organization |
member.joined | Member accepted invitation |
member.removed | Member removed from organization |
organization.created | New organization created |
auth.login | User logged in |
auth.password_changed | Password was changed |
billing.subscription.created | New subscription started |
billing.invoice.paid | Invoice payment received |
Receiving Webhooks
PUGUH sends a POST request with JSON body:
json
{
"event": "user.created",
"timestamp": "2026-02-20T10:30:00Z",
"data": {
"user_id": "usr-uuid",
"email": "new-user@example.com",
"full_name": "John Doe"
},
"webhook_id": "wh-uuid",
"delivery_id": "del-uuid"
} Verifying Signatures
Always verify the X-Puguh-Signature header to ensure the request is from PUGUH:
Python
python
import hmac
import hashlib
def verify_webhook(payload: bytes, signature: str, secret: str) -> bool:
expected = hmac.new(
secret.encode(),
payload,
hashlib.sha256
).hexdigest()
return hmac.compare_digest(f"sha256={expected}", signature) TypeScript
typescript
import { createHmac, timingSafeEqual } from 'crypto';
function verifyWebhook(payload: string, signature: string, secret: string): boolean {
const expected = `sha256=${createHmac('sha256', secret).update(payload).digest('hex')}`;
return timingSafeEqual(Buffer.from(signature), Buffer.from(expected));
} Webhook Limits by Plan
| Plan | Max Endpoints | Features |
|---|---|---|
| Free | 3 | Basic delivery |
| Pro | 10 | + Automatic retry |
| Business | 25 | + Guaranteed delivery |
| Enterprise | Unlimited | + Guaranteed delivery |
Best Practices
- Always verify signatures to prevent spoofed requests
- Respond quickly with
200 OK— process events asynchronously - Handle duplicates — use
delivery_idfor idempotency - Use HTTPS for your endpoint URL