Guides

Webhooks

Get told when something happens instead of polling. Register an endpoint and PostLake POSTs an event to it when a post publishes, fails, or an account connects. Ideal for scheduled posts and async platforms.

Register an endpoint

Give PostLake a URL and the events you care about. You get back a WebhookEndpoint with a secret used to verify deliveries.

curl -X POST https://api.postlake.dev/v1/webhooks \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://yourapp.com/hooks/postlake",
    "events": ["post.published", "post.failed"]
  }'

Event types

EventFires when
post.publishedEvery target of a post has published.
post.partialSome targets published, some failed.
post.failedNo target published.
post.processingA post moved to processing (async platforms).
account.connectedA social account finished connecting.

The delivery

PostLake POSTs a JSON body with the event type and the affected resource (the full Post for post.* events), so you can act without a follow-up API call.

{
  "type": "post.published",
  "data": { "id": "post_a1b2c3", "state": "published", "targets": [ … ] }
}

Verify the signature

Every delivery carries a postlake-signature header of the form t=<unix-seconds>,v1=<hex>. The v1 value is an HMAC-SHA256 of <t>.<raw-body> keyed with your endpoint secret. Verify it before trusting the payload. This proves the request really came from PostLake and (with a timestamp tolerance) blocks replays.

Verify the raw body, exactly as received. Don't parse and re-serialize the JSON first, or the bytes (and the signature) change.

With the SDK it's one call:

import { verifyWebhookSignature } from "postlake";

// in your handler. Pass the RAW request body
const ok = await verifyWebhookSignature(
  endpointSecret,                     // the secret returned by webhooks.create()
  rawBody,                            // exact bytes received
  req.headers["postlake-signature"],  // the signature header
  { toleranceSec: 300 },              // reject deliveries older than 5 min (optional)
);
if (!ok) return res.status(400).end();

Or without the SDK, in plain Node:

import { createHmac, timingSafeEqual } from "node:crypto";

function verify(secret, rawBody, header) {
  const { t, v1 } = Object.fromEntries(header.split(",").map(kv => kv.split("=")));
  const expected = createHmac("sha256", secret).update(`${t}.${rawBody}`).digest("hex");
  const a = Buffer.from(expected), b = Buffer.from(v1);
  return a.length === b.length && timingSafeEqual(a, b);
}

Respond 2xx quickly once verified; failed deliveries are retried with backoff.

Managing endpoints

List your endpoints with GET /v1/webhooks and remove one with DELETE /v1/webhooks/{id}. See the API reference for the exact shapes.