Webhook Integration
How the Webhook Integration Works
The webhook is the universal publish path: when an article is ready, RankPush sends a signed JSON POST to an endpoint you control, and your code maps it into any CMS, static-site pipeline, or database. If your platform isn't one of our native integrations, this is how you connect it.
Endpoint requirements:
- A public https:// URL (plain http and internal/private addresses are rejected)
- Responds with a 2xx status when it accepts a delivery
- Responds quickly — deliveries time out after 20 seconds; accept fast and process async if needed
Setup Instructions
- Open Settings → Integrations → Webhooks and enter your endpoint URL
- RankPush immediately sends a signed
pingevent — your endpoint must answer 2xx for the connection to complete - Your signing secret is shown once on success — store it in your server's environment. It can't be viewed again; reconnect to rotate it.
Delivery format
Every delivery is a JSON POST with three RankPush headers:
| Header | Value |
|---|---|
x-rankpush-signature | sha256=<hex> — HMAC-SHA256 of the raw request body, keyed with your signing secret |
x-rankpush-timestamp | Unix seconds when the delivery was sent — reject stale values to block replays |
x-rankpush-event | ping · article.published · article.updated |
The secret itself is never transmitted — authenticity is proven only by the signature, so nothing on the wire can be captured and reused to forge deliveries.
What Gets Published
{
"event": "article.published",
"our_post_id": "9f8f89d0-b73e-4f96-9a1d-24cf12f23c20",
"title": "10 Brand Content Examples That Turn Readers Into Fans",
"content": "<p>Full sanitized article HTML…</p>",
"slug": "brand-content-example",
"meta_description": "See how leading brands…",
"focus_keyword": "brand content example",
"seo_title": "10 Brand Content Examples That Turn Readers Into Fans",
"featured_image_url": "https://…/featured.webp",
"images": [
{ "url": "https://…/body-1.webp", "alt": "Designer's hands arranging printed brand mood boards" }
],
"sent_at": "2026-08-14T13:05:09.320Z"
}- our_post_id is the stable correlation key — upsert on it.
article.updatedarrives with the same id when an article is edited or improved after publishing. - content is sanitized, ready-to-render HTML; in-body images are hosted on our durable CDN URLs
- images[].alt carries the descriptive alt text — keep it when importing
- Nullable fields (
slug,featured_image_url, …) may benull
Verifying the signature
Compute the HMAC over the raw request body — before any JSON parsing or re-serialization — and compare in constant time:
import crypto from "node:crypto";
export function verifyRankPush(rawBody, headers, secret) {
const expected =
"sha256=" + crypto.createHmac("sha256", secret).update(rawBody).digest("hex");
const given = headers["x-rankpush-signature"] ?? "";
const fresh =
Math.abs(Date.now() / 1000 - Number(headers["x-rankpush-timestamp"])) < 300;
return (
fresh &&
given.length === expected.length &&
crypto.timingSafeEqual(Buffer.from(given), Buffer.from(expected))
);
}Retries and failure handling
- 2xx — delivery accepted; the article is marked published
- 429 or 5xx — treated as transient and retried
- Other 4xx — treated as a configuration error and surfaced on the article so you can fix the endpoint and retry manually
Troubleshooting
Connection fails at the ping
The endpoint must be public https and answer 2xx. Localhost, private IPs, and http URLs are rejected by design.
Signature never matches
You're almost certainly hashing a parsed-and-re-stringified body. Frameworks like Express need the raw body (e.g. express.raw() on the webhook route) before any JSON middleware touches it.
Duplicate posts
Upsert on our_post_id, not on slug or title.
Security & Best Practices
- Always verify the signature before trusting a delivery — the secret is never transmitted, so a valid HMAC is the only proof it came from RankPush
- Reject stale timestamps (±5 minutes is a sane window) to block replayed deliveries
- Store the signing secret in your server's environment, never in client-side code or the repo
- Return 2xx as soon as the delivery is safely accepted and do heavy processing async — deliveries time out at 20 seconds
- To rotate the secret, disconnect and reconnect the webhook
Other integrations
On a supported platform? Native WordPress and Webflow integrations skip the custom code entirely.
Put your content on autopilot
Connect your site once — RankPush researches keywords, writes SEO articles, and publishes them for you every day.
Join with Google