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
secretimmediately. 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_countfield); 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-generatorto scaffold typed SDKs (PHP, Python, TypeScript, Go, ...).- Swagger UI / ReDoc to render interactive docs.
- IDE plugins for autocomplete in API integration code.