Guide

Webhooks: events, HMAC signature, deliveries, redrive

Social Relay sends signed HTTPS POSTs to your webhook URL for post and connection events. Verify header X-Social-Restapi-Signature as t=<unix>,v1=<hex> where v1 is HMAC-SHA256 of `{t}.{raw_body}` with your webhook secret. Handlers must be idempotent on event id.

← GuidesWebhooks & reliabilityUpdated 2026-08-10

In short

Social Relay sends signed HTTPS POSTs to your webhook URL for post and connection events. Verify header X-Social-Restapi-Signature as t=<unix>,v1=<hex> where v1 is HMAC-SHA256 of `{t}.{raw_body}` with your webhook secret. Handlers must be idempotent on event id.

Register

POST /api/v1/webhooks with an HTTPS url and events array (or *). Webhooks are application-scoped—register under the same app as the keys/profiles that emit events; fan-out does not cross apps. The signing secret is shown once—store it in your secret manager.

Register bodyjson
{
  "url": "https://saas.example/hooks/social",
  "events": ["post.succeeded", "post.partial", "post.failed", "connection.created", "connection.revoked"]
}

Signature verification

Header name: X-Social-Restapi-Signature. Value form: t=<unix_seconds>,v1=<hex_digest>. Base string is the timestamp, a period, then the exact raw request body. HMAC-SHA256 with the webhook secret; compare hex digests in constant time. Reject stale timestamps.

Node sketchjavascript
import crypto from "node:crypto";
function verify(secret, rawBody, header) {
  const parts = Object.fromEntries(header.split(",").map((p) => p.split("=")));
  const base = `${parts.t}.${rawBody}`;
  const expected = crypto.createHmac("sha256", secret).update(base).digest("hex");
  return crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(parts.v1));
}

Events (v1)

  • post.processing, post.succeeded, post.partial, post.failed, post.scheduled
  • connection.created, connection.revoked

Delivery and redrive

Deliveries are logged with status and HTTP codes. Auto-retry uses exponential backoff. Use dashboard or API redrive for dead letters. Listing deliveries costs list tokens—do not poll every second.

Token costs

webhooks.create = 1 token; webhooks.list = free. Outbound delivery attempts are not billed as a separate action in the current rate card.