The Webhook integration sends a request to your own web address every time something happens to a ticket — a ticket is created, closed, reopened, assigned, escalated, rated, and more. Your system receives the event and can do whatever you like with it: log it, sync it to a CRM, post it somewhere, or kick off an automation.
You need somewhere to receive the events — a URL your team controls. Everything on the Clarify side is point-and-click, and it costs no feature token.
How it works
When a selected event happens, Clarify sends an HTTPS POST to your URL with the event and the ticket in the body. Every request is signed with your secret, so your server can confirm it came from Clarify and was not altered on the way. Clarify tries up to three times (10 seconds each, with a short pause between attempts) before giving up on a delivery.
Requests are sent through Clarify's delivery relay, so do not filter by IP address — verify the signature instead.
Destination
https:// — plain http:// is not accepted.Events
- Ticket created — A new ticket has been opened.
- Ticket reopened — A closed ticket was opened again.
- Ticket closed — A ticket was marked as resolved.
- Agent assigned — An agent was assigned to a ticket.
- Agent unassigned — An agent was removed from a ticket.
- Member added — Someone was added to a ticket.
- Member removed — Someone was removed from a ticket.
- Ticket rated — The customer left a rating.
- Ticket escalated — A ticket was moved to another support tier.
The X-Clarify-Event header and event.type in the body carry the event name: created, opened, closed, assigned, unassigned, added, removed, rated, escalated.
Custom headers
Authorization: Bearer … header your endpoint expects. Optional. Your headers are added after Clarify's own, so a header with the same name overrides it.What a request looks like
POST /hooks/clarify HTTP/1.1
Content-Type: application/json
X-Clarify-Event: closed
X-Clarify-Timestamp: 1758000000
X-Clarify-Signature: sha256=3f7a…
{
"event": {
"type": "closed",
"timestamp": 1758000000000,
"serverId": "123456789012345678",
"ticketId": "…",
"executor": { "id": "…", "username": "alex", "avatarUrl": "…" }
},
"ticket": { "…": "the full ticket record — participants, messages, inputs, assignees, routing" },
"review": null
}
event.timestampis in milliseconds; theX-Clarify-Timestampheader is in seconds.ticketis the complete ticket as Clarify stores it, including its messages and the answers to its inputs. Treat your endpoint as confidential as the tickets themselves.reviewholds the customer's rating and comment once the ticket has been rated, on every later event too; before that it isnull.
Verifying the signature
Clarify signs "<X-Clarify-Timestamp>.<raw request body>" with HMAC-SHA256 using your secret and sends the hex digest as X-Clarify-Signature: sha256=…. Recreate it and compare:
import { createHmac, timingSafeEqual } from 'node:crypto'
function verify(rawBody, headers, secret) {
const expected = 'sha256=' + createHmac('sha256', secret)
.update(`${headers['x-clarify-timestamp']}.${rawBody}`)
.digest('hex')
const given = headers['x-clarify-signature'] ?? ''
return given.length === expected.length && timingSafeEqual(Buffer.from(given), Buffer.from(expected))
}
Use the raw body bytes, not a re-serialised object. Reject requests whose timestamp is far from now if you want protection against replays.
Turning it on and testing
Set it Active
Use the Active / Inactive toggle on the Webhook page. While inactive, Clarify keeps your settings and sends nothing — handy for pausing during maintenance.
Send a test
Send test fires a sample request at your URL right away — a small fake ticket with the first event you selected — and shows the HTTP status and how long it took. The page also remembers the outcome of the last real delivery so you can see whether events are getting through.
2xx status or a timeout means your endpoint did not accept the request. Check that the URL is public, that any required custom headers are set, and that your verification uses the exact secret you saved. See Troubleshooting if it persists.Related
Opening hours
Tell members when your team is around — per ticket category — and decide whether a ticket opened outside those hours is created with a notice, blocked, or opened after a warning.
Assignment
Let supporters claim tickets or assign each other, distribute new tickets automatically per category, and show who owns a ticket right in Discord.