Skip to main content

Webhooks

Webhooks let Palisade notify your own systems the moment something changes, instead of you asking repeatedly whether anything has. Register an HTTPS URL, and Palisade sends it a small JSON message every time a domain is added, removed, or changes state.

If your ticketing system is Autotask, ConnectWise, or HaloPSA, you probably want a PSA integration instead -- those are purpose-built and require no code. Webhooks are the path when your tooling is something else: an internal dashboard, a Slack workflow, a custom portal, or an automation platform like Zapier or Make.

What you can subscribe to

EventFires when
domain.createdA domain is added to your organization
domain.updatedA domain changes -- monitoring state, score, or configuration
domain.deletedA domain is removed
domain.monitoring.activatedA domain reaches full DMARC monitoring for the first time
domain.monitoring.failedMonitoring could not be established, or was lost
domain.monitoring.driftedA working domain stops resolving the expected records
domain.monitoring.recoveredA drifted or failed domain is working again
domain.hosted_record.ready / .errorA Palisade-hosted record went live, or broke
domain.score_changedA domain crossed a score band
domain.policy_changedThe DMARC policy changed, for example none to quarantine
mta_sts.enabled / .updated / .disabledHosted MTA-STS changes for a domain
task.opened / .completed / .canceled / .dismissed / .reopenedA remediation task changes state
organization.updated, member.*, invitation.*, group.*Team and account changes

If you only subscribe to one thing, make it domain.monitoring.drifted — a domain that silently stops authenticating is the failure that costs you. domain.monitoring.activated and .recovered are the good-news counterparts, and domain.updated still fires for every change if you would rather do your own diffing.

The live list is always available from the API at GET /webhook-events.

What is in a message

data.object is the affected resource, as it was at the moment of the event. Events that describe a change also carry data.previous_attributes with the old values, so you do not have to keep your own copy of every domain to know what moved — domain.score_changed, for instance, tells you the band you came from. Hosted-record events add data.record, naming which of dmarc, spf, dkim, bimi, or mta_sts moved.

Setting one up

  1. Create an endpoint with POST /webhook-endpoints, passing the URL you want events sent to.
  2. Save the signing secret from the response. It is shown once and never again. If you lose it, rotate to get a new one.
  3. Verify the signature on each incoming request before trusting it.

Full request and response details, plus verification code in Node and Python, are in the API guide.

caution

Anyone who knows your endpoint URL can send it a request. The signature is what proves a message actually came from Palisade -- always verify it, and never act on an unverified payload.

What to expect in practice

The same event can arrive twice. Palisade retries failed deliveries, and a retry can land after the original eventually succeeded. Every message carries an id that stays the same across retries, so record which ids you have processed and ignore repeats.

Events can arrive out of order. If a delivery is retried, an older event may show up after a newer one. Use the timestamps in the payload rather than assuming arrival order matches what happened.

Answer quickly. Reply with a 2xx within 10 seconds and do the real work afterwards. A slow reply counts as a failure and will be retried.

Persistently failing endpoints get switched off. After 20 consecutive failures the endpoint moves to AUTO_DISABLED and stops receiving events until you turn it back on. This protects your system from a backlog and ours from retrying into a void.

Some changes are not instant. Domain monitoring states come from a periodic sweep, not a live feed, so there is a delay between a DNS change and the event describing it. Recovery from a hosted-record error is picked up by an hourly reconciliation, so an error clearing can take an hour or more to be reported.

Task events wait four hours on purpose. Newly detected tasks churn, so a task has to hold its state for four hours before Palisade sends an event. A task you can already see in the dashboard may not have produced a task.opened yet, and a task that opens and resolves inside that window produces no events at all. This is deliberate: it keeps self-resolving problems out of your ticket queue. If you would rather see everything immediately, poll the tasks API instead.

tip

Subscribe to task.reopened alongside task.completed. If you close a ticket when a task completes and do not listen for reopening, your ticket will stay closed after the problem comes back.

Checking what happened

GET /webhook-endpoints/{id}/deliveries lists recent attempts with the response code and error from each one. Records are kept for 30 days, so it is a debugging aid rather than an archive -- if you need a permanent record, store events as you receive them. You can still read the history after deleting an endpoint, which is usually exactly when you want to. Start there when an event you expected never arrived -- it will usually show either a rejected signature, a timeout, or an endpoint that was disabled.

Rotating the secret

POST /webhook-endpoints/{id}/rotate-secret issues a new signing secret and returns it once.

Rotation takes effect immediately: messages signed with the old secret will fail verification from that moment. Update your receiver in the same change window, or briefly accept either secret while you roll over.