API operational
Webhooks

Webhook payload shapes

The envelope, the signing headers, and the event catalog PostGate publishes — laid out with a clear line between what's confirmed in the Webhooks reference and what you should confirm against a live delivery before you rely on it.

What this page is (and isn't)
This is a field-by-field read of what the Webhooks guide actually documents, not a reverse-engineered full schema. Where the guide only names an event and doesn't enumerate its data object, this page says so instead of inventing fields. Use POST /api/webhooks/{id}/test to see a real payload for events where the shape isn't fully spelled out.
01

The envelope — confirmed

Every webhook delivery shares the same top-level shape: id, type, occurred_at, and a resource-specific data object. That's the complete confirmed envelope — the guide doesn't publish a full worked JSON example with every field filled in, so treat the block below as the documented field list, not a literal sample response.

Keep unknown fields when you relay an event through your own pipeline. PostGate can add fields to data for a given event type without warning, and a strict allowlist mapper will silently drop them.

Confirmed envelope fields (not a literal payload example)PostGate API
{
  "id": "string — stable event ID, also sent as X-PostGate-Event-Id",
  "type": "string — one of the event catalog names below",
  "occurred_at": "string — when the underlying change happened",
  "data": { /* resource-specific — see the event catalog for what's documented per type */ }
}
02

Signing headers — confirmed

PostGate signs <timestamp>.<raw-body> with HMAC-SHA256 using your webhook's signing secret. The digest is sent in X-PostGate-Signature as two comma-separated key/value pairs — t (the signing timestamp) and v1 (the hex-encoded HMAC). The event's stable ID is sent separately as X-PostGate-Event-Id, matching the envelope's id field. Both header names are confirmed in the Webhooks reference and used verbatim in the signature verification walkthrough, which includes a complete working verification example.

X-PostGate-Signature header shapePostGate API
t=1785254400,v1=4f7c...9a2e
03

Event catalog — what's named vs. what's fully specified

You choose a subset of these topics in events[] when you create a subscription. For a few event types the guide also documents the specific fields inside data; for the rest, only the event name and a one-line description are published.

Data fields the guide confirms:

  • post.insights — post_id, targets[] (each with target_id, platform, platform_post_id, metrics), captured_at.
  • profile.stats_updated — profile_id, platform, followers, follower_delta, metrics, captured_at.
  • profile.expired — reason: "token_expired".
  • profile.reauth_required — reason, one of refresh_failed, revoked, or publish_auth_error.

profile.expired and profile.reauth_required are also confirmed to fire once per authorization state transition, not on every internal maintenance sweep — a profile that reconnects and later breaks again fires a new event rather than repeating the old one.

Named, but with no documented data field list:

  • post.draft / post.scheduled — a post was created in that state.
  • post.published / post.partial / post.failed — a post reached a terminal state. The guide doesn't enumerate data for these; the delivery lifecycle guide documents the equivalent targets array shape returned by GET /api/posts/{id}, which is a reasonable working assumption for what data carries — but it isn't stated as identical, so verify it against a real delivery before you depend on exact field names.
  • profile.connected / profile.disconnected — a profile was connected or disconnected.
  • profile.expiring — a profile's authorization is nearing expiry.
  • stats.updated — PostGate's generic analytics event, covering both post targets and profiles.
  • comment.created / message.received — inbound engagement arrived.
04

Subscribe to the events you use

Subscribe only to events your product consumes. The signing secret is returned once at creation — save it immediately.

Create a webhook subscriptionPostGate API
curl -X POST https://postgate.studio/api/webhooks \
  -H "Authorization: Bearer $POSTGATE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://app.example.com/webhooks/postgate",
    "events": ["post.published", "post.partial", "post.failed"]
  }'
05

See a real payload instead of guessing

For any event type not covered above, the fastest way to get the exact data shape is to trigger one and look at it — not to infer it from field names in prose. POST /api/webhooks/{id}/test queues a test delivery to your endpoint, and logging the raw request body there (before you build any strict parsing against it) gives you the real, current shape for that event type in your account.

Don't hardcode an unconfirmed shape
Building a strict typed parser against a data shape you inferred rather than confirmed is a common source of webhook consumers that silently break the first time PostGate adds a field. Deserialize loosely and read only the fields you actually need until a shape is documented.