SeloraXDEVELOPERS

Developer Webhooks API

Developer Webhooks API

This page documents the dashboard-facing merchant webhook management routes mounted under:

/api/apps/webhooks

These routes are different from the app-facing runtime webhook API under /api/apps/v1/webhooks.

Authentication and Permissions

These routes use the dashboard auth stack and usually require:

  • authenticated admin session
  • store_id
  • store ownership validation
  • apps__view_webhooks for most mutating operations

The dashboard uses these routes to manage webhook subscriptions that belong to a store, whether they were created by a merchant or by an installed app.

Supported Merchant Topics

Merchant-created subscriptions are limited to these topics:

  • order.created
  • order.updated
  • order.status_changed
  • product.created
  • product.updated
  • product.deleted
  • customer.created
  • customer.updated
  • inventory.updated
  • app.installed
  • app.uninstalled

Billing topics such as charge.* and GDPR topics such as customers/redact are app-runtime topics and should be managed through the app-facing Webhooks API.

List Subscriptions

GET /api/apps/webhooks/subscriptions?store_id=22

Returns all webhook subscriptions for the store, including both app-created and merchant-created entries.

Response:

{
  "message": "Subscriptions fetched successfully.",
  "data": [
    {
      "subscription_id": 15,
      "app_id": 2,
      "installation_id": 12,
      "store_id": 22,
      "event_topic": "order.status_changed",
      "target_url": "https://app.example.com/webhooks/orders",
      "is_active": 1,
      "failure_count": 0,
      "name": null,
      "permissions": null,
      "created_by_type": "app",
      "source_name": "SeloraX Messaging"
    },
    {
      "subscription_id": 19,
      "app_id": null,
      "installation_id": null,
      "store_id": 22,
      "event_topic": "order.created",
      "target_url": "https://merchant.example.com/hooks/orders",
      "is_active": 1,
      "failure_count": 1,
      "name": "Merchant Order Hook",
      "permissions": ["read_orders"],
      "created_by_type": "merchant",
      "source_name": "Merchant Order Hook"
    }
  ],
  "status": 200
}

Create Merchant Webhook Subscriptions

POST /api/apps/webhooks/subscriptions
Content-Type: application/json
{
  "store_id": 22,
  "name": "Orders Webhook",
  "target_url": "https://merchant.example.com/hooks/orders",
  "event_topics": ["order.created", "order.status_changed"],
  "permissions": ["read_orders"]
}

One subscription is created per topic. The response returns the generated signing secret once.

Response:

{
  "message": "Webhook subscription(s) created successfully.",
  "data": {
    "subscriptions": [
      {
        "subscription_id": 25,
        "store_id": 22,
        "event_topic": "order.created",
        "target_url": "https://merchant.example.com/hooks/orders",
        "name": "Orders Webhook",
        "permissions": ["read_orders"],
        "created_by_type": "merchant",
        "is_active": 1,
        "failure_count": 0
      },
      {
        "subscription_id": 26,
        "store_id": 22,
        "event_topic": "order.status_changed",
        "target_url": "https://merchant.example.com/hooks/orders",
        "name": "Orders Webhook",
        "permissions": ["read_orders"],
        "created_by_type": "merchant",
        "is_active": 1,
        "failure_count": 0
      }
    ],
    "signing_secret": "whsec_..."
  },
  "status": 200
}

Signing secret is shown once

Store the returned signing_secret securely. Subsequent list requests do not return it.

Update Merchant Webhooks

Update a single subscription

PUT /api/apps/webhooks/subscriptions/:id
Content-Type: application/json
{
  "store_id": 22,
  "name": "Updated Orders Webhook",
  "target_url": "https://merchant.example.com/hooks/orders-v2",
  "permissions": ["read_orders"],
  "is_active": true
}

This route only updates merchant-created subscriptions.

Batch update and reconcile topics

PUT /api/apps/webhooks/subscriptions/batch
Content-Type: application/json
{
  "store_id": 22,
  "subscription_ids": [25, 26],
  "name": "Orders Webhook",
  "target_url": "https://merchant.example.com/hooks/orders-v2",
  "permissions": ["read_orders"],
  "event_topics": ["order.created", "order.updated"]
}

If event_topics is included, the backend reconciles the group:

  • creates subscriptions for newly added topics
  • deletes subscriptions for removed topics
  • updates remaining subscriptions with shared fields

Delete and Toggle

Delete one merchant subscription

DELETE /api/apps/webhooks/subscriptions/:id?store_id=22

Delete many merchant subscriptions

DELETE /api/apps/webhooks/subscriptions/batch?store_id=22&ids=25,26

Toggle one subscription

PUT /api/apps/webhooks/subscriptions/:id/toggle
Content-Type: application/json
{
  "store_id": 22,
  "is_active": false
}

This route can toggle either merchant-created or app-created subscriptions.

Toggle many subscriptions

PUT /api/apps/webhooks/subscriptions/batch/toggle
Content-Type: application/json
{
  "store_id": 22,
  "subscription_ids": [25, 26],
  "is_active": false
}

Delivery Logs

List deliveries

GET /api/apps/webhooks/deliveries?store_id=22&page=1&limit=50&event_topic=order.created&status=failed

Response:

{
  "message": "Deliveries fetched successfully.",
  "data": [
    {
      "delivery_id": 81,
      "subscription_id": 25,
      "event_topic": "order.created",
      "event_id": "550e8400-e29b-41d4-a716-446655440000",
      "target_url": "https://merchant.example.com/hooks/orders",
      "response_status": 500,
      "attempt_number": 2,
      "status": "failed",
      "duration_ms": 413,
      "error_message": "socket hang up",
      "created_at": "2026-03-31T10:00:00.000Z",
      "completed_at": "2026-03-31T10:00:00.413Z",
      "app_name": "Custom"
    }
  ],
  "pagination": {
    "page": 1,
    "limit": 50,
    "total": 1
  },
  "status": 200
}

Retry a delivery

POST /api/apps/webhooks/deliveries/:delivery_id/retry
Content-Type: application/json
{
  "store_id": 22
}

This does not replay the original HTTP request inline. It republishes the original platform event so the webhook pipeline can deliver it again.

Response:

{
  "message": "Delivery retry queued.",
  "status": 200
}

Delivery Behavior

Merchant webhook deliveries share the same signing and retry model as app webhook deliveries:

  • signature header: X-SeloraX-Signature
  • timestamp header: X-SeloraX-Timestamp
  • event topic header: X-SeloraX-Webhook-Event
  • event id header: X-SeloraX-Webhook-Event-Id
  • idempotency header: X-SeloraX-Idempotency-Key

See Receiving Webhooks for signature verification code.

Auto-Disable

If a subscription accumulates 20 consecutive failures, the platform disables it automatically.

Successful deliveries reset failure_count back to 0.

Runtime App Webhooks vs Dashboard Webhooks

Use this page when you are:

  • building webhook management screens inside the SeloraX dashboard
  • managing merchant-owned subscriptions
  • inspecting store-level delivery logs
  • retrying failed deliveries from the dashboard

Use the app-facing Webhooks API when you are:

  • creating subscriptions from your installed app
  • rotating an app webhook signing secret
  • managing app-owned subscriptions with app credentials