Webhooks let you subscribe to VMArea events and receive real-time HTTP POST notifications at your own HTTPS endpoint. Requires the webhooks:write scope to manage subscriptions, and webhooks:read to list them.
Subscribing
Create a webhook subscription with POST /webhooks:
curl -X POST https://api.vmarea.com/api/public/v1/webhooks \
-H "x-api-key: $VMAREA_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"url": "https://your-server.example.com/hooks/vmarea",
"events": ["vm.created", "vm.started", "billing.payment_received"],
"description": "Production listener"
}'
The response includes a secret field — copy it immediately, it is shown only once. You use this secret to verify incoming requests.
Endpoint URLs must use HTTPS. Each account can have up to 10 active webhook subscriptions.
Event types
| Event | Description |
|---|
vm.created | A VM has finished provisioning. |
vm.started | A VM has started. |
vm.stopped | A VM has stopped. |
vm.restarted | A VM has restarted. |
vm.suspended | A VM has been suspended (e.g., due to non-payment). |
vm.terminated | A VM has been permanently deleted. |
vm.renewed | A VM billing cycle has renewed. |
billing.payment_received | A wallet top-up was successfully processed. |
billing.low_balance | Wallet balance has dropped below the threshold needed to cover upcoming renewals. |
ticket.reply | A support ticket has received a new reply. |
Signature verification
Every delivery includes an HMAC-SHA256 signature so you can verify the request came from VMArea.
Headers sent with each delivery:
| Header | Value |
|---|
X-VMArea-Event | The event type string (e.g., vm.started). |
X-VMArea-Signature | sha256=<hex-digest> of the raw JSON request body, signed with your webhook secret. |
X-VMArea-Delivery-Id | A unique ID for this delivery attempt. |
Verification example:
import crypto from "node:crypto";
function verifySignature(rawBody, signatureHeader, secret) {
const expected = "sha256=" +
crypto.createHmac("sha256", secret).update(rawBody).digest("hex");
return crypto.timingSafeEqual(
Buffer.from(expected),
Buffer.from(signatureHeader)
);
}
// Express example
app.post("/hooks/vmarea", express.raw({ type: "application/json" }), (req, res) => {
const sig = req.headers["x-vmarea-signature"];
if (!verifySignature(req.body, sig, process.env.VMAREA_WEBHOOK_SECRET)) {
return res.status(401).send("Invalid signature");
}
const event = req.headers["x-vmarea-event"];
const payload = JSON.parse(req.body);
// handle event ...
res.status(200).send("ok");
});
Always use crypto.timingSafeEqual (or equivalent) to prevent timing attacks.
Retry semantics
If your endpoint does not return a 2xx response within 15 seconds, VMArea retries the delivery up to 3 attempts total with exponential backoff (initial delay 10 seconds, doubling per attempt).
After 50 consecutive delivery failures across all events, the webhook subscription is automatically disabled. You can re-enable it from the dashboard or via PATCH /webhooks/:id with { "isActive": true }.
Delivery history (status code, success flag, attempt count) is available via GET /webhooks/:id/deliveries.
Best practices
- Respond quickly. Return
2xx before doing any heavy processing — offload work to a queue so you don’t hit the 15-second timeout.
- Make handlers idempotent. The same event may be delivered more than once (e.g., after a retry). Use
X-VMArea-Delivery-Id to deduplicate.
- Always verify the signature. Do not trust the payload without checking the HMAC.
- Use a dedicated endpoint per environment (production, staging) so you can inspect and replay events independently.