Webhooks
Get real-time notifications about events in your affiliate program.
Overview
Refgrow's webhook system allows you to receive HTTP POST notifications about important events in your affiliate program. This enables you to integrate Refgrow with your internal systems for automated conversion processing, notifications, and analytics.
Supported Events
| Event | Description | When it triggers |
|---|---|---|
referral_signed_up | New user signed up via referral link | When a user registers through a referral link |
referral_converted | Referral converted to paying customer | When a referred user makes a purchase |
referral_canceled | Conversion canceled or refunded | When a payment is refunded or canceled |
referral_updated | Conversion updated or modified | When a conversion is created or updated via API |
Payout Preferences in Webhooks
Webhook payloads automatically include PayPal and Wise payout preferences when available. This allows finance systems to process payouts directly from webhook data without requiring additional API calls.
Payout Preferences Structure
{
"referrer": {
"id": "456",
"email": "affiliate@example.com",
"payout_preferences": {
"paypal_email": "affiliate@example.com",
"wise_details": {
"accountId": "wise_account_123",
"email": "affiliate@example.com"
}
}
}
}- No need to call
GET /api/v1/affiliates/:emailto enrich webhook data - Automatic payout processing directly from webhook payloads
- Reduced API calls and faster integration setup
- Payout preferences are retrieved from both
client_payment_settingsand custom attributes
Note: The payout_preferences field is only included when an affiliate has configured PayPal email or Wise payment details. If no payout preferences are configured, this field will be omitted from the payload.
Setting up Webhooks
1. Creating a Webhook
- Go to Project Settings → "Webhooks" tab
- Click "Add Webhook" button
- Enter your endpoint URL (e.g.:
https://yourapp.com/webhooks/refgrow) - Select the events you want to receive
- Optional: Generate a secret key for signature verification
- Save the settings
2. Testing Your Webhook
After creating a webhook, you can test it:
- In the webhooks table, click the test button next to your webhook
- Select the event type to test
- Click "Send Test" - the system will send test data
- Check the delivery status and server response
Payload Format
All webhooks are sent as HTTP POST requests with JSON payload.
referrer.payout_preferences field when available. This eliminates the need for manual API enrichment steps.Request Headers
Content-Type: application/json
User-Agent: Refgrow-Webhooks/1.0
X-Refgrow-Event: referral_converted
X-Refgrow-Signature: sha256=abc123... (if signature is configured)referral_signed_up
{
"event": "referral_signed_up",
"timestamp": 1703123456,
"project_id": "123",
"referrer": {
"id": "456",
"email": "affiliate@example.com",
"payout_preferences": {
"paypal_email": "affiliate@example.com",
"wise_details": {
"accountId": "wise_account_123",
"email": "affiliate@example.com"
}
}
},
"referred": {
"id": "789",
"email": "customer@example.com"
},
"data": {
"referral_code": "REF123",
"signup_date": "2024-01-15T10:00:00Z",
"user_agent": "Mozilla/5.0...",
"ip_address": "192.168.1.1"
}
}referral_converted
{
"event": "referral_converted",
"timestamp": 1703123456,
"project_id": "123",
"referrer": {
"id": "456",
"email": "affiliate@example.com",
"payout_preferences": {
"paypal_email": "affiliate@example.com",
"wise_details": {
"accountId": "wise_account_123",
"email": "affiliate@example.com"
}
}
},
"referred": {
"id": "789",
"email": "customer@example.com"
},
"conversion": {
"id": "conv_123",
"amount": 99.99,
"currency": "USD",
"commission_amount": 19.99,
"commission_type": "percentage",
"commission_rate": 20,
"payment_processor": "stripe",
"product_id": "prod_abc123",
"order_id": "order_456",
"conversion_date": "2024-01-15T10:30:00Z"
}
}referral_canceled
{
"event": "referral_canceled",
"timestamp": 1703123456,
"project_id": "123",
"referrer": {
"id": "456",
"email": "affiliate@example.com",
"payout_preferences": { ... }
},
"referred": {
"id": "789",
"email": "customer@example.com"
},
"conversion": {
"id": "conv_123",
"amount": 99.99,
"commission_amount": 19.99,
"refund_amount": 99.99,
"reason": "Customer requested refund",
"canceled_date": "2024-01-16T14:20:00Z"
}
}referral_updated
{
"event": "referral_updated",
"timestamp": 1703123456,
"project_id": "123",
"referrer": {
"id": "456",
"email": "affiliate@example.com",
"payout_preferences": { ... }
},
"referred": {
"id": "789",
"email": "customer@example.com"
},
"conversion": {
"id": "conv_123",
"amount": 99.99,
"amount_usd": 19.99,
"commission_amount": 19.99,
"base_value": 99.99,
"conversion_date": "2024-01-15T10:30:00Z",
"reference": "order_456"
}
}Signature Verification
If you configured a secret key, each webhook will contain an HMAC-SHA256 signature in the X-Refgrow-Signature header.
Signature Verification (PHP)
function verifySignature($payload, $signature, $secret) {
$expectedSignature = 'sha256=' . hash_hmac('sha256', $payload, $secret);
return hash_equals($expectedSignature, $signature);
}
// Usage
$payload = file_get_contents('php://input');
$signature = $_SERVER['HTTP_X_REFGROW_SIGNATURE'] ?? '';
$secret = 'your_webhook_secret';
if (!verifySignature($payload, $signature, $secret)) {
http_response_code(401);
exit('Invalid signature');
}Signature Verification (Node.js)
const crypto = require('crypto');
function verifySignature(payload, signature, secret) {
const expectedSignature = 'sha256=' + crypto
.createHmac('sha256', secret)
.update(payload, 'utf8')
.digest('hex');
return crypto.timingSafeEqual(
Buffer.from(expectedSignature),
Buffer.from(signature)
);
}
// Express middleware
app.use('/webhooks/refgrow', express.raw({type: 'application/json'}), (req, res) => {
const signature = req.headers['x-refgrow-signature'];
const secret = process.env.REFGROW_WEBHOOK_SECRET;
if (!verifySignature(req.body, signature, secret)) {
return res.status(401).send('Invalid signature');
}
// Process webhook
const event = JSON.parse(req.body);
console.log('Received event:', event.event);
res.status(200).send('OK');
});Implementation Examples
Basic PHP Handler
<?php
header('Content-Type: application/json');
$payload = file_get_contents('php://input');
$event = json_decode($payload, true);
switch ($event['event']) {
case 'referral_signed_up':
$referrerEmail = $event['referrer']['email'];
$referredEmail = $event['referred']['email'];
sendEmailNotification($referrerEmail, "New referral: $referredEmail");
break;
case 'referral_converted':
$commissionAmount = $event['conversion']['commission_amount'];
$referrerEmail = $event['referrer']['email'];
// Get payout preferences if available
$payoutPreferences = $event['referrer']['payout_preferences'] ?? null;
if ($payoutPreferences) {
$paypalEmail = $payoutPreferences['paypal_email'] ?? null;
$wiseDetails = $payoutPreferences['wise_details'] ?? null;
if ($paypalEmail) {
processPayPalPayout($referrerEmail, $commissionAmount, $paypalEmail);
} elseif ($wiseDetails) {
processWisePayout($referrerEmail, $commissionAmount, $wiseDetails);
}
}
updatePartnerCommission($referrerEmail, $commissionAmount);
break;
case 'referral_canceled':
$refundAmount = $event['conversion']['refund_amount'];
$referrerEmail = $event['referrer']['email'];
adjustPartnerCommission($referrerEmail, -$refundAmount);
break;
}
http_response_code(200);
echo json_encode(['status' => 'success']);
?>Express.js Handler
const express = require('express');
const app = express();
app.post('/webhooks/refgrow', express.raw({type: 'application/json'}), async (req, res) => {
try {
const event = JSON.parse(req.body);
switch (event.event) {
case 'referral_signed_up':
await handleReferralSignup(event);
break;
case 'referral_converted':
await handleReferralConversion(event);
break;
case 'referral_updated':
await handleReferralUpdate(event);
break;
case 'referral_canceled':
await handleReferralCancellation(event);
break;
default:
console.log('Unknown event type:', event.event);
}
res.status(200).json({ received: true });
} catch (error) {
console.error('Webhook error:', error);
res.status(400).send('Webhook Error');
}
});
async function handleReferralConversion(event) {
const { referrer, conversion } = event;
const payoutPreferences = referrer.payout_preferences;
if (payoutPreferences) {
const { paypal_email, wise_details } = payoutPreferences;
if (paypal_email) {
await processPayPalPayout(referrer.email, conversion.commission_amount, paypal_email);
} else if (wise_details) {
await processWisePayout(referrer.email, conversion.commission_amount, wise_details);
}
}
await db.updatePartnerStats(referrer.id, {
totalCommissions: conversion.commission_amount,
lastConversionDate: new Date()
});
}Monitoring and Logs
Viewing Delivery Logs
In the webhook settings you can:
- View delivery history for each webhook
- See HTTP status codes and response times
- Analyze delivery errors
- Retry failed webhooks
Successful Delivery
HTTP Status: 200-299
Response Time: <5 seconds
Delivery Error
HTTP Status: 400+ or timeout
Automatic Retries: 3 attempts
Best Practices
Security
- Always verify webhook signatures
- Use HTTPS endpoints
- Store secret keys securely
- Restrict endpoint access
Performance
- Respond quickly (within 10 seconds)
- Return HTTP 200 on success
- Handle duplicate events
- Use queues for heavy operations
Troubleshooting
Webhook not being delivered
- Check that the URL is publicly accessible
- Ensure your server responds with HTTP 200
- Check delivery logs in the admin panel
- Use the test webhook for diagnostics
- Check firewall and security settings
Signature verification error
- Make sure you are using the correct secret key
- Verify you are reading the raw request body
- Compare your signature algorithm with examples
- Check encoding (should be UTF-8)
Duplicate events
Webhooks may be delivered multiple times in case of errors. Implement idempotency:
- Use event IDs for deduplication
- Store processed events in database
- Check for existing records before processing
Testing Endpoint
You can use a test endpoint to verify your webhook implementation:
curl -X POST https://yourdomain.com/webhook/test \
-H "Content-Type: application/json" \
-H "X-Refgrow-Signature: sha256=test_signature" \
-d '{
"event": "referral_converted",
"timestamp": 1703123456,
"project_id": "test",
"referrer": {"id": "123", "email": "test@example.com"},
"referred": {"id": "456", "email": "customer@example.com"},
"conversion": {"amount": 99.99, "commission_amount": 19.99}
}'API Reference
Test Webhook Endpoint
POST /api/project/{projectId}/webhooks/{webhookId}/test
Sends a test webhook with generated test data.
Parameters:
{
"eventType": "referral_converted"
}Response:
{
"success": true,
"status": 200,
"response": "OK"
}