Skip to main content

Overview

Webhooks let your server receive HTTP POST callbacks when events occur in SmartlyQ — like a job completing or a social post being published.

Setting up webhooks

  1. Go to the Developer Dashboard
  2. Navigate to the Webhooks tab
  3. Add an endpoint URL (must be HTTPS)
  4. Select the events you want to receive

Payload format

All webhook payloads are JSON:
{
  "event": "job.completed",
  "timestamp": "2026-03-02T14:30:00Z",
  "data": {
    "job_id": "job_abc123",
    "type": "article_generation",
    "status": "completed",
    "result": { ... }
  }
}

Verifying signatures

Every delivery is signed. Two headers accompany each request:
  • X-SmartlyQ-Signaturet=<timestamp>,v1=<hmac>, where <hmac> is the HMAC-SHA256 of <timestamp>.<raw-body> keyed with your webhook secret.
  • X-SmartlyQ-Event — the event name (e.g. job.completed).
Compute the HMAC over the timestamp and the raw request body joined with a ., then compare it against v1:
const crypto = require("crypto");

// rawBody = the exact bytes of the request body (do not re-serialize the JSON)
function verifySignature(rawBody, signatureHeader, secret) {
  const parts = Object.fromEntries(
    signatureHeader.split(",").map((kv) => kv.split("="))
  );
  const expected = crypto
    .createHmac("sha256", secret)
    .update(`${parts.t}.${rawBody}`)
    .digest("hex");
  return crypto.timingSafeEqual(
    Buffer.from(parts.v1),
    Buffer.from(expected)
  );
}
Always verify the signature before processing a webhook. Unverified payloads may be spoofed. The signing secret is shown once, when you add the endpoint in the dashboard.

Retry policy

If your endpoint returns a non-2xx status code, SmartlyQ retries delivery up to 5 times with exponential backoff — the wait doubles each attempt (≈2, 4, 8, 16, 32 minutes). Deliveries still failing after the final attempt are dropped.

Available events

EventTrigger
job.completedAn async job finished successfully
job.failedAn async job failed
social.postedA social media post was published
social.failedA social media post failed to publish
chatbot.messageA chatbot received a visitor message
wallet.lowWallet balance dropped below threshold