Webhooks
Webhooks let you receive events instantly instead of continuously polling your
server. When an event occurs, Rabisu sends a signed POST request to your
registered URL.
1. Register an Endpoint — POST /webhooks
curl -X POST https://api.rabisu.com/api/v1/webhooks \
-u "rsk_live_xxx:rsks_yyy" \
-H "Content-Type: application/json" \
-d '{
"url": "https://reseller.com/modules/addons/rabisu/webhook.php",
"event_types": ["service.*", "credit.added"],
"description": "Production webhook"
}'
The HMAC secret is returned only once — store it securely:
{
"success": true,
"data": {
"id": 12,
"url": "https://reseller.com/.../webhook.php",
"event_types": ["service.*", "credit.added"],
"secret": "whsec_...ONE_TIME...",
"is_active": true
},
"meta": { "trace_id": "...", "timestamp": "..." }
}
URL Rules (SSRF Protection)
https://is required.- The URL may not contain
user:pass@. - All resolved DNS IPs must be public (private/internal IPs are rejected).
2. Subscription Patterns
The event_types array supports these forms:
| Pattern | Meaning |
|---|---|
* | All events (catch-all) |
service.* | Namespace wildcard — all events starting with service |
service.created | Exact event name |
Valid namespaces: service, product, credit. Sending an invalid pattern makes
the registration fail with 422 (a clear error instead of silently "receiving no
events").
3. Event Catalog
| Event | When | Payload fields (summary) |
|---|---|---|
service.created | VPS provisioning completed (active) | provision_id, service_id, order_id, product_id, status |
service.suspended | Service suspended | service_id, reason |
service.unsuspended | Suspension lifted | service_id |
service.terminated | Service terminated | service_id |
product.price_changed | Product price changed (notification) | product_id |
product.stock_changed | Product stock status changed | product_id, stock_active |
product.disabled | Product closed for sale | product_id |
credit.added | Reseller credit added (refund/manual) | reseller_id, amount, currency, reason, new_balance |
Note:
product.*events carry a notification only. Fetch the current data withGET /products/{id}(hybrid notification + pull).
Every payload includes a schema_version field at its root (currently 1).
4. Signature Verification (CRITICAL)
Every request includes an X-Rabisu-Signature header. The signature is the
HMAC-SHA256 of the raw request body:
X-Rabisu-Signature: sha256=<hmac_sha256(raw_body, secret)>
Verification (PHP):
$raw = file_get_contents('php://input');
$expected = 'sha256=' . hash_hmac('sha256', $raw, $webhookSecret);
$received = $_SERVER['HTTP_X_RABISU_SIGNATURE'] ?? '';
if (!hash_equals($expected, $received)) {
http_response_code(401); // Invalid signature
exit;
}
// Safe: the payload can be processed
$payload = json_decode($raw, true);
- Always verify the signature — otherwise you accept forged requests.
- Use a constant-time comparison such as
hash_equals. - Verify against the raw body before decoding to JSON (re-serialized JSON breaks the signature).
5. Delivery and Response Contract
Your endpoint should return the following HTTP codes:
| Response | Meaning | Rabisu behavior |
|---|---|---|
2xx | Processed successfully | Delivery complete |
4xx (incl. 401) | Permanent error (signature/format) | Not retried |
5xx | Transient error | Retried with exponential backoff |
Retry schedule: 1m → 5m → 15m → 1h → 6h → 24h. After 6 attempts the event is marked
"dead letter". After 5 consecutive failures the endpoint is automatically
deactivated (circuit breaker) — reactivate it with PATCH /webhooks/{id} once fixed.
6. Management Endpoints
GET /webhooks— list registered endpoints (including inactive)GET /webhooks/{id}— detailPATCH /webhooks/{id}— reactivate / updateevent_typesordescriptionDELETE /webhooks/{id}— delete (soft delete)