# Webhooks

Webhooks are used to send events from ReferralHero to your server. You can decide which events to send to your server.

To enable webhooks:

* go to your campaign dashboard > *Edit Campaign > Integrations > Webhooks*
* Click on the **+ New Webhook** button
* In the popup, add your endpoint URL and toggle the events you want to receive
* Click on **Create Webhook**

<figure><img src="/files/IE6PfDzCdM8wtNEmMlUg" alt=""><figcaption></figcaption></figure>

***

### Webhook Payload Verification

To ensure that your webhook payloads are authentic and have not been tampered with, ReferralHero includes a signature header in every webhook request. You can use this signature to validate requests.

⚠️ **Important:** Make sure to **enable the “Payload Verification” toggle**. Once enabled, a secret key will be generated. This key is required to decode and validate the signature header in your application that receives the webhook.

<figure><img src="/files/TWzfwthfzHyiLN9XqlFR" alt=""><figcaption></figcaption></figure>

***

### Where to Find Your Webhook Secret Key

You can find your Webhook Secret Key in two places:

**Option 1: From Profile Menu**

1. Log in to your **ReferralHero dashboard**.
2. Click on your **profile button** (top-right corner).
3. In the popup, select **Webhook Secret**.
4. You will see your **Webhook Secret Key** along with an option to **regenerate** it if needed.

<figure><img src="/files/ycwIyo2bPDOddRP7FhOu" alt=""><figcaption></figcaption></figure>

**Option 2: From Campaign Settings**

1. Log in to your ReferralHero dashboard.
2. Click **Edit Campaign** for the campaign you want.
3. Go to the **Integration** tab.
4. Click on **Webhook**, and you will see the Webhook Secret Key.

<figure><img src="/files/YddN3pocO4u0KgHaueFh" alt=""><figcaption></figcaption></figure>

Use this secret key in your server code to verify incoming webhooks.

***

### Steps to Verify a Webhook

1. **Read the raw request body** (e.g., `request.raw_post` in Rails).
2. **Retrieve the signature** from the `X-ReferralHero-Signature` header.
3. **Recompute the HMAC-SHA256 hash** of the raw body using your Webhook Secret Key as the secret.
4. **Compare** your computed value with the signature header. If they match, the webhook is valid.

***

Code Examples

{% tabs %}
{% tab title="Ruby" %}

```ruby
require 'openssl'
require 'base64'

class WebhooksController < ActionController::API
  skip_before_action :verify_authenticity_token

  def receive
    raw_payload = request.raw_post
    signature   = request.headers['X-ReferralHero-Signature']
    secret      = ENV['REFERRALHERO_API_KEY']

    computed_signature = Base64.strict_encode64(
      OpenSSL::HMAC.digest('sha256', secret, raw_payload)
    )

    unless ActiveSupport::SecurityUtils.secure_compare(signature.to_s, computed_signature)
      render json: { error: 'Invalid signature' }, status: :unauthorized and return
    end

    data = JSON.parse(raw_payload)
    # handle data...
    head :ok
  end
end

```

{% endtab %}

{% tab title="Python (Flask)" %}

```python
from flask import Flask, request, abort
import hmac, hashlib, base64, os

app = Flask(__name__)

@app.route('/webhook', methods=['POST'])
def webhook():
    raw = request.get_data()
    signature = request.headers.get('X-ReferralHero-Signature', '')
    secret = os.environ['REFERRALHERO_API_KEY'].encode()

    digest = hmac.new(secret, raw, hashlib.sha256).digest()
    computed = base64.b64encode(digest).decode()

    if not hmac.compare_digest(signature, computed):
        abort(401)
    data = request.get_json()
    # handle data...
    return '', 200
```

{% endtab %}

{% tab title="Node.js (Express)" %}

```javascript
const express = require('express');
const crypto  = require('crypto');

const app = express();
app.use(express.raw({ type: 'application/json' }));

app.post('/webhook', (req, res) => {
  const rawBody = req.body; // Buffer
  const signature = req.header('X-ReferralHero-Signature') || '';
  const secret = process.env.REFERRALHERO_API_KEY;

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

  if (!timingSafeEqual(signature, computed)) {
    return res.status(401).send('Invalid signature');
  }

  const data = JSON.parse(rawBody.toString('utf8'));
  // process data...
  res.sendStatus(200);
});

function timingSafeEqual(a, b) {
  const bufA = Buffer.from(a || '');
  const bufB = Buffer.from(b || '');
  if (bufA.length !== bufB.length) return false;
  return crypto.timingSafeEqual(bufA, bufB);
}

```

{% endtab %}
{% endtabs %}

***

✅ **Backward Compatible**: If you do not check this header, your existing webhooks will continue to work without any changes.\
🔒 **Recommended**: Implement signature validation to ensure authenticity and security of incoming webhooks.

### Events

ReferralHero sends a `POST HTTP` request with a `JSON` payload when specific events occur.

There are 6 types of events:

#### **new\_registration**

{% tabs %}
{% tab title="Description" %}
Sent when a new person subscribes to your list. If you the confirmation email is disabled,  the event is sent as soon as the person is subscribed to the list.
{% endtab %}

{% tab title="Response" %}

```yaml
{
  response: "new_registration",
  list_uuid: "MFXXXX", //The UUID of your list
  subscriber_id: "sub_123ABC", // Subscriber's ID
  name: "John Doe", //Subscriber's name
  first_name: "John",
  last_name: "Doe",
  email: "john.doe@email.com", //Subscriber's email
  extra_field: "+1 2348891123", // Subscriber's extra field's value
  extra_field_2: "USA", // Subscriber's second extra field's value
  code: "2hg36dvs", //Subscriber's unique referral code
  source: "facebook", //Subscriber's source. If the subscriber doesn't have a source the value will be "direct_visit"
  referred: true,
  referrer: {
    subscriber_id: "sub_123CCD",
    people_referred: 2,
    referral_link: "http://mywebsite.com/LINK_PLAIN",
    points: 3,
    last_referral_at: 1702017953,
    name: "Mark Doe",
    first_name: "Mark",
    last_name: "Doe",
    email: "mark@yahoo.com"
    extra_field: "+1 2348894454",
    extra_field_2: "USA",
    option_field: "Los Angeles",
    code: "fd336dff",
    phone_number: "+1 2348894454",
    crypto_wallet_address: "0x0000000000000000000000000000000000000011"
  }, //This property can have 3 possible values: an empty string (if the subscriber has not been referred), an object containing data of the referral (if the subscriber has been referred) or "subscriber_deleted" (if the subscriber has been referred but the user has been deleted.)
  referral_link: "http://mywebsite.com/LINK_PLAIN",
  created_at: 1234567889 // Timestamp of the subscriber's sign up
}
```

{% endtab %}
{% endtabs %}

#### **subscriber\_promoted**

{% tabs %}
{% tab title="Description" %}
Sent when a subscriber is promoted.
{% endtab %}

{% tab title="Response" %}

```yaml
{
  response: "subscriber_promoted",
  list_uuid: "MFXXXX",
  subscriber_id: "sub_123ABC",
  source: "facebook",
  referred: false,
  referral: {
    subscriber_id: "sub_123CCD",
    people_referred: 2,
    referral_link: "http://mywebsite.com/LINK_PLAIN",
    points: 3,
    last_referral_at: 1702017953,
    name: "Mark Doe",
    first_name: "Mark",
    last_name: "Doe",
    email: "mark@yahoo.com"
    extra_field: "+1 2348894454",
    extra_field_2: "USA",
    option_field: "Los Angeles",
    code: "fd336dff",
    phone_number: "+1 2348894454",
    crypto_wallet_address: "0x0000000000000000000000000000000000000011"
  },
  people_referred: 3, //Number of people referred
  referral_link: "http://mywebsite.com/LINK_PLAIN",
  created_at: 1234567889 // Timestamp of the subscriber's promotion
  name: "John Doe", //Subscriber's name
  first_name: "John",
  last_name: "Doe",
  email: "john.doe@email.com" //Subscriber's email
  extra_field: "+1 2348891123", // Subscriber's extra field's value
  extra_field_2: "USA", // Subscriber's second extra field's value
  option_field: "Florida", // Subscriber's option field's value
  code: "2hg36dvs",
  phone_number: "+1 2348891123",
  crypto_wallet_address: "0x0000000000000000000000000000000000000000"
}
```

{% endtab %}
{% endtabs %}

#### **subscriber\_updated**

{% tabs %}
{% tab title="Description" %}
Sent when a subscriber field is updated.
{% endtab %}

{% tab title="Response" %}

```yaml
{
"response": "subscriber_fields_updated",
"list_uuid": "MF833ac6ee2d", // Unique list identifier
"subscriber_id": "sub_61ad4723e3a9", // Unique ID of the subscriber
"source": "referral", // Source of the subscriber (e.g., referral, direct_visit)
"referred": false, // Whether the subscriber was referred
"referral": null,
"referral_link": "https://campaign.referralhero.com/MF833ac6ee2d/signup?mwr=1296cda7", // Personalized referral URL
"people_referred": 0,
"created_at": 1746795375, // Timestamp of subscriber creation
"last_referral_at": null,
"name": "Jane Doe", // Full name
"first_name": "Jane", // First name
"last_name": "Doe", // Last name
"email": "jane.doe@example.com", // Email address
"extra_field": "Company ABC",
"extra_field_2": "Product Manager",
"extra_field_3": "New York",
"extra_field_4": "Referral Campaign A",
"option_field": "Option 1",
"code": "1296cda7",
"phone_number": "+1234567890", // Phone number
"crypto_wallet_address": "0xABCDEF1234567890"
}
```

{% endtab %}
{% endtabs %}

#### **subscriber\_deleted**

{% tabs %}
{% tab title="Description" %}
Sent when a subscriber is deleted.
{% endtab %}

{% tab title="Response" %}

```yaml
{
  response: "subscriber_deleted",
  list_uuid: "MFXXXX",
  subscriber_id: "sub_123ABC",
  last_referral_at: 1702017953,
  name: "John Doe", //Subscriber's name
  first_name: "John",
  last_name: "Doe",
  email: "john.doe@email.com" //Subscriber's email
  extra_field: "+1 2348891123", // Subscriber's extra field's value
  extra_field_2: "USA", // Subscriber's second extra field's value
  option_field: "Florida", // Subscriber's option field's value
  code: "2hg36dvs",
  phone_number: "+1 2348891123",
  crypto_wallet_address: "0x0000000000000000000000000000000000000000"
}
```

{% endtab %}
{% endtabs %}

#### **reward\_unlocked**

{% tabs %}
{% tab title="Description" %}
Sent immediately when a subscriber qualifies for and unlocks a reward.
{% endtab %}

{% tab title="Response" %}

```yaml
{
"response": "reward_unlocked",
"list_uuid": "MFABC123",
"subscriber_id": "sub_ABC123",
"bonus_id": 178, // Unique ID of the reward unlocked
"reward_name": "$100 Giftcard", // Name of reward
"reward_value": 100, // Value of the reward if set
"name": "John Smith", // Subscriber's full name
"first_name": "John",
"last_name": "Smith",
"email": "john.smith@email.com", // Subscriber's email
"extra_field": null, // Custom field #1 (optional)
"extra_field_2": null, // Custom field #2 (optional)
"extra_field_3": null, // Custom field #3 (optional)
"extra_field_4": null, // Custom field #4 (optional)
"code": "YYY999", // Unique referral code
"people_referred": 5, // Number of successful referrals
"referral_link": "ReferralHero | Referral Program Software for B2B & B2C Brands ", // Personalized referral URL
"phone_number": "", // Subscriber's phone number
"crypto_wallet_address": "" // Wallet address if used
}
```

{% endtab %}
{% endtabs %}

#### **reward\_sent**

{% tabs %}
{% tab title="Description" %}
Sent when a reward is actually delivered to the subscriber. This happens only after conditions like 'Hold until manually reviewed' or 'Hold for X days' are fulfilled or Reward delivery set to\
'Unlock and send reward immediately'.
{% endtab %}

{% tab title="Response" %}

```yaml
{
"response": "reward_sent",
"list_uuid": "MFABC123",
"subscriber_id": "sub_ABC123",
"bonus_id": 178, // Unique ID of the reward sent
"reward_name": "$100 Giftcard", // Name of reward
"reward_value": 100, // Value of the reward if set
"name": "John Smith", // Subscriber's full name
"first_name": "John",
"last_name": "Smith",
"email": "john.smith@email.com", // Subscriber's email
"extra_field": null, // Custom field #1 (optional)
"extra_field_2": null, // Custom field #2 (optional)
"extra_field_3": null, // Custom field #3 (optional)
"extra_field_4": null, // Custom field #4 (optional)
"code": "YYY999", // Unique referral code
"people_referred": 5, // Number of successful referrals
"referral_link": "https://referralhero.com/?mwr=YYY999", // Personalized referral URL
"phone_number": "", // Subscriber's phone number
"crypto_wallet_address": "" // Wallet address if used
}
```

{% endtab %}
{% endtabs %}

### Errors

Please send back a blank response with a status code of `200`. \
All not-200 responses will be considered errors. After 10 consecutive bad responses, the webhook will be disabled.

If a webhook fails, we will try to deliver it 3 times over a period of 5 minutes.

### How to test a webhook

To test a webhook just click on the **Test** button next to the webhook URL you want to test.\
We will ping your webhook URL with a JSON file containing fake data.


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://support.referralhero.com/campaign-builder/integrations/webhooks.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
