Integrations (outbound webhooks)
When a lead qualifies, replies, books a call or is won, SiteRevive can post that lead to a tool you already use — your CRM, Zapier, GoHighLevel, or anything that accepts an HTTPS request. SiteRevive finds and proves; your receiver keeps the pipeline. Nothing here sends anything to a prospect.
You set it up under Settings → Integrations.
Adding an endpoint
An endpoint is the URL your tool gave you to receive posts — a Zapier "Catch Hook", a GoHighLevel inbound webhook, your own server. Give it a name and paste the URL.
- The URL must be https. Plain http is refused.
- The address must be on the public internet. Private, internal and local addresses are refused, and SiteRevive checks the address again before every post in case it changes later.
- You get the signing secret exactly once, right after the endpoint is added. Copy it into your receiver then. SiteRevive keeps it sealed and never shows it again; if you lose it, use Rotate secret to get a new one (the old one stops signing anything).
Only an owner can add, rotate, disable or delete an endpoint. Anyone in the workspace can choose which events post, send a test event, or retry a failed post.
Choosing what posts
Each endpoint has four switches. Turn on the ones your tool should hear about:
- Lead qualified (
lead.qualified) — a business passed the audit and its evidence report has been published. The post goes out when the report is ready, not at the audit itself, solinks.reportis always filled in; a lead whose report never publishes is never posted. - Reply received (
reply.received) — a reply arrived, or you logged one by hand. - Call booked (
call.booked) — you marked a call as booked. - Lead won (
lead.won) — you marked the deal won.
Each switch posts a lead at most once per day for that event, however many times the event lands.
Send test event posts a lead.test with a made-up business so you can see the shape of a post without any real prospect's data leaving your workspace. It is signed and retried exactly like the real thing.
What a post contains
Every post is a JSON body with the lead's facts and links — never a prospect's message body, never a reply's text, never your notes, never your own email address.
id— the delivery id;event— one of the names above;created_at.workspace— your workspace's id and name.lead—id,business_name,website,phone,email,city,state,score,opportunity_type,status,listed_website_kind, andreply_intent— the newest reply's label, one ofinterested,neutral,negativeorunsubscribe(or null when there is no reply). It is a label, never the words the prospect wrote. A reply that asks you to stop is never posted at all: the lead is unsubscribed in SiteRevive and noreply.receivedgoes out.links—lead(the lead's page in Manage Leads),report(the public evidence report, when there is one) andpreview(the preview site, when there is one).meta—rule_id,rule_name,fire_id, andattempt(1 on the first try).
A body is at most 16 KB.
Verifying a post
Every post carries these headers:
X-SiteRevive-Event— the event name.X-SiteRevive-Delivery— a key that is the same on every retry of the same post. Use it to ignore a duplicate.X-SiteRevive-Timestamp— when the post was signed, in unix seconds.X-SiteRevive-Signature—v1=followed by the hex HMAC-SHA256 of${timestamp}.${body}under your signing secret.Content-Type: application/jsonandUser-Agent: SiteRevive-Webhooks/1.
Reject a post whose signature does not match or whose timestamp is more than five minutes (300 seconds) old. In Node:
const { createHmac, timingSafeEqual } = require("node:crypto");
// rawBody: the request body as a string, exactly as received.
function verify(secret, headers, rawBody) {
const timestamp = headers["x-siterevive-timestamp"];
const signature = headers["x-siterevive-signature"] || "";
if (Math.abs(Date.now() / 1000 - Number(timestamp)) > 300) return false;
const expected = createHmac("sha256", secret).update(`${timestamp}.${rawBody}`).digest("hex");
const presented = signature.startsWith("v1=") ? signature.slice(3) : "";
if (!/^[0-9a-f]{64}$/.test(presented)) return false;
if (presented.length !== expected.length) return false;
return timingSafeEqual(Buffer.from(presented, "hex"), Buffer.from(expected, "hex"));
}
Sign the raw body exactly as received — do not parse and re-serialize it first. Answer with any 2xx status once you have stored the post; anything else is treated as a failure.
Retries and failures
If your receiver does not answer with a 2xx — a timeout, a 5xx, a redirect, or an address that has stopped being public — SiteRevive retries with a growing gap: after 1 minute, then 5 minutes, 30 minutes, 2 hours, and finally 12 hours. If that sixth attempt fails too, the post is marked Failed under Recent deliveries, with the last status code and the first part of the response kept, and you can press Retry now.
Redirects are never followed. A receiver that answers with a redirect is treated as failed.
If twenty posts in a row fail, SiteRevive disables the endpoint and says why on the page. Fix the receiver, then press Re-enable; a single successful post resets the count.
Recent deliveries shows the last 25 posts with their event, status, attempts, last code and time. The body itself is not shown there.
Removing an endpoint
Disable stops posting without losing anything. Delete asks you to type the endpoint's name, then removes it along with its switches and its delivery history.