---
title: "What does the RevenueDot webhook event TEST mean?"
description: "TEST is sent by the dashboard's Send test event or the webhook test API. It is shaped like a purchase, for no real customer. Use it to check your endpoint and signature check."
url: https://revenuedot.app/docs/webhooks/webhook-test
---

# What does the RevenueDot webhook event TEST mean?

The RevenueDot webhook event TEST is a sample event that RevenueDot sends only when you ask for a test delivery.

## Quick facts

| | |
|---|---|
| Event | `TEST` |
| Where | RevenueDot webhook (`event.type`), RevenueCat's webhook format |
| Sent to | Every enabled webhook whose filters match |
| What it means | Sent by the dashboard's "Send test event" or `POST .../integrations/webhooks/{id}/test`. Shaped like a purchase, for no real customer, so it never carries `experiments`. |

## When it is sent

- You pressed Send test event in the dashboard, or called the test endpoint of the webhook.
- It is shaped like a purchase so that your parser meets every field.
- It is for no real customer.

## What your server should do

1. Answer HTTP 200 and do not grant anything.
2. Use it to check your signature verification against the real header.
3. Look in the dashboard's delivery log if it does not arrive.
4. Deduplicate on `event.id`: deliveries can repeat, because anything but HTTP 200 is retried after 5, 10, 20, 40 and 80 minutes.

## Example

```javascript
import { createHmac, timingSafeEqual } from "node:crypto";

// X-RevenueCat-Webhook-Signature: t=<unix seconds>,v1=<hex HMAC-SHA256 of "<t>.<raw body>">
function verify(rawBody, header, secret, toleranceSeconds = 300) {
  const m = /^t=(\d+),v1=([0-9a-f]{64})$/.exec(header ?? "");
  if (!m || Math.abs(Date.now() / 1000 - Number(m[1])) > toleranceSeconds) return false;
  const expected = createHmac("sha256", secret).update(`${m[1]}.${rawBody}`).digest();
  return timingSafeEqual(expected, Buffer.from(m[2], "hex"));
}

// Sign a sample delivery the way RevenueDot does, then handle it.
const secret = "whsec_test_secret";
const rawBody = JSON.stringify({ api_version: "1.0", event: {"id":"66339910-3BFF-49F4-B873-D1283D673DE2","type":"TEST","app_user_id":"user_1","product_id":"pro_monthly","period_type":"NORMAL"} });
const t = Math.floor(Date.now() / 1000);
const header = `t=${t},v1=${createHmac("sha256", secret).update(`${t}.${rawBody}`).digest("hex")}`;

const seen = new Set(); // use a database table in production

function handle(rawBody, header) {
  if (!verify(rawBody, header, secret)) return "401 bad signature";
  const { event } = JSON.parse(rawBody);
  if (seen.has(event.id)) return "200 duplicate";
  seen.add(event.id);
  if (event.type !== "TEST") return "200 ignored";
  return "200, check the signature works, change nothing";
}

console.log(handle(rawBody, header));
```

*Run-checked: `npm run check:snippets` runs this snippet with Node and compares its output with `check the signature works` (checked 2026-10-03).*

## How RevenueDot produces it

The webhook test route (`routes/v2/partner-integrations.ts`) builds a `TEST` event shaped like a purchase for no real customer, stores it and queues it to the webhook you tested, where it is signed like any delivery. It never carries `experiments`.

## Related

- [What does the RevenueDot webhook event INITIAL_PURCHASE mean?](https://revenuedot.app/docs/webhooks/webhook-initial-purchase.md)
- [What does the RevenueDot webhook event RENEWAL mean?](https://revenuedot.app/docs/webhooks/webhook-renewal.md)
- [What does the RevenueDot webhook event CANCELLATION mean?](https://revenuedot.app/docs/webhooks/webhook-cancellation.md)
- [TEST fields and a recorded example payload](https://revenuedot.app/docs/api/webhook-events.md#test)
- [Webhooks guide: set up, verify and test](https://revenuedot.app/docs/guides/webhooks.md)

## Source

- [RevenueDot docs: which webhook events RevenueDot sends](https://revenuedot.app/docs/api/webhook-events)
- [RevenueCat: webhook event types and fields (the format RevenueDot follows)](https://www.revenuecat.com/docs/integrations/webhooks/event-types-and-fields)
- [RevenueDot core: events.ts (the event types and the rules that derive them)](https://github.com/revenuedot/revenuedot/blob/main/packages/core/src/events.ts)
- [RevenueDot server: routes/v2/partner-integrations.ts (the test event)](https://github.com/revenuedot/revenuedot/blob/main/apps/server/src/routes/v2/partner-integrations.ts)
- [RevenueDot server: services/webhooks.ts (signing and delivery)](https://github.com/revenuedot/revenuedot/blob/main/apps/server/src/services/webhooks.ts)

Checked: 2026-10-03
