Skip to main content

Webhooks

Set a webhook URL and secret in the integration's dashboard settings and enable delivery. Cloud API uses one endpoint for all event types. Delivery history is available in the dashboard. The webhook secret is separate from the API key.

Envelope​

Events arrive as HTTP POST with Content-Type: application/json and X-Webhook-Signature:

{
"event": "order.completed",
"timestamp": "2026-09-28T12:00:00.000Z",
"data": {
"order_id": 401,
"status": "completed",
"amount_usd": "5.0000",
"currency": "USD",
"vm_id": 101,
"rental_id": null,
"error_code": null,
"error_message": null,
"order_type": "vm_purchase",
"api_user_id": "customer-123"
}
}

event is the event type; timestamp is the envelope creation time in UTC. data is event-specific. Resource events also contain the numeric data.event_id and data.created_at from the source event; order events do not contain those two fields. Some event fields are optional and are omitted when absent at the source.

Order events​

EventMeaning
order.completedPaid action completed; dedicated purchase is reserved, not yet issued
order.failedOrder failed; inspect error and transaction history
order.refundedOrder amount returned to the integration balance
order.reviewUncertain or partial result requiring clarification

All four use the order fields shown above: order_id, order_type, api_user_id, status, amount_usd, currency, nullable vm_id, rental_id, error_code and error_message. vm_id is returned only for a completed order. ipv4_renewal additionally includes ip_id and paid_until. A completed VPS purchase can include guest_initialization; it is null when no result is available.

Order types: vm_purchase, vm_renewal, vm_resize, traffic_purchase, ipv4_purchase, ipv4_renewal, dedicated_purchase, dedicated_renewal. A refund returns the original positive order amount; use event/status to distinguish it from a purchase.

VPS events​

Common fields: event_id, created_at, vm_id; api_user_id, order_id and operation_id when present. The table lists additional fields. Creation includes ips as objects containing only address. Deletion includes held_ips matching the VPS deletion result. Failure events include public error_code and error_message.

EventMeaningAdditional data fields
vm.rescue.enabledRescue enabledstatus, rescue
vm.rescue.enable_failedRescue enable failedrequires_review, error_code, error_message
vm.rescue.disabledNormal OS boot restoredstatus, rescue
vm.rescue.disable_failedRescue exit failedrequires_review, error_code, error_message
vm.reinstalledOS reinstalledos, hostname, wipe_extra_disks, status, guest_initialization
vm.reinstall_failedOS reinstall failedrequires_review, error_code, error_message
vm.password.changedPassword changedlogin, password_changed, status
vm.password.change_failedPassword change failedrequires_review, error_code, error_message
vm.createdVPS createdstatus, hostname, smtp_blocked, paid_until, ips, guest_initialization
vm.creation_failedVPS creation failedstatus, requires_review, error_code, error_message
vm.resizedPlan resources changedstatus, cpu_cores, cpu_percent, ram_mb, disk_gb, traffic_limit_bytes, resources_applied, traffic_applied
vm.resize_failedPlan change failed or partially appliedrequires_review, status, cpu_cores, cpu_percent, ram_mb, disk_gb, traffic_limit_bytes, resources_applied, traffic_applied, error_code, error_message
vm.renewedVPS renewedpaid_until, resume_pending, auto_start
vm.traffic.topped_upExtra traffic addedperiod_id, quota_revision, additional_bytes, total_additional_bytes, remaining_bytes
vm.traffic.updatedTraffic quota changedperiod_id, quota_revision, previous_limit_bytes, traffic_limit_bytes, remaining_bytes
vm.ip.attachedIPv4 attachedstatus, ip_id, detached_ip_id, keep_ip, addresses, guest_configuration_required
vm.ip.attach_failedIPv4 attachment failedrequires_review, error_code, error_message
vm.ip.replacedIP replacement reportedstatus, ip_id, detached_ip_id, keep_ip, addresses, guest_configuration_required
vm.ip.replace_failedIP replacement failedrequires_review, error_code, error_message
vm.ip.detachedIPv4 detachedstatus, ip_id, detached_ip_id, keep_ip, addresses, guest_configuration_required
vm.ip.detach_failedIPv4 detach failedrequires_review, error_code, error_message
vm.power.changedPower command completedaction, status, uptime
vm.power.failedPower command failedaction, requires_review, error_code, error_message
vm.deletedVPS deletedstatus, keep_ips, reason, paid_until, held_ips
vm.delete_failedVPS deletion failedrequires_review, error_code, error_message
vm.expiringPaid term ending soonpaid_until, hours_before, delete_after
vm.deleting_soonOne hour before VPS deletionpaid_until, hours_before, delete_after, reason
vm.suspendedVPS suspendedstatus, reason, paid_until, delete_after
vm.resumedVPS resumedstatus, reason, paid_until, auto_started
vm.traffic.lowTraffic quota nearly exhaustedperiod_id, quota_revision, starts_at, ends_at, included_bytes, additional_bytes, outgoing_bytes, overage_bytes, remaining_bytes
vm.traffic.exhaustedTraffic quota exhaustedperiod_id, quota_revision, starts_at, ends_at, included_bytes, additional_bytes, outgoing_bytes, overage_bytes, remaining_bytes
vm.shaping.changedBandwidth limit changedprevious_reason, reason, limit_mbps, bandwidth_limited_until

Initialization and Rescue results​

vm.created, vm.reinstalled and completed VPS purchase orders report guest_initialization separately from resource creation:

{
"guest_initialization": {
"status": "failed",
"error_code": "cloud_init_failed"
}
}

Possible statuses: succeeded with error_code=null, failed with cloud_init_failed, or unknown with guest_initialization_timeout after 15 minutes. Custom initialization may fail or remain unconfirmed while the running VPS is retained and its purchase completes. This is not a creation failure or an automatic refund. The resource event omits the field when unavailable.

Successful Rescue events include this nested state:

{
"event": "vm.rescue.enabled",
"timestamp": "2026-09-28T12:00:00.000Z",
"data": {
"event_id": 701,
"created_at": "2026-09-28T12:00:00Z",
"vm_id": 101,
"api_user_id": "customer-123",
"operation_id": 501,
"status": "running",
"rescue": {
"active": true,
"access": "ssh",
"requires_review": false,
"operation_id": 501,
"operation_status": "succeeded"
}
}
}

On exit, rescue.active=false; the VPS can remain stopped if its paid term expired or it was suspended. active means saved Rescue context, not guaranteed SSH availability. access can be ssh, console or null. Failure events carry requires_review, error_code and error_message; read VPS details and the operation for the current state.

Passwords, cloud-init contents, stdout and stderr are not sent in these webhooks. See Cloud-init and Rescue for request rules.

IPv4 events​

Common fields: event_id, created_at, ip_id, address, family, vm_id, api_user_id, paid_until when present. A saved address has vm_id=null. Additional fields:

EventMeaningAdditional data fields
ip.expiringPaid IPv4 term ending soonhours_before, delete_after
ip.releasing_soonOne hour before IPv4 releasehours_before, delete_after, reason
ip.suspendedIPv4 suspendedreason, delete_after
ip.resumedIPv4 resumedreason
ip.releasedIPv4 releasedreason

Dedicated rental events​

Common fields when present: event_id, created_at, rental_id, plan_id, order_id, api_user_id, status, issued_at, paid_until, overdue_at, finished_at. Credentials are not sent in the webhook: retrieve rental details after dedicated.issued. Additional fields:

EventMeaningAdditional data fields
dedicated.preparingRental reserved and being prepared—
dedicated.issuedDedicated server issued—
dedicated.expiringRental payment ending soonhours_before
dedicated.overdueRental payment expiredrelease_after
dedicated.releasing_soonOne hour before rental releasehours_before, release_after, reason
dedicated.renewedRental renewed—
dedicated.releasedRental released or cancelled; inspect reasonreason
dedicated.completedRental cleanup completed—

Field meanings and final warnings​

  • Dates (created_at, paid_until, starts_at, ends_at, delete_after, release_after, bandwidth_limited_until) are UTC timestamps; optional dates can be null. Byte counters are integers. limit_mbps is a speed limit in Mbps, or null.
  • status describes the affected resource, not the delivery. reason describes the transition, for example payment_expired. Do not treat reason strings as the entire event identity.
  • hours_before is the warning interval. delete_after is the VPS/IPv4 deletion or release deadline; release_after is the dedicated rental deadline.
  • resources_applied / traffic_applied indicate which parts of a resize were applied. requires_review=true means the result needs clarification before another command.
  • period_id and quota_revision identify the traffic period and its quota revision. additional_bytes is the added/current quota according to the event; total_additional_bytes is the total after a top-up. remaining_bytes is the remaining quota.
  • guest_configuration_required=true means the customer's OS network configuration needs attention. addresses contains resulting addresses; keep_ip/keep_ips expresses retention. Read current VPS/IP details for the resulting state.
  • resume_pending, auto_start and auto_started describe restoration after payment. Renewal success does not necessarily mean the VPS is already running.

vm.deleting_soon, ip.releasing_soon and dedicated.releasing_soon warn one hour before removal after the 24-hour unpaid grace period. They are forwarded even when auto-renewal is off or cannot charge the balance. When enabled, Cloud API makes the final renewal attempt. The warning still describes its original deadline; inspect renewal events or the current resource to learn the outcome.

Example final VPS warning:

{
"event": "vm.deleting_soon",
"timestamp": "2026-09-29T11:00:00.000Z",
"data": {
"event_id": 701,
"created_at": "2026-09-29T11:00:00+00:00",
"vm_id": 101,
"api_user_id": "customer-123",
"paid_until": "2026-09-28T12:00:00+00:00",
"hours_before": 1,
"delete_after": "2026-09-29T12:00:00+00:00",
"reason": "payment_expired"
}
}

Signature verification​

X-Webhook-Signature is the lowercase hexadecimal HMAC-SHA256 of the exact raw request bytes, signed with the integration's webhook secret. The secret is not sent. Verify the original bytes before parsing JSON; re-serializing JSON changes the signature input.

const crypto = require('node:crypto');

function verifySignature(rawBody, secret, signature) {
if (typeof signature !== 'string' || !/^[a-f0-9]{64}$/.test(signature)) {
return false;
}

const expected = crypto
.createHmac('sha256', secret)
.update(rawBody)
.digest();

return crypto.timingSafeEqual(expected, Buffer.from(signature, 'hex'));
}

rawBody must be the original Buffer from your HTTP server, before its JSON middleware.

Acknowledgement, repeats and delivery​

  1. Verify the signature and save the event.
  2. Apply it once: for resource events deduplicate by integration and data.event_id; for order results use integration, data.order_id and event.
  3. Return HTTP 200 or 201 after accepting the event. No response body is required. Other codes, including 202 and 204, do not acknowledge delivery.

The HTTP timeout is 10 seconds. Once accepted by the delivery service, an unsuccessful delivery has up to 10 attempts, with delays after the preceding failed attempt:

AttemptDelay
1Immediately
260 seconds
3120 seconds
4300 seconds
5600 seconds
6900 seconds
71800 seconds
83600 seconds
97200 seconds
107200 seconds

Delivery order is not guaranteed. A late warning must not overwrite a newer paid term in your billing. Recheck current state when events conflict. Order results and resource events can describe the same action; avoid granting the service or crediting a refund twice.

A webhook is not a guarantee that every result reaches your server. If absent, query orders, VPS, rentals or IPs. Delivery history is in the dashboard, not a separate public history endpoint. Some supported events, such as vm.ip.replaced, do not imply there is a matching public replacement route; follow the published route catalog.

© 2026 AdaptGroup LLC. All rights reserved.
30 N Gould St Ste R, Sheridan, WY 82801, USA
Back to top