Stop polling .
Subscribe to 8 lifecycle events with one POST. Webhooks land on your endpoint within median 800ms of each transition. HMAC-SHA256 signatures with per-endpoint secrets. Replay-safe with explicit retry budget and a dead-letter queue. Same envelope shape as the HTTP API.
{
"url": "https:x0
"events": [
"post.queued",
"post.published",
"post.failed",
"token.expiring"
]
} Polling GET /v1/posts/:id
- You eat your own rate limit just to check status
- Latency = whatever your poll interval is
- Wastes compute on the 99% of polls that are no-change
- No signal for token expiry, version deprecations, quota walls
- You write the backoff logic yourself
- Multi-target posts: N status calls per publish
letmepost Webhooks
- Push delivery, median 800ms from event to your endpoint
- Zero polling overhead, zero rate-limit hits
- HMAC-signed payloads with per-endpoint secret rotation
- Lifecycle, token, version, quota events all on one channel
- Exponential retry built in, then DLQ as last resort
- One event per state transition, no duplicate-busy work
✓ Same envelope as the HTTP API
Webhook payloads carry the same fields you'd get from a synchronous response: id, status, error, request_id. You can grep webhooks the same way you grep logs.
EVENT TYPES
DELIVERY MODEL
Event fires
Payload built, signature computed with your per-endpoint secret. Stamped with X-LMP-Signature + X-LMP-Timestamp headers. Median latency before first POST: ~50ms.
Delivery attempt 1
We POST to your endpoint. Success = HTTP 2xx within 10s. Anything else is a failure: timeout, 4xx, 5xx, connection refused.
Retry on failure
Exponential backoff: 30s, 2min, 10min, 30min, 2h, 6h. Six attempts over ~9 hours. Each carries the same payload, signature, and request id.
DLQ after exhaustion
Six failed attempts: delivery moves to your endpoint's dead-letter queue. Inspect via the dashboard or POST /v1/webhook-endpoints/:id/replay/:event_id.
FEATURES
8 event types
post.queued, post.validated, post.published, post.failed, post.rejected, token.expiring, token.revoked, version.deprecated.
HMAC-SHA256 signatures
Per-endpoint secret. Signature computed over timestamp.body. Verify with timingSafeEqual to avoid timing attacks. Replay-window enforcement built in.
Exponential retry
Six attempts over ~9h on failure: 30s, 2min, 10min, 30min, 2h, 6h. Each retry carries the same payload + signature.
Dead-letter queue
After retries exhaust, delivery lands in DLQ. 7-day inspection on Pro, 30-day on Business. Replay any event manually.
Per-endpoint secret rotation
POST /v1/webhook-endpoints/:id/rotate-secret. Old secret stays valid for 12 hours so you can roll your handler without dropping deliveries.
Verify helper in the SDK
The TS + Python SDKs ship a verifyWebhook() helper that checks signature + timestamp window. Drop into Express, Fastify, FastAPI in two lines.
CODE EXAMPLE
import { createHmac, timingSafeEqual } from 'node:crypto'; // Verify HMAC-SHA256 over `timestamp.body` against the X-LMP-Signature // header. Use timingSafeEqual to avoid timing-attack signal leakage. function verifyLetmepostWebhook(req, secret) { const sig = req.headers['x-lmp-signature'] as string; const ts = req.headers['x-lmp-timestamp'] as string; // Replay window — reject anything older than 5 min const age = Math.abs(Date.now() / 1000 - parseInt(ts, 10)); if (age > 300) return false; const expected = createHmac('sha256', secret) .update(`${ts}.${req.rawBody}`) .digest('hex'); return timingSafeEqual(Buffer.from(expected), Buffer.from(sig)); } app.post('/lmp-webhook', (req, res) => { if (!verifyLetmepostWebhook(req, process.env.LMP_WEBHOOK_SECRET)) { return res.status(401).end(); } const event = JSON.parse(req.rawBody); switch (event.type) { case 'post.published': /* update your UI */ break; case 'post.failed': /* notify the user */ break; case 'token.expiring': /* prompt re-auth */ break; } res.status(200).end(); });
Webhook delivery reference
Every event payload schema, every header, every retry rule. Plus the verify-helper source.
COMMON QUESTIONS
How fast do webhooks arrive?
Median 800ms from event firing to your endpoint receiving the POST. P95 under 3s. Long-tail bounded by upstream platform latencies (e.g. Meta video transcoding).
What if my endpoint is down?
We retry on exponential backoff: 30s, 2min, 10min, 30min, 2h, 6h. Six attempts over ~9h. Then the delivery lands in DLQ where you can replay it manually.
Do I need a separate endpoint per event?
No. One endpoint can subscribe to all 8 events. You dispatch on event.type in your handler. But you can subscribe multiple endpoints if you want to route events to different services.
How do I rotate a webhook secret?
POST /v1/webhook-endpoints/:id/rotate-secret. Old secret stays valid for 12 hours after rotation so you can roll your handler without dropping deliveries.
Are webhooks counted against my quota?
No. Webhook deliveries are free, unlimited, and don't consume any post-quota units. We only meter writes you initiate.
Can I replay events from the past?
Yes on Pro and Business: replay any event from the last 7 days (Pro) or 30 days (Business) via the dashboard or POST /v1/webhook-endpoints/:id/replay.
How big can payloads get?
Typical payload is 2–4 KB. Maximum 16 KB. Embedded raw upstream responses are truncated past the cap; the full body is always available via GET /v1/posts/:id.
OTHER SURFACES
LEARN MORE
READY TO SUBSCRIBE?
One POST. Eight event types. Stop polling, start listening.