Skip to content
DocsReference

Webhooks

Subscribe a URL to receive real-time events when posts are published, partially published or fail. We sign every delivery with HMAC-SHA256 so you can verify the request came from us.

Event types

EventFires when
post.queuedPost has been accepted and tasks enqueued.
post.publishedAll platforms succeeded (also emitted per platform).
post.partialAt least one platform succeeded and at least one failed.
post.failedEvery targeted platform failed, or a single platform terminally failed.
account.connectedUser connected a platform account.
account.disconnectedUser disconnected a platform account.

Register a webhook

POST /v1/webhooks

curl https://api.letspost.it/v1/webhooks \
  -H "Authorization: Bearer $LETSPOST_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://your.app/letspost/webhook",
    "events": ["post.published","post.failed","post.partial"]
  }'

The response includes a secret — save it. Use it to verify every future delivery.

Delivery format

HTTP
POST https://your.app/letspost/webhook
Content-Type: application/json
X-letspost.it-Event: post.published
X-letspost.it-Signature: sha256=<hex-hmac>

{
  "id":        "evt_1abcd23_4ef5",
  "type":      "post.published",
  "createdAt": "2026-04-16T20:30:01.000Z",
  "data":      { "postId": "pst_1", "published": 3, "failed": 0, "total": 3 }
}

Verify the signature

import express from 'express';
import crypto from 'node:crypto';

const app = express();
// Use the raw body — json parsing changes whitespace and breaks the HMAC.
app.post('/letspost/webhook', express.raw({ type: 'application/json' }), (req, res) => {
  const header = req.header('X-letspost.it-Signature') || '';
  const presented = header.replace(/^sha256=/, '');
  const expected = crypto
    .createHmac('sha256', process.env.SOCIALHUB_WEBHOOK_SECRET)
    .update(req.body)
    .digest('hex');

  if (!crypto.timingSafeEqual(Buffer.from(presented), Buffer.from(expected))) {
    return res.status(401).end();
  }

  const event = JSON.parse(req.body.toString());
  console.log(event.type, event.data);
  res.status(200).end();
});

Retries & idempotency

  • Return a 2xx within 5s. Non-2xx or timeout is treated as failure.
  • We do not retry failed deliveries today — add your own queue if you need strict delivery guarantees (see roadmap). event.id
  • Deduplicate on event.id — it is unique per delivery.

Listing & revoking

GET /v1/webhooks lists your webhooks. DELETE /v1/webhooks/{id} removes one.

Get an endpoint

GET /v1/webhooks/{id}

Returns one webhook endpoint you own.

curl https://api.letspost.it/v1/webhooks/wh_123 \
  -H "Authorization: Bearer $LETSPOST_KEY"

Update an endpoint

PATCH /v1/webhooks/{id}

Partial update of events, secret, headers, or active. The URL is immutable.

curl -X PATCH https://api.letspost.it/v1/webhooks/wh_123 \
  -H "Authorization: Bearer $LETSPOST_KEY" \
  -H "Content-Type: application/json" \
  -d '{"events":["post.published","account.disconnected"],"active":true}'

Regenerate the signing secret

POST /v1/webhooks/{id}/regenerate-secret

Rotates the HMAC signing secret and returns the new plaintext once — store it immediately.

curl -X POST https://api.letspost.it/v1/webhooks/wh_123/regenerate-secret \
  -H "Authorization: Bearer $LETSPOST_KEY"

Send a test event

POST /v1/webhooks/{id}/test

Fires a signed webhook.test event at the endpoint so you can validate your subscriber URL. It shows up under deliveries alongside real events.

curl -X POST https://api.letspost.it/v1/webhooks/wh_123/test \
  -H "Authorization: Bearer $LETSPOST_KEY"

List deliveries

GET /v1/webhooks/{id}/deliveries

Cursor-paginated delivery records for one endpoint, newest first. limit is 1–100 (default 25).

curl "https://api.letspost.it/v1/webhooks/wh_123/deliveries?limit=25" \
  -H "Authorization: Bearer $LETSPOST_KEY"
JSON
{
  "deliveries": [
    {
      "id": "dl_456",
      "event": "post.published",
      "status": "delivered",
      "responseStatus": 200,
      "attempts": 1,
      "createdAt": "2026-04-16T20:30:01.000Z"
    }
  ],
  "nextCursor": null
}

Inspect a delivery

GET /v1/webhooks/{id}/deliveries/{deliveryId}

Returns one delivery record with its per-attempt history.

curl https://api.letspost.it/v1/webhooks/wh_123/deliveries/dl_456 \
  -H "Authorization: Bearer $LETSPOST_KEY"

Replay a delivery

POST /v1/webhooks/{id}/deliveries/{deliveryId}/replay

Re-sends a past delivery's payload to the endpoint using the current signing context.

curl -X POST https://api.letspost.it/v1/webhooks/wh_123/deliveries/dl_456/replay \
  -H "Authorization: Bearer $LETSPOST_KEY"
Was this page helpful?

Something unclear? Email us — we read every message.