API Documentation

Integrate WisPanel with your applications using our comprehensive REST API.

Base URL

https://your-server-ip:2083/api/v1

All API endpoints are relative to this base URL.

Webhooks, Idempotency & OpenAPI

Webhooks

WisPanel can POST event payloads to a URL when matching events occur in the panel. Use this for WHMCS provisioning sync, Slack/Discord notifications, monitoring integrations, etc.

Subscribe

POST /api/v1/webhooks
Authorization: Bearer <jwt>
Idempotency-Key: <uuid>           # optional, recommended

{
  "url": "https://your-app.example.com/wispanel-webhook",
  "events": ["user.*", "domain.created"],
  "enabled": true
}

Response (201):

{
  "success": true,
  "data": {
    "id": "8f1d29b3a44e1c7f...",
    "owner": "admin",
    "url": "https://your-app.example.com/wispanel-webhook",
    "events": ["user.*", "domain.created"],
    "secret": "f7c3...",
    "enabled": true,
    "created_at": "2026-05-10T09:30:00Z"
  },
  "warning": "Save the secret now — it is only shown on creation."
}

Save the secret immediately. Subsequent GET responses redact it. The secret is what your endpoint uses to verify the HMAC signature below. Lost it? Delete the subscription and re-create.

Event patterns

The events array accepts:

Pattern Matches
"user.created" exactly that event
"user.*" any event with user. prefix (user.created, user.suspended, ...)
"*" every event

Currently dispatched events:

Event Fired when data payload
user.created New user provisioned username, email, role, package, creator
domain.created New domain added domain, owner, webserver, php_version

More events land per release.

Delivery

WisPanel POSTs the JSON envelope below to your URL with up to 3 attempts (1s/5s/25s exponential backoff). 2xx response = success. Any other response = retry.

{
  "event": "user.created",
  "timestamp": 1715329000,
  "data": {
    "username": "alice",
    "email": "[email protected]",
    "role": "user",
    "package": "default",
    "creator": "admin"
  }
}

Headers on every delivery:

Header Purpose
User-Agent WisPanel-Webhook/1
X-WisPanel-Signature sha256=<hex> HMAC of the body using your subscription's secret
X-WisPanel-Delivery Unique id per delivery attempt

Verifying the signature

Compute sha256=<hex> over the raw request body using your saved secret. Compare in constant time. PHP example:

$expected = 'sha256=' . hash_hmac('sha256', file_get_contents('php://input'), $secret);
$received = $_SERVER['HTTP_X_WISPANEL_SIGNATURE'] ?? '';
if (!hash_equals($expected, $received)) { http_response_code(401); exit; }

Listing / updating / removing

GET    /api/v1/webhooks                  # paginated; admin sees all, others see own
GET    /api/v1/webhooks/{id}             # single, secret redacted
PATCH  /api/v1/webhooks/{id}             # change url / events / enabled (reauth)
DELETE /api/v1/webhooks/{id}             # unsubscribe (reauth)

Limits

  • HTTPS or HTTP only. file://, gopher://, etc. are rejected.
  • Loopback / link-local / cloud-metadata destinations are rejected at subscribe time (localhost, 127.0.0.1, 169.254.169.254, ::1).
  • 10s connection + read timeout per attempt.
  • Failure count is tracked on the subscription (failure_count field); operators can use this to disable broken subscribers.

Idempotency

Send Idempotency-Key: <uuid> on POST/PUT/PATCH/DELETE requests to make retries safe. WisPanel deduplicates within a 24-hour window.

POST /api/v1/users
Idempotency-Key: c3a4d6e2-1b78-...
Authorization: Bearer <jwt>

{ "username": "alice", "password": "...", ... }
Replay condition Behaviour
Same key + same request body Replays the cached response. Header Idempotency-Replayed: true.
Same key + different body 409 IDEMPOTENCY_KEY_CONFLICT.
New key Normal processing.
Key reused after 24h Treated as new (cache expired).

The idempotency cache only stores 2xx responses. Failed requests are always re-run on retry.

Recommended use:

  • Generate a fresh UUID per logical operation (per "Create user" click, per WHMCS provisioning ticket).
  • Persist the UUID with the operation so a network-error retry uses the same key.

OpenAPI 3.0 spec

The full machine-readable spec is served at:

GET  https://YOUR_SERVER:3082/openapi.yaml
GET  https://YOUR_SERVER:3082/api/v1/openapi.yaml

No authentication required. Use it with:

  • openapi-generator to scaffold typed SDKs (PHP, Python, TypeScript, Go, ...).
  • Swagger UI / ReDoc to render interactive docs.
  • IDE plugins for autocomplete in API integration code.

Rate Limiting

API requests are limited to 60 requests per minute per API token.

  • X-RateLimit-Limit: Maximum requests per minute
  • X-RateLimit-Remaining: Remaining requests
  • X-RateLimit-Reset: Unix timestamp when limit resets