Webhooks
Receive real-time HTTP callbacks for push events — message.sent, delivered, failed, no_recipients, device.registered/updated/unregistered. HMAC signature verification, retry policy.
Receive real-time HTTP callbacks when events occur.
Available Events#
message.sentA send request was accepted for delivery (fired once per message, with success/failed counts)
message.deliveredA device confirmed receipt (fired once per device)
message.failedThe send failed (fired once per message)
message.no_recipientsNo device matched the target — message not attempted
device.registeredNew device registered
device.updatedExisting device re-registered or re-activated
device.unregisteredDevice unregistered or deactivated
Create a Webhook#
Node.js SDK
import { AbrovaPush } from '@abrova/push-node';
const abrovaPush = new AbrovaPush({
apiKey: 'ab_live_your_api_key',
serverSecret: 'ab_srv_your_server_secret',
});
const webhook = await abrovaPush.webhooks.create({
name: 'Analytics Webhook',
url: 'https://your-server.com/webhooks/abrova-push',
events: ['message.sent', 'message.delivered', 'message.failed'],
});
console.log('Webhook secret:', webhook.secret);REST API
curl -X POST "https://push-api.abrova.ir/webhooks" \
-H "x-api-key: ab_live_your_api_key" \
-H "x-server-secret: ab_srv_your_server_secret" \
-H "Content-Type: application/json" \
-d '{
"name": "Analytics Webhook",
"url": "https://your-server.com/webhooks/abrova-push",
"events": ["message.sent", "message.delivered", "message.failed"]
}'Response
{
"id": "wh_abc123",
"name": "Analytics Webhook",
"url": "https://your-server.com/webhooks/abrova-push",
"events": ["message.sent", "message.delivered", "message.failed"],
"secret": "whsec_xyz789...",
"isActive": true,
"maxRetries": 3,
"timeoutMs": 5000,
"createdAt": "2024-01-15T10:00:00Z"
}Save the secret value — you'll need it to verify webhook signatures. If you don't pass your own secret, one is generated (whsec_...). You can rotate it with POST /webhooks/:id/regenerate-secret (abrovaPush.webhooks.regenerateSecret(id)).
Webhook Payload#
When an event occurs, we send a POST request to your URL with the headers X-AbrovaPush-Signature, X-AbrovaPush-Event and X-AbrovaPush-Webhook-Id, and this payload:
{
"event": "message.sent",
"timestamp": "2024-01-15T10:30:00Z",
"webhookId": "wh_abc123",
"data": {
"messageId": "msg_xyz789",
"type": "user",
"target": "user_456",
"title": "Hello!",
"body": "Test message",
"successCount": 2,
"failedCount": 0,
"status": "sent"
}
}The data object depends on the event:
message.sent/message.failed/message.no_recipients—messageId,type,target,title,body,successCount,failedCount,statusmessage.delivered—messageId,deviceId,titledevice.registered/device.updated—deviceId,platform,userId,appIdentifier,isActive(or justdeviceId,isActivewhen a device is re-activated)device.unregistered—deviceId(plusisActive: falsewhen deactivated)
Verify Webhook Signature#
Always verify the X-AbrovaPush-Signature header to ensure the webhook came from AbrovaPush.
const crypto = require('crypto');
function verifyWebhook(payload, signature, secret) {
const expected = crypto
.createHmac('sha256', secret)
.update(payload)
.digest('hex');
return crypto.timingSafeEqual(
Buffer.from(signature),
Buffer.from(expected)
);
}
// Express.js example
app.post('/webhooks/abrova-push', express.raw({ type: 'application/json' }), (req, res) => {
const signature = req.headers['x-abrovapush-signature'];
const payload = req.body.toString();
if (!verifyWebhook(payload, signature, process.env.WEBHOOK_SECRET)) {
return res.status(401).send('Invalid signature');
}
const event = JSON.parse(payload);
switch (event.event) {
case 'message.sent':
// Record send event
break;
case 'message.delivered':
// Record delivery
break;
case 'message.failed':
// Handle failure
break;
case 'message.no_recipients':
// Target had no registered device — mark the user as push-unreachable,
// fall back to email/SMS, etc. Not a delivery failure.
break;
}
res.status(200).send('OK');
});Retry Policy#
If your endpoint returns a non-2xx status code or times out (default timeout 5 seconds, configurable with timeoutMs from 1000 to 30000), we'll retry with exponential backoff. With the default maxRetries of 3:
- Attempt 1: Immediate
- Attempt 2: After 1 second
- Attempt 3: After 2 seconds
- Attempt 4: After 4 seconds
After 4 failed attempts, the webhook delivery is marked as failed. Set maxRetries (1–10) when creating or updating the webhook to change the number of retries. Every attempt is logged — fetch the log with GET /webhooks/:id/logs?limit=50 (max 100) or abrovaPush.webhooks.getLogs(id).
List Webhooks#
Node.js SDK
const webhooks = await abrovaPush.webhooks.list();
REST API
curl -X GET "https://push-api.abrova.ir/webhooks" \ -H "x-api-key: ab_live_your_api_key" \ -H "x-server-secret: ab_srv_your_server_secret"
Update Webhook#
Node.js SDK
await abrovaPush.webhooks.update('wh_abc123', {
name: 'Updated Webhook',
events: ['message.sent', 'device.registered'],
isActive: true,
});REST API
curl -X PUT "https://push-api.abrova.ir/webhooks/wh_abc123" \
-H "x-api-key: ab_live_your_api_key" \
-H "x-server-secret: ab_srv_your_server_secret" \
-H "Content-Type: application/json" \
-d '{
"name": "Updated Webhook",
"events": ["message.sent", "device.registered"],
"isActive": true
}'Delete Webhook#
Node.js SDK
await abrovaPush.webhooks.delete('wh_abc123');REST API
curl -X DELETE "https://push-api.abrova.ir/webhooks/wh_abc123" \ -H "x-api-key: ab_live_your_api_key" \ -H "x-server-secret: ab_srv_your_server_secret"
Test Webhook#
Send a test event to verify your webhook is configured correctly. The test delivery uses the message.sent event unless you pass another one ({ "event": "device.registered" } in the body, or abrovaPush.webhooks.test(id, 'device.registered')), and its data is { "test": true, "timestamp": "...", "message": "This is a test webhook delivery" }. The response is the delivery log entry (success, responseStatus, error, durationMs, ...).
Node.js SDK
const result = await abrovaPush.webhooks.test('wh_abc123');REST API
curl -X POST "https://push-api.abrova.ir/webhooks/wh_abc123/test" \ -H "x-api-key: ab_live_your_api_key" \ -H "x-server-secret: ab_srv_your_server_secret"