Skip to main content

Webhooks

PocketPing can POST every chat event to a URL you control — a new conversation, a visitor message, an operator reply, and more — so you can pipe them into a CRM, Slack/email automation, a data warehouse, or tools like Zapier / Make / n8n.

The payload is identical across every deployment mode (hosted SaaS and the self-hosted bridge-server), so you can move between them without touching your receiver.

Enabling it

Hosted (pocketping.io): open your project → Webhooks tab → set the endpoint URL, toggle it on, and copy the signing secret. Use Send test event to verify your receiver.

Self-hosted (bridge-server): set two env vars:

EVENTS_WEBHOOK_URL=https://example.com/webhooks/pocketping
EVENTS_WEBHOOK_SECRET=a-random-secret # optional but recommended

Request format

Every event is a single POST with a JSON envelope:

POST https://example.com/webhooks/pocketping
Content-Type: application/json
X-PocketPing-Event: visitor_message
X-PocketPing-Signature: sha256=<hex>

{
"type": "visitor_message",
"data": {
"sessionId": "…",
"visitorId": "…",
"message": { "id": "…", "content": "Hi, I need help" }
},
"sentAt": "2026-06-02T12:00:00.000Z"
}

Delivery is fire-and-forget with a 10s timeout — it never blocks a visitor or operator. Respond with any 2xx to acknowledge.

Events

typeWhen
new_sessionA visitor starts a new conversation
visitor_messageA visitor sends a message
operator_messageAn operator replies (from any bridge)
visitor_message_edited / visitor_message_deletedA visitor edits or deletes a message
message_readMessages are marked read
identity_updateA visitor is identified via PocketPing.identify()
visitor_disconnectA visitor leaves the page
csat_submittedA visitor submits a satisfaction rating — data: { sessionId, score, comment, respondedAt }
custom_eventA PocketPing.trigger(name, data) custom event (bridge-server only)
testSent by the dashboard's Send test event button

Most events fire across the hosted SaaS, the self-hosted bridge-server, and the self-host SDK. The exceptions: custom_event is forwarded only by the bridge-server (the SaaS doesn't ingest custom events server-side). csat_submitted fires on all three — though on the standalone bridge-server it is relayed (the backend posts a csat_submitted event to /api/events); command-based !csat triggering there is a tracked follow-up.

Verifying the signature

When a secret is configured, the body is signed with HMAC-SHA256 and sent in X-PocketPing-Signature: sha256=<hex>. Verify it against the raw request body before trusting an event:

import crypto from 'crypto'

function verify(rawBody, header, secret) {
const expected = 'sha256=' + crypto.createHmac('sha256', secret).update(rawBody).digest('hex')
return crypto.timingSafeEqual(Buffer.from(header), Buffer.from(expected))
}
import hmac, hashlib

def verify(raw_body: bytes, header: str, secret: str) -> bool:
expected = "sha256=" + hmac.new(secret.encode(), raw_body, hashlib.sha256).hexdigest()
return hmac.compare_digest(header, expected)
tip

Compute the HMAC over the exact bytes you received — parsing and re-serializing the JSON first will change whitespace and break the signature.