Webhook integration

The GEOHATS webhook for Zapier, Make, n8n and your own backend

In short: The webhook sends every page GEOHATS publishes, and every site fix you apply, as a JSON POST to a URL you control. Each request is signed with HMAC-SHA256 in the X-Geohats-Signatureheader. Reply with a URL and GEOHATS records it as the page’s live address.

When to use the webhook

Use it when your site runs on a platform without a direct GEOHATS integration, or when you want an automation in the middle: post to a CMS that Zapier, Make or n8n supports, send a Slack message for review, save the page to a Google Doc, or call your own API. If you are on WordPress, Webflow, Shopify, Framer, Ghost, HubSpot, Wix or GitHub, a direct integration is simpler.

Setup

  1. Create a catch hook: Webhooks by Zapier (Catch Hook) in Zapier, a Custom webhook in Make, a Webhook node in n8n, or an endpoint of your own.
  2. In GEOHATS, open the website, go to Integrations, choose Webhook and paste the URL. It must be https.
  3. GEOHATS sends a ping event. If your endpoint answers with a 2xx status, the connection is saved and your signing secret is shown. Copy it then.
  4. Pick an auto-publish mode for the website: Off, Send as draft or Publish live (see auto-publish modes).

Events

Webhook events GEOHATS sends
eventWhen it is sentMain fields
pingWhen you connect, and when you click Test connectionevent, sentAt
page.draftA new page passes the quality gate while the website is in Send as draft modeevent, sentAt, page
page.publishYou click Publish, your agent calls publish_page, or a new page passes the gate in Publish live modeevent, sentAt, page
seo.fixYou apply or undo a site optimizer fixevent, sentAt, fix

Payload: pages

POST body for page.publish (page.draft is identical with status "draft")
{
  "event": "page.publish",
  "sentAt": "2026-10-23T09:14:02.511Z",
  "page": {
    "title": "Best invoicing software for freelancers",
    "slug": "best-invoicing-software-for-freelancers",
    "excerpt": "A short summary taken from the page...",
    "bodyHtml": "<article>...</article>",
    "fullHtml": "<!doctype html><html>...</html>",
    "jsonLd": ["{\"@context\":\"https://schema.org\", ...}"],
    "status": "publish"
  }
}
Fields of the page object
FieldWhat it contains
titleThe page title, cleaned of HTML entities
slugThe URL slug. The same page always has the same slug, so use it as the key when updating.
excerptA short summary taken from the page
bodyHtmlThe article body: no document head, executable scripts, style blocks, comments or placeholder markers. JSON-LD blocks inside the body are kept.
fullHtmlThe complete standalone HTML document, with internal links made absolute on your domain
jsonLdAn array of strings, one per JSON-LD block in the page, as raw JSON text
status"publish" or "draft"

Only pages that passed the GEOHATS quality gate are sent. The values above are illustrative; the structure is exact.

Payload: SEO fixes

POST body for seo.fix
{
  "event": "seo.fix",
  "sentAt": "2026-10-23T09:20:41.007Z",
  "fix": {
    "type": "meta_description",
    "pageUrl": "https://yoursite.com/pricing",
    "target": "",
    "value": "Plans for teams of every size...",
    "anchor": "",
    "revert": false
  }
}

The fixes come from the site optimizer.

Verify the signature

When you connect, GEOHATS generates a random signing secret. Every request carries the header X-Geohats-Signature: sha256=<hex>, where the hex is the HMAC-SHA256 of the raw request body keyed with that secret. Recompute it and compare with a constant-time check. Verify the raw bytes before parsing: parsing and re-serializing the JSON can change them.

verify.js (Node.js)
import crypto from "node:crypto";

// rawBody must be the exact bytes GEOHATS sent: verify BEFORE parsing JSON.
export function verifyGeohats(rawBody, signatureHeader, secret) {
  const expected =
    "sha256=" + crypto.createHmac("sha256", secret).update(rawBody).digest("hex");
  const got = Buffer.from(signatureHeader ?? "");
  const want = Buffer.from(expected);
  return got.length === want.length && crypto.timingSafeEqual(got, want);
}
Using it in a route handler
// app/api/geohats/route.js (Next.js route handler)
import { verifyGeohats } from "./verify";

export async function POST(req) {
  const raw = await req.text();
  const ok = verifyGeohats(
    raw,
    req.headers.get("x-geohats-signature"),
    process.env.GEOHATS_WEBHOOK_SECRET,
  );
  if (!ok) return new Response("Bad signature", { status: 401 });

  const evt = JSON.parse(raw);
  if (evt.event === "page.publish") {
    // Create or update your post keyed by evt.page.slug, then return its URL.
    return Response.json({ url: `https://yoursite.com/blog/${evt.page.slug}` });
  }
  return Response.json({ ok: true }); // ping, page.draft, seo.fix
}

In Zapier, Make or n8n, verifying is optional. If your automation can run a code or crypto step, recompute the HMAC there the same way. If it cannot, keep the webhook URL private, because anyone who has it can send requests to it.

Your response

Security notes

The webhook URL must be https, and GEOHATS refuses URLs that resolve to private or cloud-metadata network addresses. The connection settings, including the secret, are stored encrypted.

FAQ

How do I connect GEOHATS to Zapier?

Create a Zap with a Webhooks by Zapier Catch Hook trigger and copy its URL. In GEOHATS, open the website, go to Integrations, choose Webhook and paste the URL. GEOHATS sends a test ping, so the trigger has sample data, and shows your signing secret.

How do I verify that a request came from GEOHATS?

Compute HMAC-SHA256 of the raw request body with your signing secret, hex-encode it, prefix it with sha256= and compare it to the X-Geohats-Signature header using a constant-time comparison. Verify before parsing the JSON, since re-serializing changes the bytes.

How does GEOHATS learn the live URL of the post?

Reply to a page.publish request with JSON like {"url": "https://yoursite.com/blog/slug"}. GEOHATS records it as the page's live URL if it starts with http or https and is on a different host than the webhook itself.

What happens when I republish a page?

GEOHATS sends the page again with the same slug. Use the slug as the key in your automation and update the existing post instead of creating a new one.

Can the webhook receive SEO fixes too?

Yes. Site optimizer fixes arrive as seo.fix events for all eight fix types: title, meta description, canonical, FAQ schema, Article schema, Organization schema, image alt text and internal link. An undo arrives as a seo.fix event with revert set to true.

What if I lose the signing secret?

It is shown when the connection is saved. If you lose it, connect the webhook again: GEOHATS generates a new secret, and the old one stops being used.

Route your GEOHATS pages anywhere

The webhook is included in every plan, alongside the direct CMS integrations and the MCP server. You pay once and use your own AI keys.

See pricing

Last updated