SeloraXDEVELOPERS

Developer Webhooks API

Developer Webhooks API

All endpoints are app-scoped under:

/api/v1/apps/:appId/webhooks

Requires authentication via Authorization: Bearer <accessToken>.

List Subscriptions

GET /api/v1/apps/:appId/webhooks/subscriptions?page=1&limit=20&status=active
ParameterTypeDefaultDescription
pageinteger1Page number
limitinteger20Results per page (max 100)
statusstring--Filter: active or inactive

Response (200):

{
  "status": 200,
  "message": "Webhook subscriptions fetched",
  "data": {
    "items": [
      {
        "subscription_id": 5,
        "installation_id": 2,
        "app_id": 2,
        "store_id": 22,
        "name": "Order Status Webhook",
        "event_topic": "order.status_changed",
        "target_url": "https://api.example.com/webhooks",
        "permissions": ["read_orders"],
        "is_active": 1,
        "failure_count": 0,
        "last_failure_at": null,
        "last_success_at": "2026-02-28T10:15:00.000Z",
        "created_at": "2026-01-20T09:00:00.000Z",
        "updated_at": "2026-02-28T10:15:00.000Z"
      }
    ],
    "page": 1,
    "limit": 20,
    "total": 1,
    "totalPages": 1
  }
}

Create Subscription

POST /api/v1/apps/:appId/webhooks/subscriptions
Content-Type: application/json

Request Body:

{
  "name": "Orders Webhook",
  "event_topic": "order.created",
  "target_url": "https://example.com/webhooks/orders",
  "permissions": ["read_orders"]
}
FieldTypeRequiredDescription
namestringNoDisplay name (2-255 chars)
event_topicstringYesEvent to subscribe to (3-100 chars)
target_urlstringYesURL to deliver webhooks to (valid URL)
permissionsstring[]NoPayload filter permissions (max 50 items)

Response (201):

{
  "status": 201,
  "message": "Webhook subscription created",
  "data": {
    "subscription_id": 6,
    "app_id": 2,
    "event_topic": "order.created",
    "target_url": "https://example.com/webhooks/orders",
    "signing_secret": "whsec_a1b2c3d4e5f6g7h8i9j0...",
    "created_at": "2026-02-28T12:00:00.000Z"
  }
}

Save the signing secret

The signing_secret (prefixed whsec_) is shown only once at creation time. Use it to verify HMAC signatures on incoming webhook deliveries. See Receiving Webhooks for verification code.

Errors:

  • 400 INSTALLATION_REQUIRED — No active installation found for this app
  • 409 WEBHOOK_EXISTS — A subscription for this topic already exists

Update Subscription

PUT /api/v1/apps/:appId/webhooks/subscriptions/:subscriptionId
Content-Type: application/json

Request Body (all fields optional):

{
  "name": "Updated Webhook Name",
  "target_url": "https://example.com/webhooks/new-endpoint",
  "permissions": ["read_orders", "read_customers"],
  "is_active": true
}
FieldTypeRequiredDescription
namestringNoUpdated display name (2-255 chars)
event_topicstringNoUpdated event topic (3-100 chars)
target_urlstringNoUpdated delivery URL
permissionsstring[]NoUpdated payload filter permissions
is_activebooleanNoEnable/disable the subscription

Response (200):

{
  "status": 200,
  "message": "Webhook subscription updated",
  "data": {
    "subscription_id": 6,
    "app_id": 2,
    "name": "Updated Webhook Name",
    "event_topic": "order.created",
    "target_url": "https://example.com/webhooks/new-endpoint",
    "permissions": ["read_orders", "read_customers"],
    "is_active": 1,
    "updated_at": "2026-02-28T12:30:00.000Z"
  }
}

Delete Subscription

DELETE /api/v1/apps/:appId/webhooks/subscriptions/:subscriptionId

Soft-deletes the subscription (is_active = 0, deleted_at set).

Response (200):

{
  "status": 200,
  "message": "Webhook subscription deleted",
  "data": {
    "subscription_id": 6,
    "deleted": true
  }
}

List Deliveries

View webhook delivery attempts with filtering:

GET /api/v1/apps/:appId/webhooks/deliveries?page=1&limit=20&status=failed&event_topic=order.created
ParameterTypeDefaultDescription
pageinteger1Page number
limitinteger20Results per page (max 100)
statusstring--Filter: pending, success, or failed
event_topicstring--Filter by event topic

Response (200):

{
  "status": 200,
  "message": "Webhook deliveries fetched",
  "data": {
    "items": [
      {
        "delivery_id": "12345",
        "subscription_id": 5,
        "installation_id": 2,
        "store_id": 22,
        "event_topic": "order.status_changed",
        "event_id": "550e8400-e29b-41d4-a716-446655440000",
        "target_url": "https://api.example.com/webhooks",
        "response_status": 200,
        "response_body": "{\"received\":true}",
        "attempt_number": 1,
        "status": "success",
        "duration_ms": 245,
        "error_message": null,
        "created_at": "2026-02-28T10:15:00.000Z",
        "completed_at": "2026-02-28T10:15:00.245Z"
      }
    ],
    "page": 1,
    "limit": 20,
    "total": 1,
    "totalPages": 1
  }
}

Retry Delivery

Retry a failed webhook delivery. Creates a new delivery attempt with incremented attempt_number.

POST /api/v1/apps/:appId/webhooks/deliveries/:deliveryId/retry

Response (200):

{
  "status": 200,
  "message": "Webhook retry queued",
  "data": {
    "delivery_id": "12346",
    "status": "pending",
    "attempt_number": 2,
    "created_at": "2026-02-28T12:00:00.000Z"
  }
}

Test Webhook

Send a test webhook delivery to your app's webhook_receive_url. Useful for verifying your endpoint is reachable and correctly verifying signatures.

POST /api/v1/apps/:appId/webhooks/test
Content-Type: application/json

Request Body (optional):

{
  "event_topic": "test.ping"
}
FieldTypeDefaultDescription
event_topicstringtest.pingTopic for the test event (3-100 chars)

Response (200):

{
  "status": 200,
  "message": "Webhook test completed",
  "data": {
    "delivered": true,
    "target_url": "https://api.example.com/webhooks",
    "event_topic": "test.ping",
    "event_id": "550e8400-e29b-41d4-a716-446655440001",
    "response_status": 200,
    "response_body": "{\"received\":true}",
    "duration_ms": 189,
    "error_message": null
  }
}

Errors:

  • 400 NO_WEBHOOK_URL — App has no webhook_receive_url configured

Auto-Disable Behavior

If a webhook subscription accumulates 20 consecutive failed deliveries, the platform automatically deactivates it (is_active = 0). You can re-enable it via the Update Subscription endpoint after fixing the underlying issue.

The delivery log (failure_count, last_failure_at, last_success_at) helps you monitor subscription health and catch issues before auto-disable kicks in.