Webhook Delivery
Receive HMAC-SHA256 signed HTTP POST callbacks for each detected tweet. Webhooks provide reliable delivery with automatic retries.
Request Headers
| Header | Description |
|---|---|
X-ScrapeBadger-Signature | HMAC-SHA256 signature: sha256=hex_digest |
X-ScrapeBadger-Delivery-Id | Unique delivery ID for idempotency |
X-ScrapeBadger-Event | Event type: tweet or test |
Content-Type | application/json |
User-Agent | ScrapeBadger-Webhook/1.0 |
Webhook Payload
// Webhook POST body (JSON)
{
"type": "tweet",
"monitor_id": "mon-123",
"tweet_id": "1234567890123456789",
"author_username": "elonmusk",
"tweet_published_at": "2026-03-04T12:00:00Z",
"detected_at": "2026-03-04T12:00:00.850Z",
"latency_ms": 850,
"tweet": {
"id": "1234567890123456789",
"text": "The future is electric...",
"created_at": "Mon Mar 04 12:00:00 +0000 2026",
"user_id": "44196397",
"username": "elonmusk",
"user_name": "Elon Musk",
"favorite_count": 0,
"retweet_count": 0,
"reply_count": 0,
"media": [],
"urls": [],
"hashtags": []
}
}Signature Verification
Always verify the X-ScrapeBadger-Signature header to ensure the request is authentic. The signature is computed as HMAC-SHA256(webhook_secret, request_body).
Node.js / Express
import crypto from 'crypto';
function verifyWebhookSignature(body, signature, secret) {
const expected = crypto
.createHmac('sha256', secret)
.update(body)
.digest('hex');
const received = signature.replace('sha256=', '');
return crypto.timingSafeEqual(
Buffer.from(expected),
Buffer.from(received)
);
}
// Express.js example
app.post('/webhooks/tweets', (req, res) => {
const signature = req.headers['x-scrapebadger-signature'];
const body = JSON.stringify(req.body);
if (!verifyWebhookSignature(body, signature, WEBHOOK_SECRET)) {
return res.status(401).send('Invalid signature');
}
const tweet = req.body;
console.log('New tweet from', tweet.author_username);
res.status(200).send('OK');
});Python / Flask
import hmac
import hashlib
from flask import Flask, request
app = Flask(__name__)
WEBHOOK_SECRET = "your_webhook_secret"
def verify_signature(body: bytes, signature: str, secret: str) -> bool:
expected = hmac.new(
secret.encode(),
body,
hashlib.sha256
).hexdigest()
received = signature.replace("sha256=", "")
return hmac.compare_digest(expected, received)
@app.post("/webhooks/tweets")
def handle_webhook():
signature = request.headers.get("X-ScrapeBadger-Signature", "")
if not verify_signature(request.data, signature, WEBHOOK_SECRET):
return "Invalid signature", 401
data = request.json
print(f"New tweet from @{data['author_username']}")
return "OK", 200Response Requirements
Success Response
Return any 2xx status code within 10 seconds to acknowledge delivery. The response body is ignored.
Retry Logic
Failed deliveries (non-2xx or timeout) are retried up to 3 times with exponential backoff. After all retries are exhausted, the delivery is marked as webhook_failed in the delivery log.
Idempotency
Use the X-ScrapeBadger-Delivery-Id header to deduplicate webhook deliveries on your end in case of retries.
Testing
Use the POST /v1/twitter/stream/webhooks/test endpoint to send a test payload to your webhook URL and verify it is receiving and processing events correctly.