Know the moment a post lands, or does not
Register a URL once and FoPost calls it whenever a delivery settles. Each event carries the post id, the account, the platform, the permalink, or the error text, so your system reacts without polling.
curl -X POST https://api.fopost.com/v1/webhooks \
-H "X-API-Key: $API_KEY" \
-H "Content-Type: application/json" \
-d '{
"workspaceId": "9b2f6c1e-...",
"url": "https://yourbrand.com/hooks/social",
"events": ["post.published", "post.failed"]
}'Fires on settle
One event per account delivery, sent as soon as the network confirms or rejects.
Signed
Every request carries a signature header so you can verify it came from us.
Retried
A non-2xx response is retried with backoff before the event is dropped.
Two events cover the whole publish lifecycle
post.published fires when a network accepts a delivery and includes the external id and permalink. post.failed fires when retries are exhausted and includes the platform’s error text. Because a post fans out per account, you get one event per network.
Read the webhook reference{
"event": "post.published",
"postId": "post_01j8...",
"workspaceId": "9b2f6c1e-...",
"delivery": {
"accountId": "4a71d80b-...",
"platform": "linkedin",
"status": "delivered",
"externalId": "urn:li:share:7301...",
"externalUrl": "https://linkedin.com/feed/update/..."
},
"occurredAt": "2026-09-01T09:00:07Z"
}post.published
Permalink and external id, ready to store or link back from your CMS.
post.failed
The network’s own error message, so you can fix the cause, not guess.
Per workspace
A webhook belongs to one workspace and only sees that workspace’s posts.
Trust the payload before you act on it
Each request is signed with the secret returned when you create the webhook. Compute the signature over the raw body, compare it with the header, and reject anything that does not match. Respond 2xx quickly and do the work afterward.
See signature verificationapp.post('/hooks/social', async (req, res) => {
const signature = req.header(SIGNATURE_HEADER) // header name is in the docs;
if (!verify(req.rawBody, signature, process.env.WEBHOOK_SECRET)) {
return res.status(401).end();
}
const { event, postId, delivery } = req.body;
await queue.add(event, { postId, delivery });
res.status(200).end();
});Signature header
Verify with the secret you were given at creation. Rotate by recreating.
Timestamped
occurredAt lets you ignore stale replays and order events correctly.
Idempotent by id
Retries carry the same event id, so a double delivery is easy to drop.
Create, list, and remove endpoints from code
Webhooks are plain API objects. Create one per environment, list them to audit what is registered, and delete the ones you no longer need. Point them at a staging URL during development and swap to production with one call.
Start building
List endpoints
GET /v1/webhooks shows every URL and the events it subscribes to.
Per environment
Register a separate URL for staging so test posts never hit production.
webhooks scope
Managing endpoints needs its own scope. A publish-only key cannot add one.
Webhooks questions, answered
Which events are available?
How do I verify a webhook?
What if my endpoint is down?
Can I receive events for one account only?
Can I test without publishing for real?
Do I need webhooks at all?
Build on the Webhooks today
Starting is free and the full API is included. Create a key and make your first call in minutes.
Get your API key