Notifications V5 (beta)
Read, change and test the webhook address of a bot.
A finished collection is announced to the webhook address. It applies to every collection, manual or by plan, and works even for accounts where multiple plans are not open.
Endpoints
-
GET
/v5/api/bots/{bot_id}/notificationsWebhook settings and the last delivery result -
PUT
/v5/api/bots/{bot_id}/notificationsSet or remove the webhook address -
POST
/v5/api/bots/{bot_id}/notifications/testSend a test delivery
Read
| Field | Description |
|---|---|
webhook_url, webhook_enabled | The webhook address and whether it is on. |
webhook_token_set | Whether a signing token exists. The token value is never returned. |
last_delivery | The last delivery { kind, status, http_status, at } (kind is real, test and so on; the body and signature are not returned), or null. |
curl 'https://www.hashscraper.com/v5/api/bots/8f3a7c1e9b5d24f6/notifications' \
-H 'Authorization: Bearer YOUR_API_KEY'{
"result": "success",
"version": "v5",
"request_id": "req_5a8c1f1c-9b2d-4e7c-9abf-3f7e0a4d1b21",
"elapsed_sec": 0.0123,
"data": {
"bot_id": "8f3a7c1e9b5d24f6",
"webhook_url": "https://example.com/hooks/hashscraper",
"webhook_enabled": true,
"webhook_token_set": true,
"last_delivery": {
"kind": "real",
"status": "success",
"http_status": 200,
"at": "2026-09-28T09:01:38+09:00"
}
}
}Set or remove the address
Send an http:// or https:// address (no spaces, 255 characters at most) in webhook_url to set it, or null to remove it. If the account has no webhook token yet, one is created the same way as on screen. Internal and private addresses cannot be used.
curl -X PUT 'https://www.hashscraper.com/v5/api/bots/8f3a7c1e9b5d24f6/notifications' \
-H 'Authorization: Bearer YOUR_API_KEY' \
-H "Idempotency-Key: $(uuidgen)" \
-H 'Content-Type: application/json' \
-d '{
"webhook_url": "https://example.com/hooks/hashscraper"
}'curl -X PUT 'https://www.hashscraper.com/v5/api/bots/8f3a7c1e9b5d24f6/notifications' \
-H 'Authorization: Bearer YOUR_API_KEY' \
-H "Idempotency-Key: $(uuidgen)" \
-H 'Content-Type: application/json' \
-d '{
"webhook_url": null
}'Test delivery
The same as "Send to check" on screen. Without an address it is 422 WEBHOOK_NOT_SET. Even if the receiver fails the test itself has completed, so you get 200 and the outcome in data.success (with the reason in error when no response arrived). An idempotency key is not required.
curl -X POST 'https://www.hashscraper.com/v5/api/bots/8f3a7c1e9b5d24f6/notifications/test' \
-H 'Authorization: Bearer YOUR_API_KEY' \
-H "Idempotency-Key: $(uuidgen)"{
"result": "success",
"version": "v5",
"request_id": "req_5a8c1f1c-9b2d-4e7c-9abf-3f7e0a4d1b21",
"elapsed_sec": 0.0123,
"data": {
"bot_id": "8f3a7c1e9b5d24f6",
"success": true,
"http_status": 200,
"timed_out": false,
"elapsed_ms": 184,
"error": null
}
}Fields added to the webhook body
The existing fields of the webhook body keep their names, values and order, and three fields were added after them. They are included by default in every webhook, manual or by plan.
trigger—manual,api,period,period_manualorexcel.plan—{ id, name, label, scheduled_at }when a plan started it, ornullwhen manual.inputs— the conditions used for that collection{ param1: { name, value } }(the same shape as the v5inputsdefinition).
The X-HashScraper-Version header stays 1.0, and the signature (X-Webhook-Signature) is computed over the body actually sent, so your verification still passes. A bot with several plans sends a webhook per plan, so tell them apart with plan.
plan.id in the webhook is a number, while a plan id in v5 API responses is a string ("512"). Convert when you compare.
{
"schedule_id": 4821,
"schedule_slug": "sample-shopping-bot",
"schedule_name": "Sample shopping bot",
"schedule_result_id": 239758028,
"data_count": 1280,
"completed_at": "2026-09-28T09:01:37.000+09:00",
"job_start_time": "2026-09-28T09:00:03.000+09:00",
"last_result_id": 90998721,
"status": "completed",
"trigger": "period",
"plan": {
"id": 512,
"name": "주기 2",
"label": "매주 월요일 09:00 (KST)",
"scheduled_at": "2026-09-28T09:00:00+09:00"
},
"inputs": {
"param1": {
"name": "Keyword",
"value": "sneakers"
}
},
"empty_reason": null
}