Events

Every webhook event FoPost can send, when it fires, and its payload.

Nineteen events, in six families. Subscribe to delivery.* when you want per-account granularity, post.* when you only care about the overall outcome. Subscribing to both means two notifications for the same publish, which is fine as long as your handler expects it.

Posts

EventFires when
post.scheduledA post was put on the calendar, by hand, by an approval, by a bulk import or by an automation. Rescheduling fires it again
post.publishedEvery account on the post published successfully
post.partially_failedSome accounts published, some did not
post.failedNo account published (failed and cancelled deliveries both count)
post.deletedA post was deleted. Any delivery still pending was cancelled with it

The three outcome events fire once per post, when every account has a final status. data carries the post and its status:

{ "postId": "7d2b8c11-…", "status": "published" }

post.scheduled adds scheduleAt; post.deleted carries only postId.

Delivery outcomes

One event per account on the post.

EventFires when
delivery.publishedOne account published. Fires once per account
delivery.failedOne account will not publish, after its retries, or immediately when the failure is final, such as expired credentials or an error the platform will never accept
delivery.delayedOne delivery was held by a platform rate limit and will retry at retryAt

delivery.published data:

{ "postId": "…", "postAccountId": "…", "accountId": "…", "platform": "linkedin", "externalUrl": "https://…" }

externalUrl is the live post when the platform reports one, and null when it does not.

delivery.failed swaps externalUrl for errorCode and errorMessage; delivery.delayed carries reason: "platform_rate_limit", a message, and retryAt. Ordinary retry backoff between attempts does not emit delivery.delayed; only a platform rate limit does.

Accounts

EventFires when
account.connectedA social account was connected to the workspace
account.disconnectedA social account was disconnected
account.health_changedA connected account's credential health changed: degraded, expired, revoked, or recovered

account.connected and account.disconnected carry the account:

{ "accountId": "…", "platform": "instagram", "username": "yourbrand" }

account.health_changed adds the transition:

{ "accountId": "…", "platform": "instagram", "username": "yourbrand", "previousStatus": "healthy", "newStatus": "expired" }

This is the one worth wiring even if you skip the rest. It is how you learn a token died before a scheduled post silently fails. It fires on recovery too, so you can close the alert it opened. When the change comes from a failed token refresh rather than a health check, the payload carries a reason instead of a username.

Articles

EventFires when
article.publishedA blog article was published to its target: a connected account, your website, or the product blog

Unlike the other events, data carries the whole article, so a website can store it without a follow-up GET:

{
  "id": "b41e7c05-9d38-4a2f-8e60-1c7d5b3a9f24",
  "title": "A Marathon Training Plan for First-Time Runners",
  "slug": "marathon-training-plan-for-first-time-runners",
  "excerpt": "Sixteen weeks, three runs a week, and one long run that grows slowly.",
  "metaTitle": "Marathon Training Plan for Beginners (16 Weeks)",
  "metaDescription": "A sixteen-week marathon plan for first-time runners.",
  "bodyMarkdown": "## Why sixteen weeks\n\n...",
  "bodyHtml": "<h2>Why sixteen weeks</h2><p>...</p>",
  "featuredImage": { "mediaId": "6b0e9a4c-…", "url": "https://…", "alt": "A runner lacing shoes at dawn" },
  "images": [{ "mediaId": "9c2f7b31-…", "url": "https://…", "alt": "A weekly mileage chart", "position": 2 }],
  "tags": ["marathon", "training"],
  "keyword": "marathon training plan for beginners",
  "wordCount": 1540,
  "publishedAt": "2026-10-14T07:00:00.000Z",
  "publishedUrl": "https://yourbrand.com/blog/marathon-training-plan-for-first-time-runners"
}

excerpt, metaTitle, metaDescription, featuredImage, keyword and publishedUrl are null when there is nothing to put in them. position on an in-body image is the index of the outline heading it sits under; the featured image has none. bodyMarkdown references the same image URLs inline.

Image URLs expire after 6 hours. Download each image and store your own copy when the event arrives; a URL kept past that window stops working.

The Website target POSTs this same envelope straight to the URL in your blog settings, signed with its own secret, and sends article.test from the settings page. The receiving guide covers that receiver.

Inbox

One event per new inbound item, as the inbox poll picks it up. Your own replies never fire one.

EventFires when
inbox.comment_receivedSomeone commented on one of your posts
inbox.mention_receivedSomeone mentioned one of your accounts
inbox.message_receivedA direct message arrived
inbox.review_receivedA review or Page recommendation arrived
inbox.reply_sentA reply you sent from the inbox reached the platform
{ "itemId": "…", "type": "comment", "platform": "instagram", "accountId": "…", "receivedAt": "2026-09-01T09:00:12.000Z" }

inbox.reply_sent carries the same ids plus replyId (the platform's id for your reply) and sentAt instead of receivedAt.

The payload is ids only. Fetch the item from the inbox for its text and author, so nothing a customer wrote sits in your webhook logs. Building a bot on inbox.message_received? The chat adapter does the verify-and-fetch half for you.

Automations

EventFires when
automation.triggeredA run started
automation.completedA run finished every step
automation.failedA run stopped on an error
{ "automationId": "…", "runId": 4821, "totalSteps": 3 }

automation.triggered carries automationId and runId; automation.completed adds totalSteps; automation.failed adds error.

The envelope

Every delivery is the same three-key body:

{ "event": "<name>", "data": { … }, "timestamp": "<ISO 8601>" }

timestamp is when the event was queued. The delivery id lives in the X-FoPost-Delivery header. Deduplicate on that, since a retried delivery repeats the identical body. Ids in data are the same public ids the API uses, so a webhook payload can be followed with a GET.

Next

Related documentation
  • Webhooks

    Hear about publishing outcomes and account health without polling.

  • Verifying Signatures

    Prove a delivery came from FoPost before acting on it.

  • Retries and Failures

    Timeouts, retry backoff, auto-disable, and test deliveries.

  • Blog

    A keyword plan, articles written in the background, a review window, and a target they publish to.

  • Receiving Blog Articles

    Publish FoPost articles on your own site, whatever it is built with.

  • Inbox

    Comments, mentions and reviews from every connected account, in one list.

  • Chat Adapter

    Plug the FoPost inbox into a chatbot framework as one send/receive channel.

  • API Overview

    Base URL, envelopes, pagination, and errors for the FoPost REST API.

Was this helpful?

On this page