Gareth Wilson Gareth Wilson

Guide to Reditus Webhooks: Features and Best Practices

Published


Reditus runs affiliate programmes and in-app customer referral programmes for B2B SaaS companies, tracking who referred whom and what commission or reward they've earned. Its webhooks tell your product when an affiliate joins, a referral or lead is created, or a reward is generated, which is when you'd typically send a welcome email, apply a Stripe discount or post to Slack.

This guide walks through the five Reditus events and their data fields, verifying X-Signature, and the large parts of delivery that Reditus' docs leave out.

What are Reditus webhooks?

Reditus has two programme types, and the events split along the same line. The affiliate programme, where partners promote your product for commission, sends partnership.accepted and referral.created. The referral programme, where your own users invite others through an in-app widget, sends advocate.created, lead.created and reward.created.

Reditus describes its webhooks as an alternative to polling its API, and its docs say more events are planned on request.

Reditus webhook features

FeatureDetails
Signaturehex HMAC-SHA256
Signature headerx-signature
BodyJSON
Event routingBody field event_type

Reditus' webhook docs cover signing in detail, with verification samples in Ruby, Go, Python, Node, .NET, PHP and Java. They don't describe how to register an endpoint, where the secret comes from, the HTTP method, the Content-Type, timeouts or retries.

Events and payloads

Route on the top-level event_type.

| Event routing | Body field event_type |

Each event has its own data fields:

Eventdata fields
partnership.acceptedaffiliate_name, affiliate_email, affiliate_first_name, affiliate_last_name, accepted_at
referral.createdaffiliate_email, referral_id, referral_uid (your internal ID), referral_email
advocate.createdadvocate_uid (your internal ID), advocate_id, advocate_slug, advocate_referral_link, advocate_first_name, advocate_last_name, advocate_email, advocate_company, advocate_company_id
lead.createdadvocate_uid, lead_id, lead_uid (your internal ID), lead_email
reward.createdamount (sample 5521 = $55.21, so minor units), currency, advocate_uid, lead_id, reward_id, custom_text (only with custom reward triggers)

Every body also has url and created_at. created_at is a date, such as 2024-05-05, with no time, and there's no event ID. Fields ending _uid hold your own IDs, which you pass to Reditus when you track referrals and authenticate advocates, so you can match them to your records directly.

The partnership.accepted example from Reditus' docs:

{
  "event_type": "partnership.accepted",
  "url": "destination-url@example.com",
  "created_at": "2024-05-05",
  "data": {
    "affiliate_name": "Acme",
    "affiliate_email": "john@acme.com",
    "affiliate_first_name": "John",
    "affiliate_last_name": "Doe",
    "accepted_at": "2024-05-05"
  }
}

The other four examples on Reditus' event pages contain // comments, and in reward.created one sits inside a value, so none of them parse as JSON. Use them as field lists only.

Setting up Reditus webhooks

Reditus doesn't document the setup steps or where the webhook secret is shown. Look for webhook settings in your Reditus dashboard, or ask Reditus support to add your endpoint and give you the secret. Store it as REDITUS_WEBHOOK_SECRET and use it as plain UTF-8 text.

To use Hookdeck, create a Reditus source with that secret and give Reditus the source URL as the endpoint. To forward to a local server while testing:

npx hookdeck-cli listen 3000 reditus --path /webhooks/reditus

HTTP Method

Reditus's docs don't name the HTTP method. The linked skill examples accept GET, POST, PUT, PATCH and DELETE on /webhooks/reditus and verify the signature on each. If you receive through Hookdeck, note that Hookdeck's Reditus source pre-selects POST without managing the method, so any other method Reditus uses must also be allowed on the source.

Securing Reditus webhooks

X-Signature is the hex HMAC-SHA256 of the raw request body, keyed with the webhook secret. The header holds only the digest. All seven of Reditus' samples compute it the same way, and the Ruby one is the clearest: OpenSSL::HMAC.hexdigest("SHA256", webhook_secret, raw_body). Nothing time-based is signed.

Node.js verification

const crypto = require('node:crypto');

function verifySignature(rawBody, headers, secret) {
  if (!Buffer.isBuffer(rawBody) || typeof secret !== 'string' || !secret) return false;
  const signature = headers['x-signature'];
  if (typeof signature !== 'string') return false;
  const key = Buffer.from(secret, 'utf8');
  const message = rawBody;
  const candidates = [signature];
  const expected = crypto.createHmac('sha256', key).update(message).digest();
  return candidates.some((candidate) => {
    if (!/^[0-9a-fA-F]{64}$/.test(candidate)) return false;
    const received = Buffer.from(candidate, 'hex');
    return received.length === expected.length && crypto.timingSafeEqual(received, expected);
  });
}

The handler accepts any method, as described above, and branches on the referral programme events. lead_id plus event_type is the deduplication key, because Reditus sends no event ID.

const express = require('express');

const app = express();

app.all('/webhooks/reditus', express.raw({ type: '*/*' }), async (req, res) => {
  const secret = process.env.REDITUS_WEBHOOK_SECRET;
  if (!secret) return res.sendStatus(500);
  const body = Buffer.isBuffer(req.body) ? req.body : Buffer.alloc(0);
  if (!verifySignature(body, req.headers, secret)) return res.sendStatus(401);
  if (!body.length) return res.sendStatus(200);

  let parsed;
  try {
    parsed = JSON.parse(body.toString('utf8'));
  } catch {
    return res.sendStatus(400);
  }
  if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) return res.sendStatus(400);
  const eventType = parsed.event_type;
  const data = parsed.data && typeof parsed.data === 'object' ? parsed.data : {};

  try {
    switch (eventType) {
      case 'reward.created':
        await grantReward(data.reward_id, data.advocate_uid, data.amount, data.currency);
        break;
      case 'lead.created':
        await createReferralDiscount(data.lead_uid, data.lead_id);
        break;
      case 'partnership.accepted':
        await sendAffiliateWelcome(data.affiliate_email, data.affiliate_first_name);
        break;
      default:
        console.log('Unhandled Reditus event', eventType);
    }
  } catch {
    return res.sendStatus(503);
  }

  res.sendStatus(200);
});

Hookdeck's Reditus source checks the same X-Signature. It answers 200 and records mismatches as failed verification instead of rejecting them, and applies no time window.

Make Reditus webhooks production-ready. Hookdeck Event Gateway records every Reditus delivery, so you can see what Reditus actually sends and replay a reward or referral your service missed.

Reditus webhook limitations and pain points

Delivery behaviour is undocumented

The Problem: You don't know whether a failed delivery is retried, how long Reditus waits, or what response it expects.

Why It Happens: Reditus' webhook pages cover the signature and the payloads only. The HTTP method, Content-Type, timeout and retry policy aren't stated.

Workarounds:

  • Respond with 200 as soon as the event is stored.
  • After an outage, reconcile affiliate referrals and commissions against the Reditus Affiliate Program API.

How Hookdeck Can Help: Hookdeck accepts the delivery immediately and retries your service until it succeeds, so you aren't relying on unknown retry behaviour.

No setup or secret documentation

The Problem: It's unclear where to register an endpoint or find the secret.

Why It Happens: The docs show verification code that uses webhook_secret, but don't say where it's issued.

Workarounds:

  • Check the Reditus dashboard settings, or ask Reditus support.
  • Once you have it, test with a real event before relying on it.

How Hookdeck Can Help: Hookdeck's request log shows whether incoming requests pass verification, which confirms quickly that you have the right secret.

No event ID, and created_at is only a date

The Problem: Telling a duplicate from a new event, or ordering events from the same day, is guesswork.

Why It Happens: The envelope is event_type, url, created_at and data, and created_at has no time component.

Workarounds:

  • Use the Reditus object ID in data (reward_id, lead_id, referral_id) with event_type as the key.
  • Record your own receive time for ordering.

How Hookdeck Can Help: Hookdeck deduplication can match on event_type and an ID field in data within a time window.

Example payloads aren't valid JSON

The Problem: Copying Reditus' examples into tests breaks your parser.

Why It Happens: Four of the five examples include // comments, and the reward.created one has a comment inside the amount value.

Workarounds:

  • Remove comments and build fixtures by hand.
  • Capture real deliveries and use those as fixtures.

How Hookdeck Can Help: Hookdeck stores the exact body of each real delivery, which makes a better test fixture than the docs.

Best practices

Treat amount as minor units

The reward.created example shows 5521 for $55.21. Divide by the currency's minor unit, and store the currency with it.

Make reward grants safe to repeat

Granting a hoodie or a discount twice costs money. Check reward_id before acting, and see the idempotency guide for patterns.

Store first, then call Stripe or email

Creating a discount or sending email can be slow. Queue the event and acknowledge it, as described in asynchronous webhook processing.

Pass your own IDs to Reditus

The _uid fields only help if you set them. Pass your user and referral IDs when you track conversions and authenticate advocates, so webhook data maps straight to your records.

Conclusion

Reditus webhooks cover five affiliate and referral programme events, signed with a hex HMAC-SHA256 in X-Signature. The signature is well documented. Delivery, setup and retries aren't, and there's no event ID, so build in deduplication and reconciliation from the start.

Hookdeck Event Gateway verifies Reditus requests, records what arrives and retries delivery to your service.

Get started with Hookdeck for free and handle Reditus webhooks reliably in minutes.


Gareth Wilson

Gareth Wilson

Product Marketing

Multi-time founding marketer, Gareth is PMM at Hookdeck and author of the newsletter, Community Inc.