Getting Started / How It Works
How It Works
A technical walkthrough of how Paggio captures, stores, forwards, and replays webhook events.
1. Endpoint creation
When you create an endpoint, Paggio generates a unique slug and stores the endpoint configuration in the database (name, destination URL, secret key). The webhook URL is:
https://paggio.dev/api/webhook/:slug2. Capturing events
When a POST request arrives at the webhook URL, Paggio:
- 1. Returns
200 {"received": true}immediately — so the sender doesn't time out - 2. Reads the full request body and all headers
- 3. Detects the source (Stripe, GitHub, Shopify, etc.) from the request headers
- 4. Saves the event to the
webhook_eventstable with statuspending
3. Forwarding
If the endpoint has a destination URL configured, Paggio forwards the original request (headers + body) to that URL. Hop-by-hop headers (connection, transfer-encoding, etc.) are stripped. A 10-second timeout is enforced.
- ✓ 2xx response → event status set to
delivered - ✗ 4xx / 5xx response → event status set to
failed - ✗ Network error / timeout → event status set to
failed - ● No destination URL → event status set to
captured
captured.4. Event data stored
Every captured event stores the following:
{
"id": "uuid",
"endpoint_id": "uuid",
"user_id": "uuid",
"source": "stripe",
"event_type": "payment_intent.succeeded",
"method": "POST",
"headers": { "stripe-signature": "t=...,v1=..." },
"payload": { "id": "evt_123", "type": "payment_intent.succeeded" },
"remote_addr": "54.187.205.235",
"status": "delivered",
"response_status": 200,
"response_body": "{ \"ok\": true }",
"latency_ms": 142,
"received_at": "2024-03-10T15:23:41.000Z"
}5. Replays
A replay takes a stored event and re-sends the original payload + headers to a target URL. Each replay is saved as a separate record in the replay_attempts table — replays never modify the original event.
Replay targets can be: original destination, localhost:3000 (for local dev), or any custom URL.
6. Source detection
Paggio inspects request headers to identify the source. For example:
// Examples of what Paggio checks
if (headers.get('stripe-signature')) return 'stripe';
if (headers.get('x-github-event')) return 'github';
if (headers.get('x-shopify-hmac-sha256')) return 'shopify';
if (headers.get('linear-signature')) return 'linear';
if (headers.get('x-vercel-signature')) return 'vercel';
// ...15+ sources total