> ## Documentation Index
> Fetch the complete documentation index at: https://docs.rankly.live/llms.txt
> Use this file to discover all available pages before exploring further.

# Vote Webhooks

> Handle vote webhook events for your server listing.

Use vote webhooks when you want Rankly to notify your service about verified votes.

## Vote webhook

Use this for voter rewards, role grants, or vote analytics.

### What Rankly sends

When a vote is processed, Rankly posts a small JSON payload to the webhook URL saved on the server.

Example payload:

```json theme={null}
{
  "userId": "123456789012345678",
  "serverId": "987654321098765432",
  "timestamp": "2026-01-01T12:00:00.000Z",
  "creditsAwarded": true,
  "adBlocker": false,
  "creditDenialReason": null
}
```

A test delivery uses the same shape and may include `test: true`.

### Set it up

<Steps>
  <Step title="Use a public HTTPS endpoint">
    Your webhook must be reachable over HTTPS. Localhost and private/internal addresses are rejected.
  </Step>

  <Step title="Save the URL in Rankly">
    Add the endpoint in your server settings, then optionally set an Authorization header if your backend expects one.
  </Step>

  <Step title="Send a test request">
    Use the dashboard test action before relying on live vote traffic.
  </Step>

  <Step title="Return 2xx quickly">
    Acknowledge the request fast and do your heavier work asynchronously.
  </Step>
</Steps>

### Example receiver

```javascript theme={null}
import express from 'express';

const app = express();
app.use(express.json());

app.post('/rankly/vote', async (req, res) => {
  const auth = req.header('Authorization');
  if (auth !== `Bearer ${process.env.RANKLY_WEBHOOK_SECRET}`) {
    return res.status(401).json({ error: 'unauthorized' });
  }

  const { userId, serverId, creditsAwarded, creditDenialReason } = req.body;

  // Update your database or trigger a reward here.
  console.log({ userId, serverId, creditsAwarded, creditDenialReason });

  return res.status(200).json({ received: true });
});
```

## Security notes

* Keep the endpoint public, but keep the processing logic private.
* Verify the Authorization header if you set one in Rankly.
* Treat deliveries as at-least-once and dedupe by `userId`, `serverId`, and `timestamp`.
* Never point a webhook at localhost, a private subnet, or an internal admin panel.

## Common issues

* No delivery at all: check the saved URL and whether the test request succeeds.
* 4xx response: fix your endpoint auth or JSON parsing.
* Repeated events: add deduplication before issuing rewards.
* No credits awarded: the vote may still be counted, but the payload will explain why credits were denied.

## Related docs

<CardGroup cols={2}>
  <Card title="Server Premium Webhooks" href="/servers/premium-webhooks">
    Handle signed monetization events for server premium purchases.
  </Card>
</CardGroup>
