Skip to main content
Plans: Core and Plus, and the free trial. Who: owners and admins add webhook destinations.
A webhook destination gets one HTTPS POST per event, with a JSON body and an HMAC-SHA256 signature made with the destination’s signing secret. To add a destination and choose its events, see Notifications.

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:
  1. Read the raw request body, before any JSON parsing.
  2. Split Pharus-Signature at the commas into t and v1.
  3. Refuse the request if t is more than 5 minutes from your clock.
  4. Compute the HMAC-SHA256 of t, a full stop and the raw body, with your signing secret as the key, and hex-encode it.
  5. Compare it with v1 in constant time.
The key is the whole signing secret as Pharus showed it, whsec_ prefix included, as UTF-8 text. Don’t decode it.
To try your endpoint before Pharus can reach it, sign a request yourself:
New signing secret under Settings → Notifications replaces the secret at once; the old one stops working with no overlap. Put the new secret in your endpoint straight away, or the deliveries in between fail verification.

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 2xx status, for example 204 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 2xx to event types you don’t handle, such as test.
  • Use Pharus-Event-Id to log deliveries and to drop one you have already seen.
Because nothing is retried, treat a webhook as a prompt, not the record. The incident, the decision record and the disclosure inbox in Pharus stay the source of truth.

Notifications

API introduction

Paging

Disclosure inbox