REST API
Webhooks
Get a signed HTTPS request the moment something happens in PostNinja: a post goes out or fails, a teammate submits a post for approval, an account needs reconnecting, a comment arrives. Ideal for n8n, Zapier, Make, Slack alerts or your own backend.
Set up an endpoint
- Add the URL under Settings → API → Webhooks, or with
POST /api/v1/webhooks. It must be a publichttps://address. Up to 10 per workspace. - Pick the events you want, or leave it empty for all of them.
- Copy the signing secret (
whsec_…). It's shown once; you can rotate it in Settings. - Click Send test event: PostNinja sends one
webhook.testso you can check your receiver and its signature check.
Events
| Event | When | In data |
|---|---|---|
post.created | Posts: Created (draft or waiting) | post; status (draft or awaiting_approval) |
post.scheduled | Posts: Scheduled | post; status |
post.updated | Posts: Changed | post; status |
post.rescheduled | Posts: Moved to a new time | post |
post.deleted | Posts: Deleted | postId only (the post is gone) |
post.retried | Posts: Retried | post |
post.published | Posts: Published | post (every target published, with links) |
post.partial | Posts: Partly published | post (see each target's status and error) |
post.failed | Posts: Failed | post (see each target's error) |
post.submitted | Approvals: Submitted for approval | post |
post.approved | Approvals: Approved | post; note if one was left; profileId when approved from a client review link |
post.changes_requested | Approvals: Changes requested | post; note; profileId when sent back from a client review link |
account.connected | Accounts: Connected | accountId, platform, username |
account.disconnected | Accounts: Disconnected | accountId, platform |
account.needs_reconnect | Accounts: Needs reconnecting | accountId, platform, username, note (why) |
member.joined | Team: Member joined | role |
comment.received | Comments: New comment | accountId, platform, inboxItemId, author, text (first 280 characters), reply, permalink, and post when it's on a post from PostNinja |
message.received | Direct messages: New message | accountId, platform, conversationId, messageId, from (username or name), text (first 280 characters), attachments (how many) |
message.sent | Direct messages: Reply sent from PostNinja | accountId, platform, conversationId, messageId, to, text (first 280 characters); sent from PostNinja by a person or through the API |
Post events carry the post exactly as GET /api/v1/posts/:id returns it, in data.post. When many comments or messages arrive at once, comment.received and message.received send one summary instead (count, platforms, summary: true).
The request
| Header | Value |
|---|---|
Content-Type | application/json |
PostNinja-Event | The event name, e.g. post.published. |
PostNinja-Delivery | This attempt's id. A redelivery gets a new one; the body's id stays the same. |
PostNinja-Signature | t=<unix seconds>,v1=<hex HMAC-SHA256> |
Verify the signature
v1 is the HMAC-SHA256 of {t}.{raw body} with your endpoint's secret, in hex. Compute it over the raw body exactly as received (before parsing JSON), compare in constant time, and reject requests whose t is more than 5 minutes old.
Retries and switching off
- Answer with any 2xx status within 10 seconds. Do slow work after answering.
- Anything else is retried after 1 min, 5 min, 30 min, 2 h, 6 h, 12 h, 24 h; after that the delivery is marked failed.
- After 50 failed attempts in a row, the endpoint is switched off and the workspace owner gets an email. Switch it back on in Settings; that resets the count.
- Deliveries can arrive more than once or out of order. Use the body's
idto skip events you've handled, andcreatedAtto order them. - Settings shows each endpoint's recent deliveries (status code and the start of your answer) and can Redeliver any of them. History is kept 30 days.
No-code tools
In n8n, Zapier or Make, create a webhook trigger, paste its URL as the endpoint, and choose the events. To verify signatures there, compute the HMAC in a code step with the raw body; if your tool only gives you parsed JSON, keep the URL secret instead and check the event by fetching the post with the REST API.