Real-Time Delivery Events, Pushed to You
When you send a notification through the One-Ping REST API, the initial response tells you the message was accepted and queued. But what happens next? Did the Telegram message actually reach the user? Did the email bounce? Did the Slack webhook return an error?
One-Ping webhooks answer these questions in real time. Instead of polling the API or checking the dashboard manually, you register a callback URL and we push delivery events to your server as they happen. Your application stays in sync with the actual delivery status of every notification you send, across every channel.
This is essential for building reliable notification workflows where you need to know whether a message was delivered -- not just that it was sent. Update your database, notify your team, trigger follow-up actions, or escalate to an alternative channel, all automatically based on webhook events.
Available on Pro and Business plans. Webhooks are included with Pro ($9/mo) and Business ($29/mo) plans. Free tier users can monitor delivery status through the dashboard.
How Webhooks Work
The webhook flow is straightforward. When you send a notification, One-Ping processes it and dispatches to the requested channels. As each channel confirms delivery (or reports a failure), One-Ping sends an HTTP POST request to your registered callback URL with the event details.
Register your webhook URL
In your dashboard settings, add a webhook endpoint URL (e.g., https://yourapp.com/webhooks/one-ping). You can also pass a callback_url parameter on each API call to override the default.
Send notifications as usual
Use the POST /send endpoint to send your notifications. No changes to your existing integration are needed -- webhooks work alongside your current setup.
Receive delivery events
One-Ping sends HTTP POST requests to your webhook URL for each delivery event: success, failure, retry, and bounce. Each event includes the notification ID, channel, status, and timestamp.
Respond with 200 OK
Your endpoint should return a 200 status code to acknowledge receipt. If we do not receive a 200, we will retry the webhook delivery (see retry logic below).
Webhook Event Types
One-Ping sends different webhook events depending on what happens with your notification. Each event type is identified by the event field in the payload.
| Event | Description | When It Fires |
|---|---|---|
notification.delivered |
Notification was successfully delivered to the channel | Channel confirms receipt |
notification.failed |
Notification failed to deliver after all retry attempts | All retries exhausted |
notification.retrying |
A delivery attempt failed and a retry has been scheduled | Before each retry attempt |
notification.bounced |
Email notification bounced (invalid address or inbox full) | Email provider reports bounce |
notification.fallback |
Primary channel failed, message sent to a fallback channel | Fallback channel is triggered |
Webhook Payload Format
Every webhook event is delivered as an HTTP POST request with a JSON body. Here is the full payload structure with an example for a successful delivery.
Delivery Success Event
// POST to your webhook URL { "event": "notification.delivered", "notification_id": "msg_a1b2c3d4e5", "channel": "telegram", "status": "delivered", "recipient": "@username", "delivered_at": "2025-01-15T10:30:05Z", "latency_ms": 245, "attempt": 1, "metadata": { "order_id": "ORD-5678" }, "timestamp": "2025-01-15T10:30:05Z" }
Delivery Failure Event
{
"event": "notification.failed",
"notification_id": "msg_a1b2c3d4e5",
"channel": "email",
"status": "failed",
"recipient": "[email protected]",
"error": {
"code": "RECIPIENT_REJECTED",
"message": "Mailbox not found"
},
"attempts": 3,
"first_attempt_at": "2025-01-15T10:30:00Z",
"last_attempt_at": "2025-01-15T10:35:00Z",
"metadata": {},
"timestamp": "2025-01-15T10:35:01Z"
}
Retry Event
{
"event": "notification.retrying",
"notification_id": "msg_a1b2c3d4e5",
"channel": "slack",
"status": "retrying",
"attempt": 2,
"max_attempts": 3,
"next_retry_at": "2025-01-15T10:32:00Z",
"error": {
"code": "TIMEOUT",
"message": "Channel did not respond within 10 seconds"
},
"timestamp": "2025-01-15T10:31:00Z"
}
Security: Signature Verification
Every webhook request from One-Ping includes a cryptographic signature so you can verify that the request genuinely came from us and was not tampered with in transit. You should always verify webhook signatures in production to prevent spoofed events from affecting your application.
How Signature Verification Works
One-Ping signs each webhook payload using HMAC-SHA256 with your webhook secret key. The signature is included in the X-OnePing-Signature header. To verify the signature, compute the HMAC-SHA256 hash of the raw request body using your secret and compare it with the header value.
// Webhook headers sent by One-Ping
X-OnePing-Signature: sha256=a1b2c3d4e5f6...
X-OnePing-Timestamp: 1705312200
Content-Type: application/json
Verification Example (Node.js)
const crypto = require('crypto'); function verifyWebhook(req, secret) { const signature = req.headers['x-oneping-signature']; const timestamp = req.headers['x-oneping-timestamp']; // Reject requests older than 5 minutes to prevent replay attacks const age = Math.abs(Date.now() / 1000 - parseInt(timestamp)); if (age > 300) return false; const expected = 'sha256=' + crypto .createHmac('sha256', secret) .update(timestamp + '.' + JSON.stringify(req.body)) .digest('hex'); return crypto.timingSafeEqual( Buffer.from(signature), Buffer.from(expected) ); }
Verification Example (Python)
import hmac import hashlib import time import json def verify_webhook(headers, body, secret): signature = headers.get('X-OnePing-Signature') timestamp = headers.get('X-OnePing-Timestamp') # Reject requests older than 5 minutes if abs(time.time() - int(timestamp)) > 300: return False payload = f"{timestamp}.{json.dumps(body)}" expected = 'sha256=' + hmac.new( secret.encode(), payload.encode(), hashlib.sha256 ).hexdigest() return hmac.compare_digest(signature, expected)
Security tip: Always use timing-safe comparison functions when verifying signatures. Standard string comparison (=== or ==) can leak information through timing differences, making your endpoint vulnerable to timing attacks.
Use Cases for Webhooks
Webhooks unlock powerful automation capabilities on top of your notification workflow. Here are the most common patterns our users build with webhook callbacks.
Update Your Database
When a notification is delivered, update the corresponding record in your database. Mark an order as "customer notified" or log the delivery timestamp for compliance and audit trails.
Trigger Follow-Up Actions
Chain notifications together. When a Telegram message is delivered, trigger a follow-up email with additional details. Build multi-step notification sequences.
Escalate on Failure
If a notification fails on all channels, alert your support team via Slack or create an incident in your issue tracker. Never let a critical notification silently disappear.
Analytics and Reporting
Feed webhook events into your own analytics pipeline to build custom dashboards, calculate delivery SLAs, and generate reports beyond what the One-Ping dashboard provides.
Sync with CRM
Update customer records in your CRM when notifications are delivered. Track which customers have been reached and through which channels for better customer communication history.
Billing and Metering
Use delivery confirmation events to track your actual notification usage for internal billing, cost allocation, or usage reporting across different teams or projects.
Webhook Delivery Retry Logic
We understand that your server might not always be available to receive webhooks. If your endpoint does not respond with a 200 status code, One-Ping retries the webhook delivery using exponential backoff.
| Attempt | Delay After Failure | Total Time Elapsed |
|---|---|---|
| 1st retry | 30 seconds | 30 seconds |
| 2nd retry | 2 minutes | 2.5 minutes |
| 3rd retry | 10 minutes | 12.5 minutes |
| 4th retry | 30 minutes | 42.5 minutes |
| 5th retry (final) | 1 hour | ~1 hour 42 minutes |
After 5 failed attempts, the webhook event is marked as failed and logged in your dashboard. You can manually re-trigger any failed webhook from the dashboard if needed.
Testing webhooks locally? Use a tunneling tool like ngrok or localtunnel to expose your local development server to the internet. This lets you receive real webhook events while developing and testing your handler.
Best Practices
- Respond quickly: Return a 200 status code as soon as possible. Process the webhook event asynchronously (queue it) rather than doing heavy work in the handler.
- Handle duplicates: In rare cases, a webhook event might be delivered more than once. Use the
notification_idandeventfields to detect and ignore duplicate events. - Always verify signatures: Check the
X-OnePing-Signatureheader on every request. Never trust unverified webhook payloads. - Log everything: Store incoming webhook events for debugging and auditing. If something goes wrong, your logs will help you trace the issue.
- Use HTTPS: Your webhook endpoint should always use HTTPS to encrypt the webhook payload in transit. One-Ping will not deliver webhooks to plain HTTP URLs in production.
- Set up monitoring: Monitor your webhook handler for errors and latency. If your handler starts failing, you will miss delivery events until the retries succeed.