eWeWasl Docs

Webhooks

Subscribe to post lifecycle events via HTTPS webhooks with HMAC-signed payloads.

Webhooks let your application receive real-time notifications when a post moves through the publishing pipeline — without polling GET /api/v1/posts.

Endpoints

MethodPathTool / scope
GET/api/v1/webhookslist_webhooks · posts:read
POST/api/v1/webhooksregister_webhook · posts:create
DELETE/api/v1/webhooks/{id}delete_webhook · posts:create

All endpoints require Authorization: Bearer ewasl_... and a Pro+ plan.

Events

EventFires when
post.publishedEvery platform succeeded.
post.partially_publishedAt least one platform succeeded, at least one failed.
post.failedEvery platform failed.
post.scheduledA new scheduled post is queued.

Register

curl -X POST https://app.ewasl.com/api/v1/webhooks \
  -H "Authorization: Bearer ewasl_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://example.com/hooks/ewasl",
    "events": ["post.published", "post.failed"],
    "description": "Production webhook"
  }'

The URL must be HTTPS (HTTP endpoints are rejected). You can subscribe to multiple events per endpoint, or register multiple endpoints.

Payload shape

Every event POST carries a JSON body:

{
  "id": "evt_01H...",
  "type": "post.published",
  "createdAt": "2026-04-22T23:58:01.123Z",
  "data": {
    "post": {
      "id": "p_01H...",
      "status": "PUBLISHED",
      "publishedAt": "2026-04-22T23:58:00.987Z",
      "results": [
        {
          "platform": "TWITTER",
          "success": true,
          "externalPostId": "1842...",
          "externalUrl": "https://x.com/eWasl/status/1842..."
        }
      ]
    }
  }
}

For post.partially_published and post.failed, the results array contains one entry per attempted platform with success: false and error populated.

Verifying signatures

Each request includes an HMAC signature header:

X-eWasl-Signature: t=1714000000,v1=5e8a...

Validate it before trusting the payload. (The shared secret is generated when you register the webhook and shown once in the response.)

import crypto from 'node:crypto';
 
function verify(rawBody: string, signatureHeader: string, secret: string) {
  const parts = Object.fromEntries(
    signatureHeader.split(',').map((kv) => kv.split('=') as [string, string]),
  );
  const expected = crypto
    .createHmac('sha256', secret)
    .update(`${parts.t}.${rawBody}`)
    .digest('hex');
  return crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(parts.v1));
}

Reject requests where Math.abs(now - parts.t) > 300 seconds to prevent replay attacks.

Retries

If your endpoint returns a non-2xx response, eWasl retries with exponential backoff: 1m, 5m, 30m, 2h, 12h. After the 5th failure, the webhook is auto-disabled and failure_count is exposed via GET /api/v1/webhooks so you can re-enable it once you've fixed the receiver.

Local development

Use smee.io or ngrok to forward HTTPS webhook traffic to a local server during development.

On this page