Webhooks
Webhooks push new articles to your own endpoint as they are published. Instead of polling the API on a schedule, you register a destination URL once and APITube delivers matching articles to it automatically.
What is a webhook?
A webhook is a saved query with a destination. You give APITube:
- a URL to deliver to, and
- a set of filters — the same parameters as
/v1/news/everything(language, category, source, sentiment, entities, dates, and more).
Whenever a newly indexed article matches those filters, APITube sends it to your URL with an HTTP POST.
Use cases:
- Real-time monitoring for a brand, competitor, topic, or person
- Breaking-news alerts into Slack, Telegram, or email
- Feeding ingestion pipelines without a polling worker
- Triggering automations (Zapier / Make / n8n) on matching coverage
Benefits:
- Push delivery — no polling loop to build or run
- Same filtering power as
/v1/news/everything - Signed payloads (HMAC-SHA256) so you can verify authenticity
- Automatic retries with exponential backoff
- Full delivery logs in the dashboard
Creating a webhook
Webhooks are created and managed in the dashboard (Webhooks page):
- Click Create webhook.
- Choose the API key the deliveries are billed to.
- Enter the destination URL (HTTPS recommended — payloads contain article data).
- Build the filters with the same controls as the API Playground (leave empty to receive every new article).
- On creation you are shown the signing secret once — copy and store it. It is used to verify delivery signatures and is never shown again.
TIP
A brand-new webhook starts delivering from the most recent articles forward. Test against an api_test_ key first — test deliveries are masked and do not consume your quota.
Plan limits
The number of webhooks you can have is limited by your subscription plan (counted across your whole account):
| Plan | Webhooks |
|---|---|
| Free | 1 |
| Basic | 5 |
| Professional | 20 |
| Corporate | 100 |
Delivery format
Each delivery is an HTTP POST to your URL:
POST https://your-app.example.com/webhook
Content-Type: application/json
X-Webhook-Signature: sha256=<hmac>
X-Webhook-Id: 42
X-Webhook-Timestamp: 1718800000{
"event": "articles.new",
"webhook_id": 1,
"delivered_at": "2026-06-19T12:00:00.000Z",
"articles": [
{
"id": 3036291250,
"title": "…",
"source": { "domain": "reuters.com" }
}
]
}Each article in articles has the same shape as /v1/news/everything. Up to 100 articles are delivered per request.
| Header | Description |
|---|---|
X-Webhook-Signature | sha256=<hmac> — HMAC-SHA256 signature (see below) |
X-Webhook-Id | ID of the delivery attempt |
X-Webhook-Timestamp | Unix timestamp (seconds) when the delivery was sent |
Respond with any 2xx status to acknowledge. A non-2xx response (or a timeout after 30 seconds) marks the delivery as failed and schedules a retry.
Verifying the signature
Every request is signed with HMAC-SHA256 over timestamp + "." + rawBody, using your webhook's signing secret. Verify it before trusting the payload.
import crypto from 'node:crypto';
function verifyWebhook(secret, signature, timestamp, rawBody) {
const expected = crypto
.createHmac('sha256', secret)
.update(timestamp + '.' + rawBody)
.digest('hex');
return signature === `sha256=${expected}`;
}
app.post('/webhook', (req, res) => {
const ok = verifyWebhook(
process.env.WEBHOOK_SECRET,
req.headers['x-webhook-signature'],
req.headers['x-webhook-timestamp'],
JSON.stringify(req.body),
);
if (!ok) return res.status(401).send('Invalid signature');
const { articles } = req.body;
console.log(`Received ${articles.length} articles`);
res.status(200).send('OK');
});import hmac
import hashlib
def verify_webhook(secret, signature, timestamp, raw_body):
expected = hmac.new(
secret.encode(),
(timestamp + '.' + raw_body).encode(),
hashlib.sha256,
).hexdigest()
return signature == f'sha256={expected}'Retries & statuses
If a delivery fails, APITube retries it with exponential backoff:
| Attempt | Delay |
|---|---|
| 1 | 1 minute |
| 2 | 5 minutes |
| 3 | 30 minutes |
| 4 | 2 hours |
| 5 | 12 hours |
After 5 failed attempts the delivery is marked failed. After several consecutive failed deliveries the webhook is automatically disabled — re-enable it from the dashboard once your endpoint is healthy.
A webhook subscription has one of three statuses:
| Status | Meaning |
|---|---|
active | Delivering matching articles |
paused | Paused by you — no deliveries until resumed |
disabled | Auto-disabled after repeated delivery failures |
You can review every delivery (status, attempts, response code, error) in the dashboard, and re-send a delivery manually.
Managing webhooks via the API
Existing webhooks can be inspected and managed programmatically (creation is done in the dashboard, where plan limits are enforced). Authenticate with X-API-Key.
# List your webhooks
curl -H "X-API-Key: YOUR_API_KEY" https://api.apitube.io/v1/webhooks
# Get one
curl -H "X-API-Key: YOUR_API_KEY" https://api.apitube.io/v1/webhooks/1
# Update url / filters / status (active | paused)
curl -X PATCH -H "X-API-Key: YOUR_API_KEY" -H "Content-Type: application/json" \
-d '{"status":"paused"}' https://api.apitube.io/v1/webhooks/1
# Delete
curl -X DELETE -H "X-API-Key: YOUR_API_KEY" https://api.apitube.io/v1/webhooks/1The required scopes are webhooks:read (for GET) and webhooks:write (for PATCH / DELETE).
Billing
Creating or managing a webhook is free. Each delivered article costs 1 point (charged to the key the webhook was created with). Deliveries made with a test key are masked and not billed.