SeloraXDEVELOPERS

Webhooks API

Webhooks API

Manage webhook subscriptions for your app. Webhooks allow your app to receive real-time HTTP POST notifications when events occur in a store (orders, products, customers, billing, etc.).

For details on webhook payload format, signature verification, and best practices, see the Webhooks guide.

Valid Event Topics

The following event topics are available for subscription:

TopicDescription
order.createdA new order is placed
order.updatedAn order is modified
order.status_changedAn order's status transitions (e.g. pending to confirmed)
product.createdA new product is added
product.updatedA product is modified
product.deletedA product is removed
customer.createdA new customer account is created
customer.updatedA customer record is modified
app.installedYour app is installed on a store
app.uninstalledYour app is uninstalled from a store
inventory.updatedStock levels change for a product variant
charge.createdA billing charge is created
charge.activatedA charge is approved and payment collected
charge.declinedA charge is declined by the merchant
charge.cancelledA charge is cancelled
charge.expiredA charge expired without merchant action
charge.payment_failedPayment collection failed for a charge
subscription.renewal_pendingA recurring subscription renewal is upcoming
customers/data_requestGDPR: Customer requests personal data export
customers/redactGDPR: Customer requests data deletion
shop/redactGDPR: Store deletion, all data to be redacted

:::note Billing and GDPR topics The billing/subscription topics (charge.*, subscription.*) and GDPR compliance topics (customers/*, shop/*) are only available for app-created webhook subscriptions via this API. Merchant-created webhooks from the dashboard do not support these topics. :::


List Webhook Subscriptions

Retrieve all webhook subscriptions for your app on the current store.

GET /api/apps/v1/webhooks

Authentication

Required. Must include valid app credentials (via Bearer token or client credentials).

Scope

No specific scope required beyond app authentication.

Query Parameters

None.

Example Request

curl -X GET "https://api.selorax.io/api/apps/v1/webhooks" \
  -H "Authorization: Bearer <token>"

Or using client credentials:

curl -X GET "https://api.selorax.io/api/apps/v1/webhooks" \
  -H "X-Client-Id: sx_app_..." \
  -H "X-Client-Secret: sx_secret_..." \
  -H "X-Store-Id: 22"

Response

{
  "data": [
    {
      "subscription_id": 15,
      "event_topic": "order.created",
      "target_url": "https://myapp.com/webhooks/orders",
      "is_active": true,
      "failure_count": 0,
      "last_failure_at": null,
      "last_success_at": "2025-06-15T14:30:00.000Z",
      "created_at": "2025-06-01T00:00:00.000Z"
    },
    {
      "subscription_id": 16,
      "event_topic": "order.status_changed",
      "target_url": "https://myapp.com/webhooks/orders",
      "is_active": true,
      "failure_count": 2,
      "last_failure_at": "2025-06-14T10:00:00.000Z",
      "last_success_at": "2025-06-15T14:30:00.000Z",
      "created_at": "2025-06-01T00:00:00.000Z"
    },
    {
      "subscription_id": 17,
      "event_topic": "product.updated",
      "target_url": "https://myapp.com/webhooks/products",
      "is_active": true,
      "failure_count": 0,
      "last_failure_at": null,
      "last_success_at": null,
      "created_at": "2025-06-05T12:00:00.000Z"
    }
  ],
  "status": 200
}

Response Fields

FieldTypeDescription
subscription_idintegerUnique subscription identifier
event_topicstringThe event topic this subscription listens for
target_urlstringThe URL that receives POST requests when events fire
is_activebooleanWhether the subscription is currently active
failure_countintegerNumber of consecutive delivery failures
last_failure_atstring or nullTimestamp of the most recent delivery failure
last_success_atstring or nullTimestamp of the most recent successful delivery
created_atstring (ISO 8601)When the subscription was created

Create Webhook Subscription

Subscribe to an event topic. The response includes a signing_secret that is shown only once -- store it securely for signature verification.

POST /api/apps/v1/webhooks

Authentication

Required. Must include valid app credentials.

Scope

No specific scope required beyond app authentication.

Request Body

FieldTypeRequiredDescription
event_topicstringYesThe event topic to subscribe to (must be a valid topic from the list above)
target_urlstringYesThe HTTPS URL that will receive webhook POST requests

Example Request

curl -X POST "https://api.selorax.io/api/apps/v1/webhooks" \
  -H "Authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d '{
    "event_topic": "order.created",
    "target_url": "https://myapp.com/webhooks/orders"
  }'

Response

{
  "message": "Webhook subscription created successfully",
  "data": {
    "subscription_id": 18,
    "event_topic": "order.created",
    "target_url": "https://myapp.com/webhooks/orders",
    "is_active": true,
    "signing_secret": "whsec_a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6",
    "failure_count": 0,
    "last_failure_at": null,
    "last_success_at": null,
    "created_at": "2025-06-15T15:00:00.000Z"
  },
  "status": 200
}

:::warning Store the signing secret The signing_secret (prefixed with whsec_) is returned only once at creation time. It will not appear in subsequent GET requests. Store it securely -- you need it to verify webhook signatures. :::

Signing Secret

The signing_secret is used to verify that incoming webhook requests are authentically from the SeloraX platform. See Receiving Webhooks for implementation details.

Error Responses

CodeStatusMeaning
invalid_token401Token is expired or invalid
missing_auth401No authentication credentials provided

If an invalid event_topic is provided:

{
  "message": "Invalid event topic. Must be one of: order.created, order.updated, ...",
  "status": 400
}

If the target_url is missing:

{
  "message": "Missing required fields: event_topic, target_url",
  "status": 400
}

Delete Webhook Subscription

Remove a webhook subscription. This performs a soft-delete -- the subscription is deactivated and will no longer receive events.

DELETE /api/apps/v1/webhooks/:subscription_id

Authentication

Required. Must include valid app credentials.

Scope

No specific scope required beyond app authentication.

Path Parameters

ParameterTypeDescription
subscription_idintegerThe subscription ID to delete

Example Request

curl -X DELETE "https://api.selorax.io/api/apps/v1/webhooks/18" \
  -H "Authorization: Bearer <token>"

Response

{
  "message": "Webhook subscription deleted.",
  "status": 200
}

Error Responses

CodeStatusMeaning
invalid_token401Token is expired or invalid
missing_auth401No authentication credentials provided

If the subscription_id does not exist or does not belong to your app:

{
  "message": "Webhook subscription not found",
  "status": 404
}

Rotate Signing Secret

Generate a new signing secret for an existing webhook subscription. The old secret is immediately invalidated.

POST /api/apps/v1/webhooks/:subscription_id/rotate-secret

Authentication

Required. Must include valid app credentials.

Path Parameters

ParameterTypeDescription
subscription_idintegerThe subscription ID to rotate the secret for

Example Request

curl -X POST "https://api.selorax.io/api/apps/v1/webhooks/18/rotate-secret" \
  -H "Authorization: Bearer <token>"

Response

{
  "message": "Signing secret rotated. Save the new signing_secret — it will not be shown again.",
  "data": {
    "subscription_id": 18,
    "signing_secret": "whsec_a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6"
  },
  "status": 200
}

:::warning The new signing_secret is returned only once. Store it securely — it replaces the previous secret immediately and all future deliveries will be signed with the new secret. :::

Error Responses

CodeStatusMeaning
invalid_token401Token is expired or invalid

If the subscription_id does not exist or does not belong to your app:

{
  "message": "Webhook subscription not found",
  "status": 404
}

Webhook Delivery Details

When an event fires, the platform delivers a POST request to each active subscription's target_url.

Delivery Headers

HeaderDescription
Content-Typeapplication/json
X-SeloraX-Signaturesha256={HMAC-SHA256 signature}
X-SeloraX-TimestampUnix timestamp used in the signature
X-SeloraX-Webhook-EventEvent topic (e.g. order.created)
X-SeloraX-Webhook-Event-IdUnique event ID (UUID)
X-SeloraX-Idempotency-KeySame as event ID, for idempotent processing
X-SeloraX-Delivery-IdUnique delivery ID (differs per retry attempt)
User-AgentSeloraX-Webhook/1.0

Payload Structure

{
  "event_id": "evt_a1b2c3d4",
  "event_topic": "order.status_changed",
  "store_id": 22,
  "timestamp": "2026-03-02T10:30:00.000Z",
  "data": {
    "order_id": 1045,
    "order_number": "1045",
    "status": "confirmed",
    "customer_name": "Rahim Ahmed",
    "customer_phone": "+8801712345678",
    "total": 1460.00,
    "tracking_id": null,
    "store_name": "My Store"
  }
}

The data fields vary by event topic. For order.status_changed, the platform automatically enriches the payload with customer and store information.

Signature Verification

Verify every delivery using X-SeloraX-Signature, X-SeloraX-Timestamp, and your signing_secret:

Node.js:

const crypto = require("crypto");
 
function verifyWebhookSignature(rawBody, signatureHeader, timestampHeader, secret) {
  const signedPayload = `${timestampHeader}.${rawBody}`;
  const expected = "sha256=" + crypto
    .createHmac("sha256", secret)
    .update(signedPayload)
    .digest("hex");
 
  return crypto.timingSafeEqual(
    Buffer.from(signatureHeader),
    Buffer.from(expected)
  );
}
 
// Express middleware
app.post("/webhooks", express.raw({ type: "application/json" }), (req, res) => {
  const signature = req.headers["x-selorax-signature"];
  const timestamp = req.headers["x-selorax-timestamp"];
  const rawBody = req.body.toString("utf8");
 
  if (!verifyWebhookSignature(rawBody, signature, timestamp, WEBHOOK_SECRET)) {
    return res.status(401).send("Invalid signature");
  }
 
  const event = JSON.parse(rawBody);
  console.log(`Received ${event.event_topic}:`, event.data);
  res.status(200).send("OK");
});

Python:

import hmac
import hashlib
 
def verify_signature(raw_body: bytes, signature_header: str, timestamp_header: str, secret: str) -> bool:
    signed_payload = timestamp_header.encode() + b"." + raw_body
    expected = "sha256=" + hmac.new(
        secret.encode(), signed_payload, hashlib.sha256
    ).hexdigest()
    return hmac.compare_digest(expected, signature_header)

Retry Policy

Failed deliveries are retried with this schedule (6 total attempts): immediate, 1 minute, 5 minutes, 30 minutes, 2 hours, 12 hours. A delivery is considered failed if:

  • Your endpoint returns a non-2xx status code
  • The request times out after 15 seconds
  • A network error occurs

Auto-Disable

If a subscription accumulates 20 consecutive failures, it is automatically disabled (is_active set to false). You can re-enable it by creating a new subscription.

The failure_count resets to 0 on any successful delivery.


Test Webhook Delivery

Use this tool to simulate a webhook delivery to your endpoint. Enter your webhook URL and signing secret, select an event topic, and generate a ready-to-use cURL command with proper HMAC-SHA256 signature.