Webhooks
HMAC-signed outbound events, exponential-backoff retries, daily delivery log. Wire Post Mate into your own pipelines.
Webhooks let you subscribe to events on your Post Mate workspace — when a post publishes, when it fails, when a new account is connected — without polling our API.
Manage webhooks at /app/settings/api under the Webhooks tab.
How it works
You give us:
- A target URL (HTTPS, must respond within 10 seconds)
- A list of event types to subscribe to
- An optional secret for HMAC-SHA256 signing
We send a POST to that URL when matching events fire. The body is JSON; the headers include signature + timestamp for verification.
Event types
| Event | Fires when |
|---|---|
post.created | A post is created (in any status) |
post.scheduled | A post moves to status scheduled |
post.published | A post successfully publishes to a network |
post.failed | A post fails to publish after retries |
post.cancelled | A scheduled post is cancelled |
account.connected | A new social account is connected |
account.disconnected | A social account is disconnected |
A single post fanning out to four networks generates four
post.published events (or a mix of published / failed), each
with its own platform identifier.
Payload shape
{
"id": "evt_01HSXJ…",
"type": "post.published",
"workspace_id": "ws_01HSXG…",
"created_at": "2026-06-01T09:00:03.124Z",
"data": {
"post_id": "post_01HSXF…",
"platform": "instagram",
"external_id": "17912345678901234",
"external_url": "https://www.instagram.com/p/abc123/",
"scheduled_at": "2026-06-01T09:00:00Z"
}
}Signing
If you set a secret, every webhook request includes:
X-PostMate-Timestamp: 1717228803
X-PostMate-Signature: sha256=2af1b34cf5...To verify:
import crypto from 'node:crypto';
function verify(rawBody: string, headers: Headers, secret: string): boolean {
const timestamp = headers.get('x-postmate-timestamp')!;
const signature = headers.get('x-postmate-signature')!.replace('sha256=', '');
const expected = crypto
.createHmac('sha256', secret)
.update(`${timestamp}.${rawBody}`)
.digest('hex');
// Use timingSafeEqual to avoid timing-attack leaks.
return crypto.timingSafeEqual(
Buffer.from(expected, 'hex'),
Buffer.from(signature, 'hex'),
);
}Reject requests where the timestamp is more than 5 minutes old — that's the replay-protection window.
Retries
Failed deliveries (non-2xx response, timeout, network error) retry with exponential backoff:
- Attempt 1: immediate
- Attempt 2: after 1 minute
- Attempt 3: after 5 minutes
- Attempt 4: after 25 minutes
- Attempt 5: after 2 hours
After 5 failed attempts, we stop retrying and mark the delivery as permanently failed. The event is still visible in the delivery log so you can manually re-fire if needed.
Delivery log
Every webhook send shows up in your dashboard with:
- Event ID and type
- Target URL
- HTTP status returned
- Response body (first 500 chars)
- Duration
- Next retry time (if pending)
The log keeps 30 days of history.
Local development
For testing webhooks against localhost, use ngrok
or Cloudflare Tunnel to expose your local server. Then point a Post
Mate webhook at the tunnel URL. Both tools give you stable URLs that
survive across sessions on their paid tiers.
Cost
Webhooks are included in the same $5/mo API add-on as the REST API and MCP. There's no per-event charge — you can subscribe to every event type and we'll deliver them.