API Reference
Webhooks
Subscribe to events like content published, trend detected, and report generated.
What webhooks deliver
Webhooks give your downstream systems a live feed of content state changes; no polling required. When a post transitions from scheduled to published, when a pipeline run completes, or when weekly analytics are ready, Max Socials fires an HTTP POST to every URL subscribed to that event type. This lets CRMs, dashboards, and automation tools react in real time: trigger a Slack notification the moment a campaign goes live, update a content calendar when a post fails, or kick off a reporting job as soon as fresh analytics land.
Subscribing to webhooks
You can create and manage webhook subscriptions from the dashboard at Settings → Webhooks → Add Endpoint, or programmatically via the REST API:
POST /v1/webhooks
Content-Type: application/json
Authorization: Bearer <your-api-key>
{
"url": "https://your-app.example.com/hooks/maxsocials",
"events": ["post.published", "analytics.weekly_ready"],
"secret": "whsec_your_signing_secret"
}The secret field is optional but strongly recommended; it enables HMAC signature verification (see below). You can subscribe to multiple event types per endpoint. To update or delete a subscription, use PATCH /v1/webhooks/:id or DELETE /v1/webhooks/:id.
Event types
| Event | Fires when… |
|---|---|
post.scheduled | A post is queued for future publication. |
post.published | A post is successfully distributed to all target channels. |
post.failed | A post distribution attempt fails after all retries are exhausted. |
analytics.weekly_ready | Weekly analytics digest is computed and available via API. |
pipeline.run.completed | A content pipeline run finishes (success or error). |
webhook.test | Synthetic test event sent from the dashboard to verify your endpoint. |
Payload shape
Every webhook delivery is a JSON body with this structure:
{
"id": "evt_01HXYZ9AB3CDE456FGH789",
"type": "post.published",
"data": {
"postId": "pst_01...",
"organizationId": "org_01...",
"publishedAt": "2026-04-29T14:32:00Z",
"channels": ["twitter", "linkedin"]
},
"signature": "v1=3d4e5f6a7b8c9d0e...",
"ts": 1745935920
}The id field uniquely identifies each delivery attempt and is stable across retries (see Idempotency below). The signature is also delivered as the X-MaxSocials-Signature HTTP header on the request.
Verifying signatures
Max Socials signs each payload with HMAC-SHA256 using the secret you provided at subscription time. Verify the signature on every incoming request to reject spoofed deliveries:
const raw = await request.text(); // read the raw body; do NOT re-stringify
const expected = "v1=" + createHmac("sha256", secret).update(raw).digest("hex");
const valid = timingSafeEqual(Buffer.from(sig), Buffer.from(expected));Always read the raw request body and compute the HMAC over that exact string. Re-parsing to JSON and then re-stringifying changes whitespace and key order, which breaks the signature check (see Gotchas).
Retry semantics
If your endpoint returns a non-2xx HTTP status (or times out after 10 seconds), Max Socials retries with exponential backoff:
| Attempt | Delay after previous failure |
|---|---|
| 1 (initial) | N/A |
| 2 | 10 seconds |
| 3 | 30 seconds |
| 4 | 90 seconds |
| 5 | 5 minutes |
| 6 (final) | 30 minutes |
After 5 failed attempts the event moves to a dead-letter queue. You can inspect and replay dead-lettered events from Settings → Webhooks → Dead Letters or via POST /v1/webhooks/dead-letters/:id/replay. Return a 2xx status quickly; do heavy processing asynchronously.
Idempotency
The same event id is reused across all retry attempts. Because network failures can cause your endpoint to process a delivery successfully without returning a clean 2xx, your consumer must deduplicate by id. Store processed event IDs in a cache or database and skip any event whose ID you have already handled.
Common gotchas
Signature mismatch on body re-encoding
The most common verification failure is computing the HMAC over a re-serialized body instead of the raw bytes. JSON serializers differ on key ordering, whitespace, and Unicode escaping. Always buffer the raw request body before any parsing. In Node.js, use request.text() or express.raw({ type: '*/*' }) before express.json() runs on that route.
Replaying events during development
Use the webhook.test event from the dashboard to fire a synthetic payload to your local tunnel without touching real post data. The test payload follows the same shape and signing rules as live events, so your verification code runs the same path.
Ready to get started?
Join the early access list and get priority onboarding with your dedicated Max Socials implementation team.
Get early access