NiroHelp fires a canonical event for every meaningful thing that happens to a ticket — created, replied to, assigned, overdue, resolved, and more. A webhook sends that event as a signed HTTPS request to a URL of your own, so you can wire NiroHelp into Make, n8n, a serverless function, or anything else that takes a POST.
Where the screen is
NiroHelp → Integrations → Webhooks. Like the rest of Integrations, it needs the manage_options capability, so only administrators see it.
Adding an endpoint
- Go to NiroHelp → Integrations → Webhooks.
- Click Add endpoint.
- Fill in:
- Endpoint URL — where the request goes. See URL rules below.
- Description — a note for yourself; shown in the endpoint list.
- Include message bodies — off by default. On sends the full text of replies and notes; off sends a short excerpt only.
- Events — which events this endpoint receives. Pick All public events, specific events, or both.
- Click Add endpoint.
The endpoint is created active, and its signing secret is shown once — see below.
URL rules
- Must be
https://— plain HTTP is refused, unless the site hasWP_DEBUGon. - Can’t resolve to this server or a private network address. NiroHelp checks this the same way WordPress does for any outgoing request, so a URL that can’t be reached safely is rejected before it’s ever saved.
Choosing events
All public events is a subscription, not a shortcut — it’s stored as * and keeps covering new events added in later releases, which ticking every current checkbox individually would not.
It deliberately stops at public events. A private event carries agent-only content — today that’s only Private note added — and it is never included in “All public events.” If you want it, choose it by name as well.
A handful of events are listed as Not emitted yet. Their names are published so you can build against them now, but nothing fires them yet — see the table below.
Events you can subscribe to
| Event | Fires when |
|---|---|
ticket.created | A ticket was submitted, created in wp-admin, or imported. |
ticket.updated | Urgency, product, reason, order or a custom field changed. At most one per ticket per request. |
ticket.replied | The customer, an agent or the AI replied. |
ticket.customer_replied | The customer specifically replied. The same reply also fires ticket.replied. |
ticket.note_added | Private. An agent-only note was added. |
ticket.assigned | A ticket was assigned, reassigned or unassigned. |
ticket.status_changed | A ticket moved from one status to another. |
ticket.resolved | A ticket was marked resolved. The same change also fires ticket.status_changed. |
ticket.overdue | A ticket has waited on an agent longer than Overdue after, under Settings → Tickets → Behaviour. |
ticket.sentiment_negative | A ticket’s sentiment turned negative. Fired on the change, not on every re-read. |
customer.created | A customer account was created. |
ai.answered | The AI auto responder replied to a ticket. |
ai.escalated | The AI held an answer back, or couldn’t answer — a person is needed. |
ticket.reopened | Not emitted yet. A customer replied to a finished ticket and it reopened. |
sla.breached | Not emitted yet. A ticket missed an SLA target. |
The signing secret
Every endpoint gets its own secret, prefixed whsec_. It’s shown exactly once — right after you add the endpoint, or right after you rotate it — in a Copy your signing secret dialog. Close that dialog and it’s gone; the endpoint list only ever shows a hint of it afterwards.
Every delivery carries an X-NiroHelp-Signature header:
X-NiroHelp-Signature: t=<unix timestamp>,v1=<hex>
v1 is an HMAC-SHA256 of "{t}.{body}", computed with your endpoint’s secret. To verify a request came from your site, recompute that HMAC on the raw request body and compare it to v1:
function verify_signature( $header, $body, $secret ) {
$parts = [];
foreach ( explode( ',', $header ) as $pair ) {
[ $key, $value ] = explode( '=', $pair, 2 );
$parts[ $key ] = $value;
}
$expected = hash_hmac( 'sha256', $parts['t'] . '.' . $body, $secret );
return hash_equals( $expected, $parts['v1'] );
}
Rotating a secret retires the old one immediately — update anywhere it’s stored before you rotate, or that receiver starts failing signature checks until it’s updated.
Managing endpoints
Each row offers:
- Send test — posts a sample event right now and shows what the receiver answered. This is the one thing on the screen that waits for a response; everything else is queued.
- Edit — change the URL, description, body setting or events.
- Disable / Enable — stop or resume deliveries without deleting the endpoint. A disabled endpoint keeps its secret and its event list.
- Rotate secret — issues a new secret and shows it once, the same as creation. Confirmed first.
- Delete — removes the endpoint and its delivery log. Confirmed first.
- Deliveries — opens the delivery log for that endpoint.
Delivery, retries and the circuit breaker
Sending a webhook never blocks a ticket being saved — every delivery is queued. A failed attempt retries up to 5 times, on a backoff of roughly 1 minute, 5 minutes, 30 minutes, 2 hours, then 12 hours.
5 consecutive failures disable the endpoint automatically. Rather than retrying a dead URL forever, NiroHelp switches it off and flags it in wp-admin so an administrator notices and fixes it — a URL that changed, a certificate that expired, a firewall that started blocking the request. Re-enable it from the endpoint row once it’s fixed.
The delivery log
Each endpoint’s Deliveries view lists every attempt: When, Event, Attempt, Result, Response, Duration, and a Redeliver action to retry a specific one on demand.
How long attempts are kept is a Settings field on the same screen — Keep the delivery log for, in days. Default 14, from 1 to 90. Older attempts, and the payloads they could be redelivered from, are deleted daily.
The payload
Every event is a JSON body: an id, the event name, a schema version, when it happened, who or what caused it, and the ticket or comment it concerns. A payload is capped at 64KB — past that, the comment body is trimmed first, then other fields, and truncated is set so a receiver can tell.
Troubleshooting
- Nothing arrives. Check the endpoint is Active, not disabled by the circuit breaker. Use Send test first — it reports the receiver’s answer immediately, instead of waiting on the delivery log.
- “Enter a full URL, starting with https://.” — the URL isn’t valid, or isn’t HTTPS. See URL rules above.
- “That address could not be resolved, or it points at this server or a private network.” — NiroHelp refuses to send webhooks to itself or to a private/internal address, the same way WordPress refuses it for any outgoing request.
- Signature never matches. Recompute the HMAC over the raw request body, before any JSON re-encoding — re-serializing the body can change whitespace and break the comparison.
Was this doc helpful?