PostraDocsOpen Postra

Webhooks

A webhook is an address on your server. Postra sends it a message each time a post goes out, so your other tools can react: post a note in Slack, add a row to a client report or update your CRM.

When Postra calls it

There is one event: a post was published.

Add a webhook

You need to be the workspace owner or an Admin.

  1. In Postra, open Settings and then the Webhooks tab.
  2. Click Add a webhook.
  3. Fill in Name (for you) and URL (your HTTPS address).
  4. In Integrations, choose All integrations or Specific integrations. With specific integrations, pick the channels.
  5. Click Save.
  6. Click Edit on the new webhook. Under Signing secret, click Reveal and copy the secret to your server.

Send Test posts an example message to the URL. On a saved webhook (opened with Edit), the test is signed like a real delivery, so you can try your signature check with it.

To change the name, URL or channels, click Edit. To stop deliveries, click Delete.

Which channels it covers

Setting Gets calls for
All integrations Every channel in the workspace, including channels you connect later
Specific integrations Only the channels you picked

What Postra sends

A POST request with a JSON body. The body is an array. A real delivery holds one post: the one just published. Send Test sends two example posts.

Field Meaning
id The post’s ID in Postra
content The post text. It can contain simple HTML tags such as <p>.
publishDate The time the post was set to go out, ISO 8601 in UTC
releaseURL Link to the live post on the platform
state PUBLISHED
integration.id The channel’s ID in Postra
integration.name The channel’s name
integration.providerIdentifier The platform, for example facebook, instagram or linkedin
integration.picture The channel’s picture
integration.type The kind of channel, for example social

Example:

[
  {
    "id": "POST_ID",
    "content": "<p>Our autumn sale starts today.</p>",
    "publishDate": "2026-10-08T09:30:00.000Z",
    "releaseURL": "https://www.facebook.com/YOUR_PAGE/posts/POST_ON_FACEBOOK",
    "state": "PUBLISHED",
    "integration": {
      "id": "CHANNEL_ID",
      "name": "Your Shop",
      "providerIdentifier": "facebook",
      "picture": "https://example.com/your-page-picture.png",
      "type": "social"
    }
  }
]

The message holds post details only. It never holds passwords or channel tokens.

Headers

Header Value
Content-Type application/json
Postra-Webhook-Id Which of your webhooks sent it. Useful when one URL gets several webhooks.
Postra-Signature t=<time>,v1=<signature>

Check the signature

Each webhook has its own signing secret. It starts with whsec_. Only the workspace owner and Admins can see it.

How the signature is made:

On your server:

  1. Read the raw body exactly as it arrived, before any JSON parsing.
  2. Work out the same HMAC with your secret and compare it with v1. Use a constant-time compare.
  3. Refuse requests where t is more than 5 minutes away from now. This stops someone replaying an old message.

Node.js example with Express:

import express from 'express';
import { createHmac, timingSafeEqual } from 'node:crypto';

const SECRET = process.env.POSTRA_WEBHOOK_SECRET; // YOUR_WEBHOOK_SECRET

function isFromPostra(rawBody, header, secret, toleranceSeconds = 300) {
  if (!header) return false;
  const parts = Object.fromEntries(header.split(',').map((p) => p.split('=', 2)));
  const t = Number(parts.t);
  if (!parts.v1 || !Number.isInteger(t)) return false;
  if (Math.abs(Date.now() / 1000 - t) > toleranceSeconds) return false;
  const expected = createHmac('sha256', secret).update(`${t}.${rawBody}`).digest();
  const given = Buffer.from(parts.v1, 'hex');
  return given.length === expected.length && timingSafeEqual(given, expected);
}

const app = express();

app.post('/postra-webhook', express.raw({ type: 'application/json' }), (req, res) => {
  const rawBody = req.body.toString('utf8');
  if (!isFromPostra(rawBody, req.get('Postra-Signature'), SECRET)) {
    return res.status(400).send('Bad signature');
  }
  const posts = JSON.parse(rawBody);
  for (const post of posts) {
    console.log(post.integration.name, post.releaseURL);
  }
  res.sendStatus(200);
});

app.listen(3000);

New secret

If the secret leaks, open the webhook with Edit and click Generate a new secret. The old secret stops working at once. Update your server straight away, or it will reject the next deliveries.

Timeouts and retries

Answer quickly and do slow work later. If your server is slow, it can get the same post twice. Use the post id to skip ones you already handled.

Limits per plan

Plan Webhooks
Starter 2
Pro 30
Business 10,000

The Webhooks tab shows how many you use, for example Webhooks (1/2).

Paused webhooks

A webhook is paused when the workspace has more webhooks than its plan allows, for example after moving to a smaller plan.

Addresses that are refused

The URL must be a public https:// address. Postra refuses:

Postra checks this when you save the webhook, when you send a test and again before each delivery.