Skip to main content
Test your webhook integration before deploying to production. Use these tools to receive real deliveries locally, inspect payloads, and debug failures.

Local Testing with ngrok

ngrok creates a public HTTPS tunnel to your local server, letting Xquik deliver webhooks to your development machine.
1

Install ngrok

# macOS
brew install ngrok

# Linux
curl -sSL https://ngrok-agent.s3.amazonaws.com/ngrok-v3-stable-linux-amd64.tgz \
  | tar -xz -C /usr/local/bin

# Authenticate (free account required)
ngrok config add-authtoken YOUR_NGROK_TOKEN
2

Start your local server

Run your webhook handler on a local port (e.g. :3000):
node server.js
# or: python app.py
# or: go run main.go
3

Start the ngrok tunnel

ngrok http 3000
ngrok outputs a public HTTPS URL:
Forwarding  https://a1b2c3d4.ngrok-free.app → http://localhost:3000
Copy the https:// URL.
4

Create a webhook with the ngrok URL

curl -X POST https://xquik.com/api/v1/webhooks \
  -H "x-api-key: xq_YOUR_KEY_HERE" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://a1b2c3d4.ngrok-free.app/webhook",
    "eventTypes": ["tweet.new", "tweet.reply"]
  }' | jq
Save the secret from the response for signature verification.
5

Trigger events

When a monitored account posts a tweet, Xquik delivers the event through ngrok to your local server. Check your server logs and the ngrok web inspector at http://localhost:4040.
ngrok URLs change every time you restart the tunnel (free plan). Update your webhook URL after each restart, or use a paid ngrok plan for stable subdomains.

Testing with RequestBin

Use webhook.site to inspect webhook payloads without running a local server.
1

Get a RequestBin URL

Visit webhook.site. A unique HTTPS URL is generated automatically:
https://webhook.site/a1b2c3d4-e5f6-7890-abcd-ef1234567890
2

Create a webhook with the RequestBin URL

curl -X POST https://xquik.com/api/v1/webhooks \
  -H "x-api-key: xq_YOUR_KEY_HERE" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://webhook.site/a1b2c3d4-e5f6-7890-abcd-ef1234567890",
    "eventTypes": ["tweet.new"]
  }' | jq
3

View incoming payloads

When events arrive, they appear in the webhook.site dashboard in real time. Inspect headers (X-Xquik-Signature, Content-Type) and the JSON body to verify the payload format matches your expectations.
RequestBin is useful for inspecting payload structure. For testing signature verification and handler logic, use ngrok with a local server instead.

Sending Test Payloads

Simulate a webhook delivery to your local handler without waiting for real events. This is useful for testing signature verification and event processing logic.
# Generate a test signature
SECRET="your_webhook_secret_here"
PAYLOAD='{"eventType":"tweet.new","username":"elonmusk","data":{"tweetId":"1893456789012345678","text":"The future is now.","metrics":{"likes":42000,"retweets":8500,"replies":3200}}}'

SIGNATURE="sha256=$(echo -n "$PAYLOAD" | openssl dgst -sha256 -hmac "$SECRET" | cut -d' ' -f2)"

# Send to your local server
curl -X POST http://localhost:3000/webhook \
  -H "Content-Type: application/json" \
  -H "X-Xquik-Signature: $SIGNATURE" \
  -d "$PAYLOAD"
Test payload structure:
{
  "eventType": "tweet.new",
  "username": "elonmusk",
  "data": {
    "tweetId": "1893456789012345678",
    "text": "The future is now.",
    "metrics": {
      "likes": 42000,
      "retweets": 8500,
      "replies": 3200
    }
  }
}
Test all event types by changing the eventType field: tweet.new, tweet.reply, tweet.quote, tweet.retweet.

Debugging Delivery Failures

Check Delivery Status

Query the deliveries endpoint to see delivery attempts and error details:
curl https://xquik.com/api/v1/webhooks/15/deliveries \
  -H "x-api-key: xq_YOUR_KEY_HERE" | jq
Response:
{
  "deliveries": [
    {
      "id": "502",
      "streamEventId": "9002",
      "status": "failed",
      "attempts": 3,
      "lastStatusCode": 500,
      "lastError": "Internal Server Error",
      "createdAt": "2026-02-24T14:25:00.000Z"
    }
  ]
}

Delivery Statuses

StatusDescription
pendingQueued, waiting for next attempt
deliveredYour endpoint returned 2xx. Complete.
failedMost recent attempt failed. Retrying with backoff.
exhaustedAll retry attempts used. No further retries.

Common Failure Reasons

Your endpoint must respond within 10 seconds. If your handler is slow, return 200 immediately and process the event asynchronously using a background job queue.
Any response outside the 200-299 range counts as a failure. Check your server logs for unhandled exceptions or validation errors in your handler. Common culprits: missing middleware (e.g. express.raw()), JSON parse errors, or database connection failures.
The webhook URL hostname could not be resolved. Verify your domain DNS records are correct. If using ngrok, confirm the tunnel is still running.
Webhook URLs must use HTTPS with a valid certificate. Self-signed certificates are rejected. Use a trusted CA (Let’s Encrypt, Cloudflare) or ngrok for local development.
The target server is not accepting connections. Verify your server is running and listening on the correct port. Check firewall rules if running on a cloud provider.
Compute the HMAC over the raw request body bytes, not a re-serialized JSON object. Re-serialization can alter whitespace or key ordering. Use express.raw() in Node.js, request.get_data() in Flask, or io.ReadAll(r.Body) in Go.