Skip to main content

Webhooks

Webhooks V2 allow you to receive real-time event notifications via POST requests to a URL of your choice. This is the recommended way to listen for events such as votes on your project.

Supported Scopes

ScopeDescription
webhook.testTest webhook sent from the dashboard.
vote.createFired when a user votes for your project.

Security

Each webhook integration is assigned a webhook secret (prefixed whs_). Use this secret to verify that incoming requests are genuinely from Top.gg.

The secret is provided either during integration setup or through your project's dashboard.

Signature Verification

Every webhook request includes an x-topgg-signature header with the following format:

t={unix timestamp},v1={signature}

To verify a request:

  1. Capture the raw body — Preserve the exact bytes Top.gg sent before any parsing or formatting.
  2. Extract the header — Parse the x-topgg-signature header to get the timestamp (t) and signature (v1).
  3. Compute the expected signature — Create an HMAC SHA-256 digest using your webhook secret as the key and {timestamp}.{rawBody} as the message.
  4. Compare — If the computed digest matches the v1 value from the header, the request is authentic.

If verification fails, the request may have been tampered with, the secret may be incorrect, or the request did not originate from Top.gg. Reject it with an appropriate error status.

Headers

HeaderDescription
x-topgg-signatureSignature in the format t={timestamp},v1={hmac_sha256_hex}.
x-topgg-traceA trace ID for debugging and correlating requests with Top.gg support.

Acknowledgement

Webhooks must be acknowledged with a 2xx response to be considered successful. Unsuccessful webhooks are retried.

Timeouts

Responses must be returned within 5 seconds, otherwise they are considered timed out and will be queued for a retry.

Retrial

Webhook requests that time out or return a 5XX status response will be retried up to 3 times. The retry delay increases exponentially per retry by 2^N seconds, from a minimum delay of 1 second up to approximately 8 seconds for the third retry.

Events

vote.create

Fired when a user votes for your project.

Payload

FieldTypeDescription
typestringAlways "vote.create".
data.idsnowflakeUnique identifier for this vote.
data.weightnumberThe number of votes this vote counted for. This is a rounded integer value which determines how many points this individual vote was worth.
data.created_atDateTimestamp of when the vote was cast.
data.expires_atDateTimestamp of when the vote expires (user can vote again).
data.project.idsnowflakeThe Top.gg project ID.
data.project.typestringThe project type (e.g. "bot").
data.project.platformstringThe platform the project belongs to (e.g. "discord").
data.project.platform_idsnowflakeThe platform-specific ID for the project.
data.user.idsnowflakeThe Top.gg user ID of the voter.
data.user.platform_idsnowflakeThe platform-specific ID of the voter.
data.user.namestringThe voter's username.
data.user.avatar_urlstringURL to the voter's avatar.

Example Payload

{
"type": "vote.create",
"data": {
"id": "808499215864008704",
"weight": 1,
"created_at": "2026-02-09T00:47:14.2510149+00:00",
"expires_at": "2026-02-09T12:47:14.2510149+00:00",
"project": {
"id": "803190510032756736",
"type": "bot",
"platform": "discord",
"platform_id": "160105994217586689"
},
"user": {
"id": "top.gg id",
"platform_id": "discord id",
"name": "username",
"avatar_url": "<avatar url>"
}
}
}

webhook.test

A test event that can be triggered from the dashboard to verify your webhook endpoint is working correctly. This scope is always enabled and cannot be disabled.

Payload

FieldTypeDescription
typestringAlways "webhook.test".
data.user.idsnowflakeThe Top.gg user ID of the user who triggered the test.
data.user.platform_idsnowflakeThe platform-specific ID of the user.
data.user.namestringThe user's username.
data.user.avatar_urlstringURL to the user's avatar.
data.project.idsnowflakeThe Top.gg project ID.
data.project.typestringThe project type (e.g. "bot").
data.project.platformstringThe platform the project belongs to (e.g. "discord").
data.project.platform_idsnowflakeThe platform-specific ID for the project.

Example Payload

{
"type": "webhook.test",
"data": {
"user": {
"id": "top.gg id",
"platform_id": "discord id",
"name": "username",
"avatar_url": "<avatar url>"
},
"project": {
"id": "803190510032756736",
"type": "bot",
"platform": "discord",
"platform_id": "160105994217586689"
}
}
}

Example Implementation

We've prepared an example of the full webhook recieve code for you to reference while you build your implementation. You can find the link on the top-gg github here.