Webhooks

Webhooks allow your application to receive real-time HTTP POST notifications about events happening on the Elixpo Accounts platform (e.g. user signup, oauth app deletion).

Supported Events

You can configure webhook subscriptions in the Developer Portal for any of the following event types:

Event CodeDescription
user.createdTriggered when a new user registers on the platform.
user.updatedTriggered when user profile data or username is updated.
user.deletedTriggered when a user deletes their account. Register a webhook_url and subscribe to this to purge the user's data and stop any billing — e.g. Elixpo Pay cancels their subscriptions and revokes entitlements on this event.
auth.login_successTriggered on a successful user login.
auth.login_failedTriggered on a failed login attempt (suspicious activity tracker).
oauth.app_createdTriggered when a new developer registers an OAuth application.

Payload Format

All webhook deliveries send a JSON POST request containing standard fields:

{
  "id": "evt_7f1c1a2b3c4d",
  "event": "user.created",
  "createdAt": "2026-06-07T18:48:21.000Z",
  "data": {
    "id": "u_9b7bf7c2-866e-ee9d-3e48-ee9d3e488297",
    "email": "newuser@example.com",
    "displayName": "swift-falcon",
    "createdAt": "2026-06-07T18:48:20.000Z"
  }
}

Signature Verification

Every webhook request includes an X-Webhook-Signature header. This is a hex-encoded HMAC SHA256 signature calculated from the raw string payload body and your webhook signing secret.

Always verify this signature using a constant-time comparison helper (like Node's crypto.timingSafeEqual) before processing.

const crypto = require("crypto");

app.post("/webhook-endpoint", (req, res) => {
  const signature = req.headers["x-webhook-signature"];
  const rawBody = JSON.stringify(req.body); // Ensure you have access to the raw payload string
  const webhookSecret = process.env.WEBHOOK_SECRET;

  if (!signature) {
    return res.status(401).send("Missing signature");
  }

  // Generate expected signature
  const expectedSignature = crypto
    .createHmac("sha256", webhookSecret)
    .update(rawBody)
    .digest("hex");

  // Constant-time comparison to prevent timing attacks
  const isValid = crypto.timingSafeEqual(
    Buffer.from(signature),
    Buffer.from(expectedSignature)
  );

  if (!isValid) {
    return res.status(403).send("Invalid signature");
  }

  // Handle the verified webhook event...
  console.log("Verified event:", req.body.event);
  res.status(200).send("OK");
});

Delivery & Retry Policy

Your server must respond with a status code in the 2xx range within 5 seconds to mark a delivery as successful. If the delivery fails (e.g. timeout or non-2xx status), the webhook system will retry up to 5 times with an exponential backoff spacing.