Foxli
Log inStart free
Developers / Guide

Webhooks

Receive real-time HTTP POST notifications the instant posts go live, fail on third-party networks, or when social channel access tokens require reconnection.

Supported events (4)

Subscribe your endpoint to any combination of these events when creating a webhook:

post.published

Fired when a post publishes successfully to all connected target channels.

Includes post_id, live post_urls per channel, and published timestamp.
post.failed

Fired when publishing attempts fail across all target channels.

Includes post_id, error messages, and network failure reason codes.
post.partially_published

Fired when a multi-channel post publishes to some channels but encounters errors on others.

Includes per-channel status breakdown with post_url or error_message for each.
channel.disconnected

Fired when a connected social account token expires, is revoked by user, or disconnected.

Includes channel_id, provider, handle, and reason code.

Payload structure

Every webhook dispatch includes an event identifier, ISO timestamp, workspace context, and the entity details:

Webhook event JSON
{
  "id": "evt_90f12c8a91",
  "event": "post.published",
  "timestamp": "2026-11-05T12:00:00Z",
  "workspace_id": "ws_brand_primary",
  "payload": {
    "post_id": "pst_89fa12b",
    "results": [
      {
        "channel_id": "ch_ig_01",
        "status": "success",
        "post_url": "https://instagram.com/p/DB18f921"
      },
      {
        "channel_id": "ch_li_02",
        "status": "success",
        "post_url": "https://linkedin.com/feed/update/urn:li:share:9812"
      }
    ]
  }
}

Foxli-Signature header

Every webhook request arrives with a Foxli-Signature HTTP header formatted as:

Foxli-Signature: t=1730808000,v1=9fa81bc32e71829...

Where t is the Unix epoch timestamp (seconds) when the webhook was sent, and v1 is the hex-encoded HMAC-SHA256 signature calculated over the concatenated string {timestamp}.{raw_request_body} using your webhook secret (whsec_...).

Verification code (Node & Python)

Always verify the signature before processing payloads to guarantee authenticity and prevent replay attacks:

import crypto from "crypto";

export function verifyFoxliWebhook(rawBody, signatureHeader, secret, toleranceSeconds = 300) {
  if (!signatureHeader) {
    throw new Error("Missing Foxli-Signature header");
  }

  // Parse header: t=1730808000,v1=9fa81bc32e...
  const parts = Object.fromEntries(
    signatureHeader.split(",").map((item) => item.split("="))
  );
  const timestamp = parseInt(parts.t, 10);
  const expectedSig = parts.v1;

  if (!timestamp || !expectedSig) {
    throw new Error("Malformed Foxli-Signature header");
  }

  // Prevent replay attacks
  const now = Math.floor(Date.now() / 1000);
  if (Math.abs(now - timestamp) > toleranceSeconds) {
    throw new Error("Webhook timestamp expired or outside tolerance window");
  }

  // Compute HMAC-SHA256 signature
  const signedPayload = `${timestamp}.${rawBody}`;
  const computedSig = crypto
    .createHmac("sha256", secret)
    .update(signedPayload, "utf8")
    .digest("hex");

  // Constant-time comparison (lengths must match first, or timingSafeEqual throws)
  const a = Buffer.from(computedSig, "hex");
  const b = Buffer.from(expectedSig, "hex");
  const isValid = a.length === b.length && crypto.timingSafeEqual(a, b);

  if (!isValid) {
    throw new Error("Invalid Foxli webhook signature");
  }

  return true;
}

Delivery & retry schedule

Your endpoint must acknowledge delivery by returning an HTTP 2xx status code within 10 seconds.

5 Automatic Retries

If delivery fails or times out, Foxli retries on an exponential schedule:
1 min → 5 min → 30 min → 2 hours → 6 hours.

7-Day Delivery Logs

Every webhook dispatch attempt, duration, response status, and error snippet is retained in your Foxli dashboard for 7 days.

Build on Foxli.

Publish posts, sync social channels, stream analytics, and get instant webhooks.

No card for month one · Cancel anytime