Post to a Custom Webhook#

When a service has no official integration, it usually has a webhook. This example posts a JSON payload to any URL you control, the generic building block for notifications and automation.

The Script#

// webhook.js
import env from "env";

const body = {
	source: "geartrain",
	message: "Daily job finished",
	at: new Date().toISOString(),
};

const res = await fetch(env.get("WEBHOOK_URL"), {
	method: "POST",
	headers: {
		"Content-Type": "application/json",
		"X-Webhook-Secret": env.get("WEBHOOK_SECRET"),
	},
	body: JSON.stringify(body),
});

if (!res.ok) {
	throw new Error(`Webhook failed: ${res.status}`);
}

console.log("Webhook delivered");

How It Works#

  • The payload is plain JSON: adapt the fields to whatever the receiving service expects.
  • Extra headers, such as a shared secret, are a common way for the receiver to verify the request came from you. A secret header alone does not protect the body from tampering; use an HMAC signature when the receiver needs to verify both authenticity and integrity.
  • If the receiver only needs a signal and no data, send an empty body with body: "" and drop the Content-Type header.

Setup#

Create two secrets:

Secret Value
WEBHOOK_URL The endpoint that receives the post
WEBHOOK_SECRET A shared secret the receiver checks

If the receiver does not check a secret, drop that header and secret.