Plans: Core and Plus, and the free trial. Who: owners and admins add webhook destinations.
The request
The body is compact JSON on one line, in UTF-8. The examples below are formatted for reading. Verify the signature against the raw bytes you receive, before you parse them.
The body
The body holds ids, titles, deadlines and links into Pharus. It never holds a reporter’s name, email address or report text, draft text, or who recorded a determination and why.
incident.opened
An exact match against CISA KEV or EUVD opened an incident.deadline.warning
A report is still open and due soon: 4 hours before a 24-hour or 72-hour report, 1 hour before DORA’s initial notification, 72 hours before a final report. One event per report.approval.requested
A determination was recorded and waits for four-eyes approval.report.received
A vulnerability report arrived in the disclosure inbox.test
Sent when an owner or admin selects Send a test on the destination. Pharus sends it whether the destination is on or off.data.destination is the destination’s name in Pharus.
Verify the signature
Check every request before you act on it:- Read the raw request body, before any JSON parsing.
- Split
Pharus-Signatureat the commas intotandv1. - Refuse the request if
tis more than 5 minutes from your clock. - Compute the HMAC-SHA256 of
t, a full stop and the raw body, with your signing secret as the key, and hex-encode it. - Compare it with
v1in constant time.
whsec_ prefix included, as UTF-8 text. Don’t decode it.
Delivery rules
Pharus sends nothing while the destination is turned off, when the workspace has no Core or Plus plan or trial, or while the workspace is read-only.
How to respond
- Answer with any
2xxstatus, for example204 No Content, within 5 seconds. Do the work after you answer. - Anything else counts as failed. Pharus records the status and the first 200 characters of your answer as the reason, for example
HTTP 401: invalid token, and shows it on the destination and under Delivery problems. Keep secrets out of error responses. - Without an answer, the reason is the connection error, for example “No answer within 5 s” or that the host “resolves to a private or reserved address”.
- Answer
2xxto event types you don’t handle, such astest. - Use
Pharus-Event-Idto log deliveries and to drop one you have already seen.