Webhooks
Webhooks allow you to receive real-time HTTP POST notifications when events occur in your Ping account — tickets created, updated, resolved, or chat sessions starting and ending.
All webhook endpoints require an API key with the tickets permission. Pass your key in the X-Ping-Api-Key header.
Register a webhook
Register a URL to receive webhook events. You can register up to 10 webhooks per business.
Request body
- Name
url- Type
- string
- Description
The HTTPS URL to receive webhook POST requests (required).
- Name
events- Type
- array
- Description
List of event types to subscribe to (required).
The response includes a secret field — save this immediately. It is only shown once and is used for signature verification.
Request
curl -X POST https://api.ping.co.zw/v1/api/webhooks \
-H "X-Ping-Api-Key: pk_live_xxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{
"url": "https://your-app.com/webhooks/ping",
"events": ["ticket.created", "ticket.resolved", "comment.added"]
}'
Response
{
"result": "success",
"message": "Webhook registered. Save the secret — it will not be shown again.",
"webhook": {
"id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"url": "https://your-app.com/webhooks/ping",
"events": ["ticket.created", "ticket.resolved", "comment.added"],
"isActive": true,
"failureCount": 0,
"lastTriggeredAt": null,
"dateCreated": "2026-05-04T08:00:00",
"secret": "whsec_a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4"
}
}
List webhooks
List all registered webhooks for your business.
Request
curl "https://api.ping.co.zw/v1/api/webhooks" \
-H "X-Ping-Api-Key: pk_live_xxxxxxxxxxxx"
Response
{
"result": "success",
"webhooks": [
{
"id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"url": "https://your-app.com/webhooks/ping",
"events": ["ticket.created", "ticket.resolved", "comment.added"],
"isActive": true,
"failureCount": 0,
"lastTriggeredAt": "2026-05-04T09:30:00",
"dateCreated": "2026-05-04T08:00:00"
}
]
}
Delete a webhook
Remove a webhook registration by its ID.
Request
curl -X DELETE "https://api.ping.co.zw/v1/api/webhooks/a1b2c3d4-e5f6-7890-abcd-ef1234567890" \
-H "X-Ping-Api-Key: pk_live_xxxxxxxxxxxx"
Response
{
"result": "success",
"message": "Webhook deleted"
}
Webhook events
Subscribe to any combination of the following event types:
Ticket events
- Name
ticket.created- Description
A new ticket was created (via API, portal, email, or live chat).
- Name
ticket.updated- Description
A ticket was updated (status, priority, fields, etc.).
- Name
ticket.resolved- Description
A ticket status was set to "resolved".
- Name
ticket.assigned- Description
A ticket was assigned or reassigned to an agent.
Comment events
- Name
comment.added- Description
A new comment was added to a ticket.
Chat events
- Name
chat.started- Description
A new live chat session was initiated by a visitor.
- Name
chat.ended- Description
A live chat session was closed.
Subscribe to all events:
{
"url": "https://your-app.com/webhook",
"events": [
"ticket.created",
"ticket.updated",
"ticket.resolved",
"ticket.assigned",
"comment.added",
"chat.started",
"chat.ended"
]
}
Webhook payload
All webhook deliveries are HTTP POST requests with a JSON body containing:
- Name
event- Type
- string
- Description
The event type (e.g.,
ticket.created).
- Name
timestamp- Type
- string
- Description
ISO 8601 timestamp of when the event occurred.
- Name
data- Type
- object
- Description
Event-specific payload data.
Headers sent with each delivery
- Name
X-Ping-Signature- Type
- string
- Description
HMAC-SHA256 signature of the request body.
- Name
X-Ping-Event- Type
- string
- Description
Event type (same as
eventfield in body).
- Name
X-Ping-Delivery- Type
- string
- Description
Unique delivery ID for idempotency.
- Name
Content-Type- Type
- string
- Description
Always
application/json.
Example: ticket.created
{
"event": "ticket.created",
"timestamp": "2026-05-04T08:00:00Z",
"data": {
"ticketNumber": "TKT-2026-00042",
"publicId": "TKT-A1B2C3D4",
"subject": "Cannot connect to Starlink",
"status": "open",
"priority": "high",
"category": "technical",
"channel": "api",
"customerFirstName": "Tendai",
"customerLastName": "Moyo",
"customerEmail": "[email protected]",
"dateCreated": "2026-05-04T08:00:00"
}
}
Example: comment.added
{
"event": "comment.added",
"timestamp": "2026-05-04T09:35:00Z",
"data": {
"ticketNumber": "TKT-2026-00042",
"comment": {
"publicId": "a1b2c3d4-...",
"authorType": "admin",
"content": "Issue resolved after adapter replacement.",
"isInternal": false,
"dateCreated": "2026-05-04T09:35:00"
}
}
}
Signature verification
Every webhook delivery includes an X-Ping-Signature header containing an HMAC-SHA256 signature of the request body, signed with your webhook secret.
Verification steps
- Get the raw request body (before JSON parsing)
- Compute HMAC-SHA256 of the body using your webhook secret
- Compare the computed signature with the
X-Ping-Signatureheader - Reject the request if signatures don't match
Python
import hmac
import hashlib
def verify_ping_webhook(payload_body: str, signature: str, secret: str) -> bool:
"""Verify that a webhook request came from Ping."""
expected = hmac.HMAC(
secret.encode("utf-8"),
payload_body.encode("utf-8"),
hashlib.sha256,
).hexdigest()
return hmac.compare_digest(signature, expected)
# In your webhook handler:
signature = request.headers.get("X-Ping-Signature")
secret = "whsec_your_webhook_secret"
if not verify_ping_webhook(request.body, signature, secret):
return Response(status=401)
Node.js
const crypto = require('crypto')
function verifyPingWebhook(body, signature, secret) {
const expected = crypto
.createHmac('sha256', secret)
.update(body)
.digest('hex')
return crypto.timingSafeEqual(
Buffer.from(signature),
Buffer.from(expected)
)
}
// In your Express handler:
app.post('/webhooks/ping', (req, res) => {
const signature = req.headers['x-ping-signature']
const secret = 'whsec_your_webhook_secret'
if (!verifyPingWebhook(req.rawBody, signature, secret)) {
return res.status(401).send('Invalid signature')
}
// Process event...
res.status(200).send('OK')
})
Retry behavior
If your endpoint returns a non-2xx status code or doesn't respond within 10 seconds, Ping will retry the delivery:
| Attempt | Delay |
|---|---|
| 1st retry | 5 seconds |
| 2nd retry | 25 seconds |
| 3rd retry | 125 seconds |
After 3 failed attempts, the delivery is marked as failed. After 10 consecutive failures across any deliveries, the webhook is automatically disabled.
Best practices
- Return
200 OKquickly (process events asynchronously) - Use the
X-Ping-Deliveryheader for idempotency - Monitor your webhook's
failureCountvia the list endpoint - Re-register webhooks if they become disabled
Endpoint requirements:
- Must accept HTTP POST
- Must return 2xx status code
- Must respond within 10 seconds
- Must use HTTPS
- Should verify the
X-Ping-Signature
