Loading...
DXVPN can deliver event notifications to an HTTPS endpoint you control so you can react to account, subscription, payment, peer, and node events in real time. Registration happens in your admin dashboard at /admin/webhooks.
Each delivery is a single HTTPS POST with a JSON body. Headers carry the event type, a unique delivery ID, and the HMAC signature.
POST /your-endpoint HTTP/1.1
Host: your-server.example
Content-Type: application/json
X-DXVPN-Event: payment.completed
X-DXVPN-Delivery: dlv_01JARK6YH7ZX…
X-DXVPN-Signature: sha256=4f3b8a…
User-Agent: DXVPN-Webhook/1.0
{"event":"payment.completed",…}The X-DXVPN-Signature header is sha256=<hmac> where HMAC is the raw request body hashed with your shared secret. Always verify on the raw byte stream before parsing JSON to avoid timing-oracle pitfalls.
import hmac, hashlib
def verify_dxvpn(raw_body: bytes, signature_header: str, secret: str) -> bool:
# signature_header looks like 'sha256=<hex>'
prefix, _, received = signature_header.partition('=')
if prefix != 'sha256' or not received:
return False
expected = hmac.new(secret.encode(), raw_body, hashlib.sha256).hexdigest()
return hmac.compare_digest(expected, received)import crypto from 'node:crypto';
export function verifyDxvpn(rawBody, signatureHeader, secret) {
const [prefix, received] = String(signatureHeader || '').split('=');
if (prefix !== 'sha256' || !received) return false;
const expected = crypto.createHmac('sha256', secret).update(rawBody).digest('hex');
return crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(received));
}X-DXVPN-Delivery. Use it as your idempotency key./admin/webhooks/<endpoint-id>/deliveries.12 event types. Subscribe to any subset when creating an endpoint.
user.createdFires when a new user completes email verification (or auto-creates via Telegram).{
"event": "user.created",
"id": "evt_01JAR4...",
"created_at": "2026-04-13T07:22:11Z",
"data": {
"user_id": "c7b9e2…",
"username": "alice",
"email": "alice@example.com",
"source": "email"
}
}user.suspendedFires when a user is suspended (admin action or automated billing policy).{
"event": "user.suspended",
"id": "evt_01JAR4...",
"created_at": "2026-04-13T07:22:11Z",
"data": {
"user_id": "c7b9e2…",
"reason": "payment_failed"
}
}user.deletedFires on user self-service deletion or admin deletion.{
"event": "user.deleted",
"data": {
"user_id": "c7b9e2…",
"deletion_initiated_by": "self"
}
}subscription.activatedFires when a subscription transitions to ACTIVE (first payment, reactivation, trial-to-paid).{
"event": "subscription.activated",
"data": {
"user_id": "c7b9e2…",
"subscription_id": "sub_...",
"plan_slug": "premium",
"billing_period": "monthly"
}
}subscription.expiredFires when a subscription's current_period_end elapses without renewal.{
"event": "subscription.expired",
"data": {
"user_id": "c7b9e2…",
"subscription_id": "sub_...",
"plan_slug": "premium"
}
}subscription.renewedFires on successful renewal payment.{
"event": "subscription.renewed",
"data": {
"user_id": "c7b9e2…",
"subscription_id": "sub_...",
"new_period_end": "2026-05-13T00:00:00Z"
}
}payment.completedFires when a payment transitions to COMPLETED.{
"event": "payment.completed",
"data": {
"payment_id": "pay_...",
"user_id": "c7b9e2…",
"amount": 299,
"currency": "RUB",
"method": "yookassa"
}
}payment.failedFires when a payment transitions to FAILED.{
"event": "payment.failed",
"data": {
"payment_id": "pay_...",
"user_id": "c7b9e2…",
"method": "yookassa",
"reason": "card_declined"
}
}payment.refundedFires on full or partial refund.{
"event": "payment.refunded",
"data": {
"payment_id": "pay_...",
"user_id": "c7b9e2…",
"amount": 299,
"currency": "RUB"
}
}peer.provisionedFires when a peer is provisioned and deployed healthy on a node.{
"event": "peer.provisioned",
"data": {
"user_id": "c7b9e2…",
"peer_id": "peer_...",
"protocol": "vless",
"node_name": "VPS_NL"
}
}peer.deletedFires when a peer is removed (either by the owning user or by admin).{
"event": "peer.deleted",
"data": {
"user_id": "c7b9e2…",
"peer_id": "peer_..."
}
}node.health_changedFires when a server node's is_healthy transitions. Admin endpoint only.{
"event": "node.health_changed",
"data": {
"node_name": "VPS_DE",
"is_healthy": false,
"latency_ms": null
}
}Adding new event types or optional fields is non-breaking and does not bump a version. Removing or renaming fields ships only on a new major version, announced at least 30 days in advance via the Telegram channel and via a node.health_changed-style announcement event.