Browse docs

Integration · outbound events

Outbound webhooks

Receive publish outcomes and fresh performance evidence without polling. Every request is signed; delivery is at least once.

Current contract

Events

post.published

Publish succeeded

The post reached its terminal published state. Destination evidence is included.

post.failed

Publish did not fully succeed

The post is failed or partial. Inspect the payload status and destination errors.

performance.updated

New measurement stored

A new evidence-backed metric snapshot is available. Null values remain null.

Stable envelope

Request

Postdom sends an HTTPS POST with the exact JSON body shown by the event. Use Webhook-Id as the idempotency key for your receiver.

EXAMPLE WEBHOOK BODY
{
  "id": "0e386be3-…",
  "type": "post.published",
  "created_at": "2026-08-28T04:12:00.000Z",
  "data": {
    "post_id": "53b81c96-…",
    "status": "published",
    "destinations": []
  }
}

Headers

Webhook-Id identifies the event, Webhook-Timestamp is Unix seconds, and Webhook-Signature contains the v1 HMAC.

HMAC-SHA256

Verify before processing

Sign the raw request body—not parsed and re-serialized JSON—with event_id.timestamp.body. Compare signatures in constant time and reject stale timestamps.

NODE.JS VERIFICATION SKELETON
import { createHmac, timingSafeEqual } from "node:crypto";

const eventId = request.headers.get("Webhook-Id");
const timestamp = request.headers.get("Webhook-Timestamp");
const supplied = request.headers.get("Webhook-Signature");
const body = await request.text();

// Reject stale timestamps first; five minutes is a sensible replay window.
const expected = "v1=" + createHmac("sha256", process.env.POSTDOM_WEBHOOK_SECRET)
  .update(eventId + "." + timestamp + "." + body)
  .digest("hex");

const valid = supplied?.length === expected.length &&
  timingSafeEqual(Buffer.from(supplied), Buffer.from(expected));

Secrets are shown once when an endpoint is created or rotated. Store them in a secret manager. New deliveries use the rotated secret immediately; a request already in flight may still use the previous secret for up to 15 seconds.

At least once

Delivery and retries

Any 2xx response completes a delivery. Redirects, timeouts, network failures, and other HTTP statuses are retried after approximately 1 minute, 5 minutes, 30 minutes, 2 hours, and 12 hours. The sixth failed attempt is exhausted.

Make receivers idempotent

A worker may retry after an ambiguous network result. Persist Webhook-Id before applying the event so a duplicate delivery does not duplicate downstream work.

Pausing or removing an endpoint cancels queued retries. A request already in flight may still finish.

Authenticated dashboard

Manage endpoints

Workspace owners and admins can add up to five HTTPS endpoints from Accounts → Developer webhooks, choose event types, pause delivery, rotate the secret, remove the endpoint, and inspect recent attempts. Workspace members can inspect status but cannot change it.

Endpoint URLs must use public DNS and the default HTTPS port. Postdom rejects IP literals, private or reserved DNS answers, credentials, fragments, and redirects.

VERIFIED · 26 AUGUST 2026Transactional event outbox · Worker delivery lease · Dashboard endpoint management

Publish and performance events are inserted in the same database transaction as the state they describe.