← View All Guides
Webhooks logo
Integration Guide

How to Build Custom Reward Fulfillment with GrowSurf Webhooks

Create a webhook-based system that automatically fulfills custom referral rewards when participants earn them.

GrowSurf handles referral tracking and determines when participants earn rewards β€” but the actual reward delivery is where your business logic lives. Custom reward fulfillment via webhooks lets you deliver any type of reward: account credits, feature unlocks, gift cards, physical merchandise, subscription upgrades, or anything else your creativity allows.

This guide covers building a webhook-based reward fulfillment system that processes GrowSurf reward events, validates eligibility, delivers the reward through your chosen method, confirms delivery back to the participant, and handles failures gracefully. You'll build a system that's reliable enough to handle your most valuable customers' rewards.

Integration Steps

Step 1: Design Your Reward Fulfillment Logic

Map out what happens when a participant earns a reward, including validation, delivery, and confirmation.

  • Define your reward types and delivery methods:
    • Account credits β†’ update user balance in your database
    • Feature unlock β†’ flip a feature flag or upgrade plan
    • Gift cards β†’ call gift card API (e.g., Tremendous, Tango Card)
    • Discount codes β†’ generate unique codes in your e-commerce platform
    • Physical rewards β†’ create a fulfillment order in your shipping system
  • Define eligibility rules: does the participant need to meet additional criteria?
  • Plan the confirmation flow: how will the participant know their reward was delivered?

Step 2: Set Up the Reward Webhook Handler

Create an endpoint that processes GrowSurf's PARTICIPANT_REACHED_REWARD event.

  • Listen for the PARTICIPANT_REACHED_REWARD event specifically
  • Extract reward details: reward type, tier, participant info
  • Validate that the participant is eligible (not already rewarded, account active, etc.)
  • Route to the appropriate fulfillment function based on reward type

Step 3: Implement Reward Delivery Functions

Build the actual reward delivery logic for each reward type.

  • For account credits: update the user's balance in your application database and create a transaction record
  • For feature unlocks: call your feature flag service (LaunchDarkly, Flagsmith) or update the user's plan
  • For gift cards: call the gift card provider's API to purchase and send a card
  • For each type: return a success/failure status and delivery confirmation details

Step 4: Track Reward Fulfillment Status

Maintain a database of all reward fulfillments for auditing and customer support.

  • Create a reward_fulfillments table with columns: participant_id, reward_type, status, delivered_at, details
  • Log every fulfillment attempt with status: pending, delivered, failed, reversed
  • Use this table for idempotency checks (prevent double-fulfillment)
  • Build an admin dashboard showing fulfillment history and pending rewards

Step 5: Confirm Delivery to the Participant

Notify participants that their reward has been successfully delivered.

  • Send a confirmation email with reward details (code, credit amount, etc.)
  • Update the participant's GrowSurf metadata with fulfillment status via API
  • If using in-app rewards, show a notification in your product UI
  • Include next steps: how to use the reward, expiration date, support contact

Step 6: Handle Failures and Edge Cases

Build robust error handling for when reward delivery fails.

  • If delivery fails, mark as "pending_retry" and attempt again after a delay
  • After 3 failed attempts, alert your support team for manual intervention
  • Handle edge cases: participant deleted their account, reward already claimed, provider API down
  • Implement reward reversal logic for refund/chargeback scenarios

Code Snippets

// Custom Reward Fulfillment Handler
const db = require('./database');
const giftCardService = require('./gift-card-service');
const emailService = require('./email-service');

// Reward fulfillment functions by type
const rewardFulfillers = {
  account_credit: async (participant, amount) => {
    const user = await db.users.findByEmail(participant.email);
    if (!user) throw new Error('User not found');

    await db.users.addCredit(user.id, amount);
    return { type: 'credit', amount, userId: user.id };
  },

  feature_unlock: async (participant, featureName) => {
    const user = await db.users.findByEmail(participant.email);
    await db.features.unlock(user.id, featureName);
    return { type: 'feature', feature: featureName, userId: user.id };
  },

  gift_card: async (participant, amount) => {
    const card = await giftCardService.create({
      amount: amount,
      recipientEmail: participant.email,
      recipientName: participant.firstName
    });
    return { type: 'gift_card', cardId: card.id, amount };
  }
};

// Main reward webhook handler
app.post('/webhooks/growsurf/reward', async (req, res) => {
  const { event, participant } = req.body;

  if (event !== 'PARTICIPANT_REACHED_REWARD') {
    return res.status(200).json({ skipped: true });
  }

  // Idempotency check
  const existing = await db.fulfillments.findByParticipant(participant.id);
  if (existing && existing.status === 'delivered') {
    return res.status(200).json({ message: 'Already fulfilled' });
  }

  res.status(200).json({ received: true }); // Respond quickly

  try {
    // Determine reward type from campaign configuration
    const rewardConfig = { type: 'account_credit', amount: 1000 }; // $10
    const fulfiller = rewardFulfillers[rewardConfig.type];

    const result = await fulfiller(participant, rewardConfig.amount);

    // Log fulfillment
    await db.fulfillments.create({
      participantId: participant.id,
      rewardType: rewardConfig.type,
      status: 'delivered',
      details: result,
      deliveredAt: new Date()
    });

    // Send confirmation email
    await emailService.send(participant.email, 'reward-confirmation', {
      name: participant.firstName,
      rewardDetails: result
    });

  } catch (error) {
    await db.fulfillments.create({
      participantId: participant.id,
      status: 'failed',
      error: error.message
    });
    console.error('Reward fulfillment failed:', error);
  }
});

Tips

Always Fulfill Before Confirming

Never send a reward confirmation email before the reward is actually delivered. If the delivery fails after sending confirmation, the participant has a bad experience and your support team has a headache. Confirm only after successful delivery.

Build an Admin Override System

Create an admin interface that lets your team manually fulfill, reverse, or re-process rewards. Automated systems fail sometimes, and having a manual fallback prevents participant frustration and reduces support load.

Monitor Reward Costs in Real Time

Track total reward costs (credits issued, gift cards sent, features unlocked) in real time. Set up alerts when daily or monthly reward costs exceed thresholds. This catches both program success (great!) and potential fraud (bad!) early.

FAQ

What happens if my reward fulfillment server is down when GrowSurf sends the webhook?

GrowSurf retries failed webhooks with exponential backoff. As long as your server comes back up within the retry window, the reward event will be processed. For extra safety, implement a periodic job that queries GrowSurf's API for unfulfilled rewards and processes any that were missed.

Can I support multiple reward types in the same campaign?

Yes. Use GrowSurf's reward tiers to define different reward levels (e.g., first referral gets a credit, fifth referral gets a gift card). In your webhook handler, check the participant's referral count or reward tier to determine which fulfillment function to call.

How do I handle reward fulfillment for rewards that require shipping?

For physical rewards, your fulfillment handler should create an order in your shipping/fulfillment system (e.g., ShipStation, Shopify Fulfillment) and send the participant a confirmation email with estimated delivery dates. Track the shipping status and send updates as the order progresses.

Set up your refer a friend program with customer referral and affiliate program software that lowers your acquisition costs, increases customer loyalty, and saves you gobs of time.

Trusted by marketing and product teams at fast-growing B2C, fintech, and SaaS companies