Webhooks

Postline sends signed webhook requests when posts are scheduled, published or fail. Learn the events, payload, signature check and retries.

On this pageAdd a webhookEventsThe requestVerify the signatureResponses and retries

Add a webhook

Only owners and admins can manage webhooks.

  1. Go to Settings → API → Webhooks.
  2. Enter a name and your URL, for example https://hooks.example.com/postline.
  3. Pick the events you want.
  4. Choose Add webhook.
  5. Copy the signing secret (it starts with whsec_). You won't see it again.

Choose Send test to send a test delivery. The list shows the result of the last delivery for each webhook. A workspace can have up to 20 webhooks. The URL must be a public address.

Events

EventSent when
post.scheduledA post is scheduled
post.approval_requestedAn editor submits a post for approval
post.publishedA scheduled post has gone out. Also sent when it went out on only some channels
post.failedA post failed on every channel
channel.reconnect_neededA channel lost its connection and must be reconnected

New webhooks start with post.published and post.failed selected. A test delivery uses the event name test.

The request

Postline sends a POST request with a JSON body:

{
  "event": "post.published",
  "createdAt": "2026-11-03T09:30:05.000Z",
  "data": { ... }
}

For post events, data is the post: its id, content, status, date and a targets list with each channel's status, url and error. For channel.reconnect_needed, data has channelId, name, network and error.

Headers:

HeaderValue
Content-Typeapplication/json
X-Postline-EventThe event name
X-Postline-TimestampUnix time in seconds when the request was signed
X-Postline-Signaturesha256= followed by the hex HMAC-SHA256 signature

Verify the signature

The signature is HMAC-SHA256 of timestamp.body, using your webhook secret as the key. timestamp is the X-Postline-Timestamp header and body is the raw request body.

  1. Read the raw body before parsing it as JSON.
  2. Compute sha256= + hex(HMAC-SHA256(secret, timestamp + "." + body)).
  3. Compare it with X-Postline-Signature using a constant-time comparison.
  4. Optionally reject requests with an old timestamp.

Node.js example:

import crypto from 'node:crypto';

function isValid(secret, timestamp, rawBody, signature) {
  const expected = 'sha256=' + crypto.createHmac('sha256', secret).update(`${timestamp}.${rawBody}`).digest('hex');
  const a = Buffer.from(expected);
  const b = Buffer.from(signature ?? '');
  return a.length === b.length && crypto.timingSafeEqual(a, b);
}

Responses and retries

Answer with any 2xx status to confirm delivery. Postline waits up to 10 seconds for a response and doesn't follow redirects.

If a delivery fails, Postline retries it up to 3 more times, waiting about 10, 20 and then 40 seconds. It doesn't retry when your server answers with a 4xx status, except 429.