GrowthRailDocs

How Webhooks Work

Reward Granted
Eligibility checks pass
Webhook Queued
Payload built and enqueued
POST Sent
Signed request to your endpoint
Logged
Result stored for debugging

Creating a Webhook

In the Growth Rail dashboard, go to Integrations → Reward Webhooks, then click Add Webhook.

Add New Webhook Dialog
Enter a name, endpoint URL, and shared secret token to configure a new webhook.
FieldRequiredDescription
nameYesA descriptive label (e.g. "Credits Service", "Notification Handler").
urlYesThe HTTPS endpoint on your server that receives POST requests.
secretYesA shared secret sent as a Bearer token in the Authorization header.
enabledNoWhether this webhook is active. Defaults to true. Disabled webhooks receive no events.

Webhook Payload

Growth Rail sends a POST request with Content-Type: application/json and your secret in the Authorization: Bearer header.

HeaderValue
X-GrowthRail-Delivery-IdStable delivery identifier for deduplication
AuthorizationBearer <secret>
POST https://api.yourapp.com/webhooks/growth-rail
{
  "event": "user_signup",
  "referrerId": "user_alice",
  "refereeId": "user_bob",
  "rewardClaimedAt": "2025-03-01T10:00:00.000Z",
  "trackingId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "rewardStatus": "Completed",
  "projectId": "proj_k8xn2m",
  "projectName": "MyApp Production",
  "campaignId": "cam_r3f9t2"
}
FieldTypeDescription
eventstringThe trigger event name that caused the reward (e.g. user_signup).
referrerIdstringThe clientProvidedId of the referrer. Use this to credit the reward.
refereeIdstringThe clientProvidedId of the new user who was referred.
rewardClaimedAtstringISO 8601 UTC timestamp of when the reward was granted.
trackingIdstringUUID of the referral tracking record. Use as an idempotency key.
rewardStatusstringAlways "Completed" when the webhook fires.
projectIdstringThe project's uniqueId. Useful when sharing one endpoint across projects.
projectNamestringHuman-readable project name.
campaignIdstringThe campaign's uniqueId.

Handling Webhooks

Your endpoint must return a 2xx HTTP response promptly (within a few seconds). Verify the secret, acknowledge immediately, then process asynchronously.

server/webhooks.ts
router.post('/webhooks/growth-rail', express.json(), async (req, res) => {
  // 1. Verify the webhook secret
  const authHeader = req.headers.authorization;
  if (authHeader !== `Bearer ${process.env.GR_WEBHOOK_SECRET}`) {
    return res.sendStatus(401);
  }

  // 2. Always acknowledge receipt immediately
  res.sendStatus(200);

  // 3. Process the reward asynchronously using trackingId as idempotency key
  const { referrerId, trackingId, rewardStatus } = req.body;
  if (rewardStatus === 'Completed') {
    // Your business logic here — credit the referrer, send a notification, etc.
  }
});

Verifying Webhook Authenticity

Growth Rail sends your webhook secret as a Bearer token in the Authorization header. Always compare it with the secret configured for that webhook before processing the payload.

Verification middleware
function verifyWebhook(req, res, next) {
  const expected = 'Bearer ' + process.env.GR_WEBHOOK_SECRET;
  const received = req.headers.authorization;

  if (received !== expected) {
    console.warn('Invalid webhook authentication');
    return res.sendStatus(401);
  }

  next();
}

// Apply to your webhook route
app.post('/webhooks/growth-rail', verifyWebhook, express.json(), handler);
Never skip verification. Reject requests whose Bearer token does not match your configured webhook secret, otherwise anyone who discovers your endpoint URL could send fake reward payloads and credit users fraudulently.

Idempotency

Webhooks may be delivered more than once due to network retries or redelivery from the dashboard. Always use the trackingId field as an idempotency key in your database before processing any reward — check whether the trackingId has already been handled and skip if so.

Retry Behavior

Growth Rail retries transient failures. Authentication and other permanent client errors are dead-lettered immediately so a broken secret does not repeatedly hit your endpoint.

PropertyValue
Max attempts5 (initial + 4 retries)
Retry intervalExponential backoff with jitter, starting at about 5 seconds
Timeout10 seconds total — respond quickly
Manual retryAvailable from the dashboard or via POST /webhooks/logs/{logId}/retry
Respond quickly. Always return 200 immediately and process the reward asynchronously. Long-running webhook handlers will cause timeouts and unnecessary retries.

Monitoring & Logs

The dashboard shows delivery logs for each webhook with full details:

Accessing Webhook Logs
Click 'View Logs' next to any configured webhook in the dashboard to inspect delivery logs.
Log FieldDescription
TimestampWhen the delivery attempt was made
Event typeThe trigger event name
HTTP statusStatus code returned by your endpoint
Response timeRound-trip time in milliseconds
SuccessWhether the delivery was successful

Managing Webhooks

All webhook management is available from the Growth Rail dashboard under Integrations → Reward Webhooks.

ActionHow
DisableToggle the webhook off to pause delivery without deleting it. Re-enable anytime.
Retry a failed deliveryClick the retry button on any failed log entry in the delivery logs.
DeletePermanently removes the webhook and all its delivery logs.
EditUpdate the endpoint URL, name, or secret at any time.

Best Practices

Always verify the Bearer token against your webhook secret
Respond with 200 immediately, then process asynchronously
Use trackingId for idempotency — webhooks may be delivered more than once
Use HTTPS endpoints in production for encrypted delivery
Monitor delivery logs in the dashboard to catch failures early
!Don't do heavy processing in the webhook handler — use a job queue for slow tasks