[ Docs ]

Webhooks

Postatron tells your server the moment a post publishes, fails or needs attention, signed so you know it came from us.

  1. Something happensa post publishes
  2. Postatron signs itPostatron-Signature
  3. POST to your URLhttps only
  4. You answer 2xxdelivered

Adding a webhook

On the API & MCP page choose New webhook, give an https address and pick the events, or all of them. Postatron shows the signing secret once: copy it then. Send a test from the same page to check your server answers.

Webhooks come with Growth and Scale. You can add up to five, and only the account owner can manage them, because they carry every post and account.

Events

EventWhen
post.publishedA post went out on every account
post.partialA post went out on some accounts and failed on others
post.failedA post went out nowhere
post.unpublishedA post came due while the account had no plan
account.connectedAn account was connected
account.disconnectedAn account was disconnected or lost access
account.needs_attentionAn account with scheduled posts needs reconnecting soon
webhook.testYou sent a test

Body

{
  "id": "<delivery id>",
  "type": "post.published",
  "created_at": "2026-11-10T09:00:04Z",
  "data": { "post": { "id": "...", "deliveries": [ ... ] } }
}

data.post is exactly what GET /v1/posts/{id} returns. Account events carry data.account, and for a lost account the scheduled posts at risk.

Checking the signature

Each request carries Postatron-Signature: t=<unix time>,v1=<signature>. The signature is an HMAC-SHA256 of the timestamp, a full stop and the raw body, keyed with your whole secret. Compare it in constant time, and refuse old timestamps.

import crypto from 'node:crypto';

export function verify(rawBody, header, secret) {
  const pairs = header.split(',').map(part => part.split('='));
  const t = pairs.find(([k]) => k === 't')?.[1];
  const signatures = pairs.filter(([k]) => k === 'v1').map(([, v]) => v);
  if (!t || Math.abs(Date.now() / 1000 - Number(t)) > 300) return false;
  const expected = crypto.createHmac('sha256', secret).update(`${t}.${rawBody}`).digest('hex');
  return signatures.some(s => s.length === expected.length &&
    crypto.timingSafeEqual(Buffer.from(s), Buffer.from(expected)));
}

Every request also carries Postatron-Event and Postatron-Delivery. The delivery id stays the same if an event is sent twice, so use it to skip duplicates.

Retries

  1. Try 1At once
  2. Try 21 minute later
  3. Try 310 minutes later
  4. Try 41 hour later
  5. Try 56 hours later
  6. Try 612 hours later
Six attempts over about 19 hours. Each waits 10 seconds for your answer.
  • Any 2xx answer counts as delivered. Anything else, a timeout or a redirect, is retried on the schedule above.
  • After 20 deliveries in a row fail, the webhook is switched off and the page says why. One success resets the count.
  • Rotating the secret keeps the old one signing beside the new one for 24 hours, so you can switch without missing an event.

The full reference, with Go too, is in the API reference.