Webhooks
Receive signed HTTP callbacks when your services are provisioned, change state, or come under DDoS attack.
Webhooks let your systems react to changes on your GameServerKings account in real time —
provisioning progress, service state changes, and DDoS attacks on your IPs — by receiving a signed
HTTP request at a URL you control.
- Configure: Client Area → Profile → Notifications → Webhooks → Manage webhooks
(/client-area/webhooks). - One endpoint per account. Choose which event types it receives, view a delivery log, resend a
delivery, rotate your signing secret, and send a test event.
Delivery mechanics
- Every event is delivered as an HTTP
POSTwith a JSON body to your endpoint URL. - Your URL must be HTTPS and must resolve to a public address. Redirects are not followed.
- Respond with any
2xxstatus to acknowledge. Respond within 10 seconds — slower responses
are treated as failures. - Anything other than
2xx(or a timeout / connection error) is retried with exponential
backoff: up to 8 attempts starting at 30 seconds and roughly doubling each time (about two
hours of total coverage). - Delivery is at-least-once: a delivery may arrive more than once (e.g. your server accepted it
but the acknowledgement was lost). De-duplicate on the eventid. - Ordering is not guaranteed. Retries can reorder events. Use the envelope
createdAtto order
events yourself. - If your endpoint fails every delivery across the full retry window for 5 consecutive events,
it is automatically disabled and we email you. Re-enable it from the Webhooks page once it is
reachable again. A single successful delivery resets the counter.
Request headers
| Header | Description |
|---|---|
Content-Type |
Always application/json. |
User-Agent |
GameServerKings-Webhooks/1. |
X-GSK-Event-Id |
The event's unique id (same as the body id). Use for idempotency. |
X-GSK-Event-Type |
The event type, e.g. service.active. |
X-GSK-Signature |
Signature used to verify authenticity — see below. |
Verifying signatures
Every request is signed with HMAC-SHA256 using your endpoint's signing secret (shown on the
Webhooks page, prefixed whsec_). Verify each request before trusting it:
- Read the
X-GSK-Signatureheader. It is a comma-separated list of fields, for examplet=1720031400,v1=5f2b…. Thetfield is the Unix timestamp (seconds) at signing. Eachv1
field is a candidate signature in lowercase hex. - Build the signed string by joining the timestamp, a literal
., and the exact raw request
body (do not re-serialize the JSON):"{t}.{raw_body}". - Compute
HMAC-SHA256(signed_string)keyed with your signing secret, as lowercase hex. - Accept the request if your computed value equals any
v1field (use a constant-time
comparison). Multiplev1values appear only during a secret rotation — see below. - Reject requests whose
tis outside your tolerance window (5 minutes is recommended) to protect
against replay.
Rotating the secret
Rotating generates a new secret and keeps the previous one valid for 24 hours. During that
window requests carry two v1 signatures — one for each secret — so a deployment that has not
yet picked up the new secret keeps validating. Update your stored secret and the old signature
simply stops appearing after the window ends.
Envelope
Every payload shares the same top-level envelope. The event-specific content lives under data.
| Field | Type | Description |
|---|---|---|
id |
string | Unique event id. Stable across redeliveries — de-duplicate on this. |
type |
string | Event type (see the catalog below). |
createdAt |
string | ISO-8601 timestamp of when the event occurred. |
data |
object | Event-specific payload. Shape depends on type. |
{
"id": "clzq1a2b3c4d5e6f7g8h9i0j",
"type": "service.active",
"createdAt": "2026-07-03T18:42:11.000Z",
"data": { }
}
Service lifecycle events
These describe the lifecycle of a service you purchased. A service is identified by its own id
and is independent of whether it runs on shared or dedicated infrastructure — the concrete backing
resource is reported separately as detail.
Event types
| Type | When it fires |
|---|---|
service.provisioning |
Provisioning has started for the service. |
service.active |
The service is live and ready (also fires after an update or unsuspend completes). |
service.updating |
A configuration or build change is being applied. |
service.suspended |
The service has been suspended. |
service.cancelled |
The service has been cancelled or removed. |
service.failed |
Provisioning or a lifecycle action failed. |
data fields
| Field | Type | Description |
|---|---|---|
service.id |
number | Stable service identifier. |
service.type |
string | SHARED (game hosting) or DEDICATED (dedicated hardware). |
service.deliveredAt |
string | null | When the service first became active. |
service.suspendedAt |
string | null | When the service was suspended, if applicable. |
service.canceledAt |
string | null | When the service was cancelled, if applicable. |
billable |
object | null | The recurring contract behind the service (null if none). |
billable.id |
number | Billable (subscription) id. |
billable.status |
string | PENDING, ACTIVE, FAILED, SUSPENDED, or CANCELLED. |
billable.currency |
string | ISO currency code, e.g. USD. |
billable.price |
number | Recurring price in the currency's minor units (e.g. cents). |
billable.periodStart |
string | Start of the current billing period. |
billable.periodEnd |
string | End of the current billing period. |
billable.autoRenew |
boolean | Whether the subscription auto-renews. |
resource.type |
string | Same as service.type (SHARED / DEDICATED). |
resource.id |
number | Id of the concrete backing server/machine. |
resource.status |
string | null | The backing resource's internal status (more granular than the event). |
Example (service.active)
{
"id": "clzq1a2b3c4d5e6f7g8h9i0j",
"type": "service.active",
"createdAt": "2026-07-03T18:42:11.000Z",
"data": {
"service": {
"id": 4821,
"type": "SHARED",
"deliveredAt": "2026-07-03T18:42:11.000Z",
"suspendedAt": null,
"canceledAt": null
},
"billable": {
"id": 9155,
"status": "ACTIVE",
"currency": "USD",
"price": 1200,
"periodStart": "2026-07-03T18:42:11.000Z",
"periodEnd": "2026-08-03T18:42:11.000Z",
"autoRenew": true
},
"resource": {
"type": "SHARED",
"id": 4821,
"status": "ACTIVE"
}
}
}
DDoS attack events
Attack events relay the same information as the Discord/email attack alerts, for DDoS attacks on IP
addresses attached to your account. They are not filtered by your Discord/email alert thresholds
— subscribing your endpoint to the event type is the only filter. Each attack produces at most oneattack.started and one attack.ended.
Event types
| Type | When it fires |
|---|---|
attack.started |
A DDoS attack on one of your IPs is first detected. |
attack.ended |
A previously reported attack has ended. |
data fields
| Field | Type | Description |
|---|---|---|
attack.eventId |
string | Upstream attack identifier — the same value on the start and end events. |
attack.ipAddress |
string | The IP under attack. |
attack.status |
string | Raw upstream marker (start / end); prefer the event type. |
attack.pps |
number | Peak packets per second observed. |
attack.mbps |
number | Peak megabits per second observed. |
attack.startedAt |
string | null | When the attack started. |
attack.endedAt |
string | null | When the attack ended (present on attack.ended). |
attack.machineId |
number | null | Your machine the IP belongs to, if it maps to one. |
attack.serverName |
string | null | That machine's name, if available. |
Example (attack.ended)
{
"id": "clzq7p8q9r0s1t2u3v4w5x6y",
"type": "attack.ended",
"createdAt": "2026-07-03T19:05:44.000Z",
"data": {
"attack": {
"eventId": "atk_8f21c0",
"ipAddress": "203.0.113.24",
"status": "end",
"pps": 1450000,
"mbps": 8800,
"startedAt": "2026-07-03T18:58:02.000Z",
"endedAt": "2026-07-03T19:05:40.000Z",
"machineId": 312,
"serverName": "fra-dedi-07"
}
}
}
Test event
The Send test event button on the Webhooks page delivers a ping to verify your endpoint and
signature wiring end-to-end. It is not a subscribable type — it is only ever sent on demand.
{
"id": "clzq0t1e2s3t4p5i6n7g8ev9",
"type": "ping",
"createdAt": "2026-07-03T20:00:00.000Z",
"data": {
"message": "This is a test event from GameServerKings."
}
}
Event type reference
| Type | Category | Subscribable |
|---|---|---|
service.provisioning |
Service lifecycle | Yes |
service.active |
Service lifecycle | Yes |
service.updating |
Service lifecycle | Yes |
service.suspended |
Service lifecycle | Yes |
service.cancelled |
Service lifecycle | Yes |
service.failed |
Service lifecycle | Yes |
attack.started |
DDoS attack | Yes |
attack.ended |
DDoS attack | Yes |
ping |
Test | No (sent on demand) |