DEV Community

Ahmed Rehan
Ahmed Rehan

Posted on

How to Debug Webhook Integrations in Minutes (Step-by-Step Guide)

Debugging webhooks is painful. You can't see what's being sent, signature verification fails mysteriously, and testing edge cases requires complex setups.

In this tutorial, I'll show you how to debug webhook integrations in minutes using Webhook Debugger & Logger.

What You'll Accomplish

By the end of this tutorial, you'll:

  • βœ… Capture webhook requests from any service
  • βœ… Inspect headers, body, and metadata in real-time
  • βœ… Test webhook signature verification
  • βœ… Replay requests to test idempotency
  • βœ… Export logs for analysis

⏱️ Time required: ~10 minutes


Prerequisites

  • Free Apify account (sign up with email or GitHub)
  • A service that sends webhooks (Stripe, GitHub, Shopify, etc.)
  • No coding required for basic usage

What You'll Achieve

By the end, you'll have a complete webhook debugging workflow that:

  • Captures every incoming request
  • Shows raw data for signature debugging
  • Allows you to replay requests for testing
  • Exports logs as JSON/CSV

Real example: I debugged a Stripe payment webhook in 8 minutes using this approach. Previously took me 3+ hours.


Step 1: Access Webhook Debugger & Logger

Go to the Webhook Debugger page on Apify Store.

If you don't have an Apify account:

  1. Click "Try for free"
  2. Sign up with email or GitHub (takes 30 seconds)
  3. You'll be redirected to Apify Console

What to expect: You'll see the Actor's input configuration page.

Screenshot showing Actor home page


Step 2: Configure Basic Settings

You'll see the input form with these key fields:

URL Count (required)

How many webhook URLs to generate (1-10)

{
  "urlCount": 3
}
Enter fullscreen mode Exit fullscreen mode

Example: If you're testing Stripe payments, GitHub webhooks, and Shopify orders, set this to 3.

Retention Hours (required)

How long to keep the URLs and logs (1-72 hours)

{
  "retentionHours": 24
}
Enter fullscreen mode Exit fullscreen mode

πŸ’‘ Tip: For quick debugging, 24 hours is plenty. For ongoing testing, use 72 hours.

Basic configuration example:

{
  "urlCount": 3,
  "retentionHours": 24
}
Enter fullscreen mode Exit fullscreen mode

Screenshot showing default Actor Input options


Step 3: Advanced Configuration (Optional)

For more control, expand the advanced settings:

Max Payload Size

Maximum request body size (default: 10MB)

{
  "maxPayloadSize": 10485760
}
Enter fullscreen mode Exit fullscreen mode

Enable JSON Parsing

Automatically parse JSON payloads (default: true)

{
  "enableJSONParsing": true
}
Enter fullscreen mode Exit fullscreen mode

JSON Schema Validation (v2.0+)

Reject invalid payloads automatically:

{
  "jsonSchema": {
    "type": "object",
    "required": ["event", "amount"],
    "properties": {
      "event": {"type": "string"},
      "amount": {"type": "number"}
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

When to use: Testing API integrations that must conform to a specific payload structure.

Screenshot showing Advanced input options filled in


Step 4: Run the Actor

  1. Click the "Start" button
  2. Status changes to "Running"
  3. Typically takes 5-10 seconds to spin up

⚠️ Tip: You can close the page - the Actor continues running in the background.

What's happening: The Actor is starting a serverless container and generating your webhook URLs.

πŸ“Έ Screenshot: Run status page showing


Step 5: Get Your Webhook URLs

Once running, there are two ways to get your URLs:

Method 1: Live View

Click "Live View" tab to see the web interface with your URLs (as shown in the previous screenshot).

Method 2: Key-Value Store

  1. Go to Storage β†’ Key-value stores
  2. Look for "WEBHOOK_STATE" key
  3. You'll see your webhook IDs

URL Format

https://<actor-run-id>.runs.apify.net/webhook/<webhook-id>
Enter fullscreen mode Exit fullscreen mode

Example:

https://abc123xyz.runs.apify.net/webhook/wh_abc123
https://abc123xyz.runs.apify.net/webhook/wh_def456
https://abc123xyz.runs.apify.net/webhook/wh_ghi789
Enter fullscreen mode Exit fullscreen mode

πŸ’‘ Pro tip: Bookmark these URLs for the duration of your testing.


Step 6: Configure Your Service

Now configure your webhook source (Stripe, GitHub, etc.) to send to your URL.

Example: Stripe

  1. Go to Stripe Dashboard β†’ Developers β†’ Webhooks
  2. Click "Add endpoint"
  3. Paste your webhook URL: https://<run-id>.runs.apify.net/webhook/wh_abc123
  4. Select events (e.g., payment_intent.succeeded)
  5. Save

Example: GitHub

  1. Go to Repository β†’ Settings β†’ Webhooks
  2. Click "Add webhook"
  3. Paste your URL
  4. Select events (e.g., push, pull_request)
  5. Save

What happens next: Any webhook sent to this URL will be captured and logged.


Step 7: Trigger a Test Webhook

There are two ways to test:

Method 1: Service Test Button

Most services have a "Send test webhook" button. Use it!

Method 2: Manual cURL

curl -X POST https://<run-id>.runs.apify.net/webhook/wh_abc123 \
  -H "Content-Type: application/json" \
  -d '{"event": "payment.success", "userId": "user_123", "amount": 9999}'
Enter fullscreen mode Exit fullscreen mode

What you'll see: Request appears in the Dataset within 1-2 seconds.


Step 8: View Results in Real-Time

Option 1: Dataset Tab

  1. Go to Storage β†’ Dataset
  2. See all captured requests
  3. Click any item to see full details

Option 2: Real-time Streaming (Advanced)

Use Server-Sent Events (SSE) for live monitoring:

curl -N https://<run-id>.runs.apify.net/log-stream
Enter fullscreen mode Exit fullscreen mode

What You'll See

Each captured request includes:

{
  "timestamp": "2025-12-25T14:31:45Z",
  "webhookId": "wh_abc123",
  "method": "POST",
  "headers": {
    "content-type": "application/json",
    "user-agent": "Stripe/1.0",
    "stripe-signature": "t=1735137105,v1=abc123..."
  },
  "body": "{\"type\": \"payment.success\", \"amount\": 9999}",
  "queryParams": {},
  "size": 78,
  "contentType": "application/json",
  "processingTime": 12,
  "remoteIp": "54.187.174.169",
  "statusCode": 200
}
Enter fullscreen mode Exit fullscreen mode

πŸ“Έ Screenshot: Results preview with data visible


Step 9: Debug Signature Verification

This is where raw data access becomes crucial.

The Problem

Signature verification fails because you're comparing the signature against the PARSED JSON, not the raw bytes.

The Solution

Use the captured raw body:

const crypto = require('crypto');

// From Webhook Debugger logs:
const rawBody = '{"type": "payment.success", "amount": 9999}';
const signature = 't=1735137105,v1=abc123...'; // from stripe-signature header
const secret = 'whsec_yourStripeSecret';

// Extract timestamp and signature
const [t, v1] = signature.split(',').map(s => s.split('=')[1]);

// Compute expected signature
const payload = `${t}.${rawBody}`;
const hmac = crypto.createHmac('sha256', secret);
hmac.update(payload, 'utf8');
const expectedSignature = hmac.digest('hex');

// Verify
const isValid = crypto.timingSafeEqual(
  Buffer.from(v1),
  Buffer.from(expectedSignature)
);

console.log('Signature valid:', isValid);
Enter fullscreen mode Exit fullscreen mode

πŸ’‘ Key insight: You MUST use the raw body from the logs, not your parsed JSON object.


Step 10: Test Idempotency with Replay

Use the /replay API to test duplicate event handling:

curl -X POST https://<run-id>.runs.apify.net/replay/wh_abc123 \
  -H "Content-Type: application/json" \
  -d '{
    "destination": "https://myapp.com/webhook",
    "headers": {
      "X-Test-Replay": "true"
    }
  }'
Enter fullscreen mode Exit fullscreen mode

This resends the captured webhook to your destination, allowing you to verify that your app handles duplicates correctly.


Step 11: Export and Analyze

Export your logs for further analysis:

Via Console:

  1. Go to Storage β†’ Dataset
  2. Click "Export"
  3. Choose format (JSON, CSV, Excel)
  4. Download

Via API:

curl "https://api.apify.com/v2/datasets/<dataset-id>/items?format=json&clean=1" \
  -H "Authorization: Bearer <your-api-token>"
Enter fullscreen mode Exit fullscreen mode

Use cases for exported data:

  • Share with team members
  • Import into analytics tools
  • Create custom reports
  • Archive for compliance

Pro Tips for Better Results

1. Use Specific Webhook IDs

Create different IDs for different services:

  • wh_stripe for Stripe
  • wh_github for GitHub
  • wh_shopify for Shopify

2. Filter Logs

Use query parameters to filter:

/logs?webhookId=wh_stripe&method=POST&statusCode=200
Enter fullscreen mode Exit fullscreen mode

3. Force Status Codes

Test error handling:

https://<run-id>.runs.apify.net/webhook/wh_abc123?__status=500
Enter fullscreen mode Exit fullscreen mode

4. Simulate Latency (v2.0+)

Test timeout handling:

{
  "customResponseDelay": 5000  // 5 second delay
}
Enter fullscreen mode Exit fullscreen mode

Troubleshooting

Issue: "Webhook not found or expired"

Solution: Check that:

  1. The webhook ID is correct
  2. The Actor is still running
  3. The retention period hasn't expired

Use /info endpoint to verify:

curl https://<run-id>.runs.apify.net/info
Enter fullscreen mode Exit fullscreen mode

Issue: Requests not appearing

Solution:

  1. Verify the URL is correct
  2. Check that the Actor is in "Running" state
  3. Ensure the service is actually sending webhooks

Issue: JSON parsing errors

Solution: Check the enableJSONParsing setting and verify the payload is valid JSON.


Conclusion

You now have a complete webhook debugging workflow! πŸŽ‰

What you learned:
βœ… How to capture webhooks without localhost tunneling
βœ… How to inspect raw request data for signature debugging
βœ… How to replay webhooks to test idempotency
βœ… How to export and analyze webhook logs

Time saved: What used to take 3-4 hours now takes 10-15 minutes.

Try Webhook Debugger yourself: https://apify.com/ar27111994/webhook-debugger-logger

Questions? Drop them in the comments! πŸ‘‡


πŸ‘ If this tutorial helped you, please give it a like and follow for more webhook debugging tips!

Top comments (0)