# Refgrow -- LLM Integration Context > Refgrow is a SaaS platform for creating affiliate and referral programs. It provides an embeddable widget, tracking scripts, REST API, webhook system, and MCP server. Supports Stripe, LemonSqueezy, Paddle, and Polar as payment providers. This document provides complete context for AI coding assistants to integrate Refgrow into any web application. Last updated: 2026-03-19. --- ## Table of Contents 1. [What is Refgrow?](#what-is-refgrow) 2. [Quick Integration (3 Steps)](#quick-integration) 3. [Tracking Script -- Detailed Setup](#tracking-script) 4. [Affiliate Dashboard Widget](#affiliate-dashboard-widget) 5. [Payment Provider Integration](#payment-provider-integration) - [Stripe](#stripe-integration) - [LemonSqueezy](#lemonsqueezy-integration) - [Paddle](#paddle-integration) 6. [REST API Reference](#rest-api-reference) - [Authentication](#api-authentication) - [Affiliates](#affiliates-api) - [Conversions](#conversions-api) - [Referrals](#referrals-api) - [Coupons](#coupons-api) - [Error Handling](#error-handling) - [Rate Limits](#rate-limits) 7. [Webhook Events](#webhook-events) 8. [Widget Customization](#widget-customization) 9. [MCP Server](#mcp-server) 10. [Framework Integration Examples](#framework-integration-examples) 11. [Troubleshooting](#troubleshooting) --- ## What is Refgrow? Refgrow is an affiliate/referral program platform for SaaS businesses. It lets you: - Add a tracking script to detect referral clicks and set cookies - Embed an affiliate dashboard widget where affiliates track performance and earnings - Automatically track conversions via webhook integrations with Stripe, LemonSqueezy, Paddle, and Polar - Manage affiliates, referrals, conversions, and coupons via REST API - Use an MCP server for AI-assisted affiliate program management - Configure commissions (percentage or fixed), per-product and per-affiliate overrides - Pay affiliates via PayPal, Wise, or manually - Support 20+ languages out of the box Website: https://refgrow.com Docs: https://refgrow.com/docs API Base URL: https://refgrow.com/api/v1 --- ## Quick Integration ### Step 1: Add Tracking Script Add to the `` of all pages: ```html ``` Replace `YOUR_PROJECT_ID` with your actual project ID from the Refgrow dashboard. ### Step 2: Embed Affiliate Dashboard Add where you want the affiliate dashboard to appear: **With user email (user is logged in):** ```html
``` **Without user email (standalone affiliate page):** ```html
``` ### Step 3: Track User Registrations (Optional) After successful user signups, call: ```javascript Refgrow(0, 'signup', 'user@example.com'); ``` ### Step 4: Connect Payment Provider Choose your payment provider in the Refgrow dashboard Integration tab: - **Stripe** -- Automatic webhook setup. Enter your Stripe Secret Key. - **LemonSqueezy** -- Create webhook at `https://refgrow.com/webhook/lemonsqueezy/YOUR_PROJECT_ID` - **Paddle** -- Create webhook at `https://refgrow.com/webhook/paddle/YOUR_PROJECT_ID` - **Polar** -- Create webhook at `https://refgrow.com/webhook/polar/YOUR_PROJECT_ID` - **Manual tracking** -- Use `Refgrow(amount, 'purchase', 'email')` or the REST API --- ## Tracking Script ### Script URL ``` https://scripts.refgrowcdn.com/latest.js ``` ### Data Attributes | Attribute | Default | Description | |---------------------|-----------------|------------------------------------------------| | `data-project-id` | (required) | Your Refgrow project ID | | `data-param` | `ref` | URL parameter name for the referral code | | `data-cookie-days` | `90` | Cookie expiration in days | | `data-cookie-domain`| Current domain | Cookie domain for cross-subdomain tracking | ### Example with Custom Options ```html ``` With this configuration, referral links use `?via=CODE` instead of `?ref=CODE`, cookies expire after 30 days, and the cookie is shared across all subdomains of `yoursite.com`. ### What the Tracking Script Does - Detects when users arrive via referral links (`?ref=CODE`) - Stores the referral code in a first-party cookie - Enables manual conversion tracking via the `Refgrow()` function - Provides helper methods for Stripe Payment Links and Paddle/LemonSqueezy links ### Manual Conversion Tracking ```javascript // Track a signup (no monetary value) Refgrow(0, 'signup', 'user@example.com'); // Track a purchase (with monetary value) Refgrow(49.99, 'purchase', 'user@example.com'); ``` Parameters: 1. `value` (number) -- Monetary value (use 0 for non-monetary events) 2. `type` (string) -- Event type ('signup', 'purchase', or custom) 3. `email` (string) -- User's email (used for attribution) ### Reading the Referral Cookie (Client-Side) ```javascript function getRefgrowRef() { const match = document.cookie.match( /(?:^|;\s*)ref=([^;]*)/ ); return match ? decodeURIComponent(match[1]) : null; } const referralCode = getRefgrowRef(); if (referralCode) { console.log('Referred by:', referralCode); } ``` ### Server-Side Cookie Reading (Node.js/Express) ```javascript app.post('/signup', async (req, res) => { const referralCode = req.cookies.ref; if (referralCode) { await fetch('https://refgrow.com/api/store-attribution', { method: 'POST', headers: { 'Authorization': 'Bearer rgk_YOUR_API_KEY', 'Content-Type': 'application/json' }, body: JSON.stringify({ email: req.body.email, referral_code: referralCode }) }); } }); ``` ### Cross-Domain Tracking **Same root domain** (e.g., `yoursite.com` and `app.yoursite.com`): ```html data-cookie-domain=".yoursite.com" ``` **Different domains:** Configure your tracking domain in Refgrow project settings. The tracking script will append the referral code as a URL parameter when users navigate between domains. ### Content Security Policy (CSP) If your site uses CSP headers: ``` Content-Security-Policy: script-src 'self' https://scripts.refgrowcdn.com https://refgrow.com; connect-src 'self' https://refgrow.com; ``` ### Privacy & GDPR The tracking script sets a first-party cookie scoped to your domain. It does not use third-party cookies, fingerprinting, or cross-site tracking. The cookie contains only the referral code and is not used for advertising. You can load the script conditionally after cookie consent. --- ## Affiliate Dashboard Widget ### Script URL ``` https://scripts.refgrowcdn.com/page.js ``` ### Data Attributes | Attribute | Required | Description | |----------------------|-------------|-------------------------------------------------------| | `data-project-id` | Yes | Your Refgrow project ID | | `data-project-email` | Recommended | Current user's email for auto-login | | `data-lang` | No | Language code (e.g., `en`, `de`, `fr`). Auto-detected. | ### With User Authentication ```html
``` ### Without User Authentication ```html
``` Users will need to enter their email and verify it to access the dashboard. ### Programmatic Control ```javascript // Identify a user after login Refgrow.identify('user@example.com'); // Switch language Refgrow.setLanguage('de'); // Listen for events Refgrow.on('affiliate:signup', (data) => { console.log('New affiliate signed up:', data.email); }); ``` ### Supported Languages English, Spanish, French, German, Portuguese, Italian, Dutch, Swedish, Norwegian, Danish, Finnish, Polish, Czech, Romanian, Hungarian, Russian, Ukrainian, Turkish, Japanese, Korean, Chinese (Simplified), Arabic, Hebrew. ### Widget Blocks The widget is composed of configurable blocks. Enable, disable, and reorder from project settings. Available blocks: - `header` -- program title and description - `share_links` -- referral URL with copy button - `coupon_code` -- affiliate's assigned coupon code - `stats` -- click count, referral count, conversion metrics - `daily_stats` -- daily performance chart - `earnings` -- total and pending commission amounts - `payment_methods` -- payout configuration - `payment_history` -- past payouts with status - `commission_levels` -- multilevel commission progress (paid plans) - `multi_tier` -- sub-affiliate earnings (paid plans) - `promotional_materials` -- banners, text links, social share templates Block configuration format (stored in `projects.widget_blocks_config`): ```json [ { "id": "header", "enabled": true, "order": 1 }, { "id": "share_links", "enabled": true, "order": 2 }, { "id": "coupon_code", "enabled": true, "order": 3 }, { "id": "stats", "enabled": true, "order": 4 }, { "id": "daily_stats", "enabled": true, "order": 5 }, { "id": "earnings", "enabled": true, "order": 6 }, { "id": "payment_methods", "enabled": true, "order": 7 }, { "id": "payment_history", "enabled": false, "order": 8 }, { "id": "commission_levels", "enabled": false, "order": 9 }, { "id": "multi_tier", "enabled": false, "order": 10 }, { "id": "promotional_materials", "enabled": false, "order": 11 } ] ``` ### Widget Appearance Customizable in project settings: - Primary Color (buttons and highlights) - Secondary Color (secondary elements and accents) - Font Color (text color) - Title (headline text) - Description (program explanation) On paid plans (Starter and above), the "Powered by Refgrow" footer can be removed. --- ## Payment Provider Integration ### Stripe Integration Webhook URL: `https://refgrow.com/webhook/stripe/{your-project-id}` (auto-configured) #### Setup 1. Go to project's "Integration" tab 2. Select "Stripe Webhooks" as tracking method 3. Enter your Stripe Secret Key (restricted key recommended) 4. Click "Connect Stripe" 5. Refgrow auto-configures the webhook endpoint in your Stripe account #### Passing Referral Codes to Stripe **For Stripe Checkout Sessions:** ```javascript const refCode = req.cookies.refgrow_ref_code; const session = await stripe.checkout.sessions.create({ // ... other session parameters metadata: { referral_code: refCode || null } }); ``` **For Stripe Payment Links (automatic):** ```html Buy Now ``` ```javascript if (window.Refgrow) { Refgrow.processStripePaymentLinks(); } ``` **For Stripe Payment Links (programmatic redirect):** ```javascript if (window.Refgrow) { Refgrow.redirectToStripePaymentLink('https://buy.stripe.com/xyz...'); } ``` #### Attribution Priority (Stripe) Refgrow checks these in order: 1. Coupon / promotion code match (most reliable) 2. `session.metadata.referral_code` 3. `client_reference_id` on checkout session 4. Subscription metadata 5. Email fallback via `referral_attributions` table #### Supported Stripe Webhook Events - `checkout.session.completed` -- purchase completed - `invoice.paid` -- subscription invoice paid - `customer.subscription.created` -- new subscription - `customer.subscription.updated` -- plan changes, renewals - `customer.discount.created` -- coupon applied (renewal tracking) - `charge.refunded` -- charge refunded #### Commission Configuration Commission priority: 1. Affiliate-specific override (highest priority) 2. Product-specific commission 3. Project default commission (fallback) Commission types: Percentage or Fixed Amount Commission duration: Lifetime, First Purchase, or Limited Period For subscriptions: - Commission on initial payment - Optional recurring commissions on renewals - Additional commission on upgrades - Automatic reversal on refunds/cancellations --- ### LemonSqueezy Integration Webhook URL: `https://refgrow.com/webhook/lemonsqueezy/YOUR_PROJECT_ID` #### Setup 1. Go to LemonSqueezy Dashboard > Settings > Webhooks 2. Click "Create Webhook" 3. Set URL to `https://refgrow.com/webhook/lemonsqueezy/YOUR_PROJECT_ID` 4. Enable events: `order_created`, `subscription_created`, `subscription_payment_succeeded` 5. Copy webhook secret and save in Refgrow project Integration tab #### Passing Referral Codes **Automatic (recommended):** Add class to checkout links: ```html Buy Now ``` The tracking script will automatically append `checkout[custom][referral_code]=CODE`. **Manual URL parameter:** ```html Buy Now ``` **Programmatic API:** ```javascript const checkoutData = { custom: { referral_code: 'ALEX123' } }; ``` **Via discount codes:** Create discount codes in LemonSqueezy, link them to affiliates in Refgrow's Coupons tab. For dynamically added links, call `Refgrow.processLemonSqueezyLinks()`. #### Supported LemonSqueezy Webhook Events - `order_created` -- one-time purchase completed - `subscription_created` -- new subscription - `subscription_payment_succeeded` -- subscription payment processed --- ### Paddle Integration Webhook URL: `https://refgrow.com/webhook/paddle/{your-project-id}` #### Setup 1. Go to project's "Integration" tab, select "Paddle Webhooks" 2. Copy the webhook URL 3. In Paddle dashboard, create webhook with that URL 4. Enable events: `transaction.completed`, `subscription.created`, `subscription.updated` 5. Copy Paddle webhook signing secret, paste in Refgrow #### Passing Referral Codes **For Paddle Checkout:** ```javascript const refCode = req.cookies.refgrow_ref_code; const checkout = await paddle.checkouts.create({ custom_data: { referral_code: refCode || null } }); ``` **For Paddle Payment Links:** ```html Buy Now ``` ```javascript if (window.Refgrow) { Refgrow.processPaddleLinks(); } ``` #### Supported Paddle Webhook Events - `transaction.completed` -- purchase completed - `subscription.created` -- new subscription - `subscription.updated` -- subscription updated --- ## REST API Reference ### API Authentication Base URL: `https://refgrow.com/api/v1` All requests require a Bearer token. API keys have the prefix `rgk_` and are generated from project settings under "API Keys". Keys are stored hashed (bcrypt). Never expose in client-side code. All requests must use HTTPS. ``` Authorization: Bearer rgk_YOUR_API_KEY ``` Example headers: ```javascript const headers = { 'Authorization': 'Bearer rgk_YOUR_API_KEY', 'Content-Type': 'application/json' }; ``` --- ### Affiliates API #### List Affiliates ``` GET /api/v1/affiliates ``` Query parameters: | Parameter | Type | Required | Description | |-----------|---------|----------|------------------------------------------------| | `limit` | integer | Optional | Number of affiliates to return (default: 20) | | `offset` | integer | Optional | Pagination offset (default: 0) | | `status` | string | Optional | Filter by status ('active', 'inactive') | Example request: ```bash curl -X GET "https://refgrow.com/api/v1/affiliates?limit=10&status=active" \ -H "Authorization: Bearer YOUR_API_KEY" ``` ```javascript const response = await fetch( 'https://refgrow.com/api/v1/affiliates?limit=10&status=active', { headers: { 'Authorization': 'Bearer YOUR_API_KEY' } } ); const data = await response.json(); ``` Example response (200 OK): ```json { "success": true, "data": [ { "id": 123, "user_email": "affiliate1@example.com", "referral_code": "REF123", "created_at": "2024-01-15T10:00:00.000Z", "status": "active", "clicks": 58, "signups": 12, "purchases": 5, "unpaid_earnings": "50.00", "total_earnings": "150.00", "eligible_earnings": "35.00", "held_earnings": "15.00", "next_release_date": "2024-02-15T10:00:00.000Z" } ], "pagination": { "limit": 10, "offset": 0, "total": 55, "has_more": true } } ``` Hold period fields (when project has hold period configured): | Field | Type | Description | |----------------------|-----------------------|------------------------------------------------| | `eligible_earnings` | string | Earnings past hold period, available for payout | | `held_earnings` | string | Earnings still within hold period | | `next_release_date` | string (ISO) or null | When next batch of held earnings becomes eligible | Note: `total_earnings` = `eligible_earnings` + `held_earnings` + `paid_earnings` #### Create Affiliate ``` POST /api/v1/affiliates ``` Request body: | Parameter | Type | Required | Description | |----------------|--------|----------|---------------------------------------------------| | `email` | string | Yes | Email address. Must be unique per project. | | `referral_code`| string | Optional | Custom referral code. Auto-generated if omitted. | Example request: ```bash curl -X POST "https://refgrow.com/api/v1/affiliates" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "email": "new.affiliate@example.com", "referral_code": "NEWCODE" }' ``` Example response (201 Created): ```json { "success": true, "data": { "id": 124, "user_email": "new.affiliate@example.com", "referral_code": "NEWCODE", "unpaid_earnings": null, "total_earnings": null, "created_at": "2024-07-29T12:30:00.000Z", "status": "active" } } ``` Error responses: `400` Invalid email or parameters. `409` Email or referral code already exists. #### Retrieve Affiliate ``` GET /api/v1/affiliates/:email ``` The email must be URL-encoded. ```bash curl -X GET "https://refgrow.com/api/v1/affiliates/affiliate1%40example.com" \ -H "Authorization: Bearer YOUR_API_KEY" ``` Example response (200 OK): ```json { "success": true, "data": { "id": 123, "user_email": "affiliate1@example.com", "referral_code": "REF123", "created_at": "2024-01-15T10:00:00.000Z", "status": "active", "clicks": 58, "signups": 12, "purchases": 5, "unpaid_earnings": "50.00", "total_earnings": "150.00" } } ``` Error responses: `400` Invalid email format. `404` Affiliate not found. #### Update Affiliate ``` PUT /api/v1/affiliates/:email ``` Updatable fields: | Parameter | Type | Description | |----------------|--------|------------------------------------------| | `email` | string | New email address | | `referral_code`| string | New unique referral code | | `status` | string | 'active' or 'inactive' | ```bash curl -X PUT "https://refgrow.com/api/v1/affiliates/affiliate1%40example.com" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"status": "inactive"}' ``` Error responses: `400` Invalid parameters. `404` Not found. `409` Conflict. #### Delete Affiliate ``` DELETE /api/v1/affiliates/:email ``` Permanently deletes an affiliate and all associated data. Irreversible. ```bash curl -X DELETE "https://refgrow.com/api/v1/affiliates/affiliate1%40example.com" \ -H "Authorization: Bearer YOUR_API_KEY" ``` Returns `204 No Content` on success. --- ### Conversions API #### List Conversions ``` GET /api/v1/conversions ``` Query parameters: | Parameter | Type | Required | Description | |-------------------|----------------|----------|------------------------------------------------| | `limit` | integer | Optional | Number to return (default: 50) | | `offset` | integer | Optional | Pagination offset (default: 0) | | `type` | string | Optional | Filter: `signup` or `purchase` | | `affiliate_id` | integer | Optional | Filter by affiliate ID | | `referred_user_id`| integer | Optional | Filter by referred user ID | | `paid` | boolean | Optional | Filter by payout status | | `from` | string (ISO) | Optional | Filter after this date | | `to` | string (ISO) | Optional | Filter before this date | Example request: ```bash curl -X GET "https://refgrow.com/api/v1/conversions?type=purchase&affiliate_id=123&paid=true" \ -H "Authorization: Bearer YOUR_API_KEY" ``` Example response (200 OK): ```json { "success": true, "data": [ { "id": 1001, "type": "purchase", "affiliate_id": 123, "referred_user_id": 501, "value": 12.5, "base_value": 250, "base_value_currency": "USD", "paid": false, "created_at": "2024-07-29T13:00:00.000Z", "reference": "ORDER-123", "coupon_code_used": "SUMMER2024" } ], "pagination": { "limit": 50, "offset": 0, "total": 2, "has_more": false } } ``` #### Create Conversion ``` POST /api/v1/conversions ``` Request body: | Parameter | Type | Required | Description | |----------------------|---------|----------|------------------------------------------------| | `type` | string | Yes | `signup` or `purchase` | | `affiliate_id` | integer | Optional | Affiliate ID (for attributed conversions) | | `referral_code` | string | Optional | Referral code to look up affiliate | | `referred_user_id` | integer | Optional | Referred user ID | | `email` | string | Optional | Customer email (for webhook payloads) | | `value` | number | Optional | Commission value (auto-calculated if omitted) | | `base_value` | number | Optional | Original transaction value | | `base_value_currency`| string | Optional | Currency code (e.g., USD, EUR) | | `paid` | boolean | Optional | Payout status (default: false) | | `reference` | string | Optional | Custom reference (e.g., order ID) | | `coupon_code_used` | string | Optional | Coupon code used | Also triggers `referral_converted` and `referral_updated` webhook events automatically. Example request: ```bash curl -X POST "https://refgrow.com/api/v1/conversions" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "type": "purchase", "affiliate_id": 123, "base_value": 250, "base_value_currency": "USD", "reference": "ORDER-123" }' ``` ```javascript const response = await fetch('https://refgrow.com/api/v1/conversions', { method: 'POST', headers: { 'Authorization': 'Bearer YOUR_API_KEY', 'Content-Type': 'application/json' }, body: JSON.stringify({ type: 'purchase', affiliate_id: 123, base_value: 250, base_value_currency: 'USD', reference: 'ORDER-123' }) }); const result = await response.json(); ``` Example response (201 Created): ```json { "success": true, "data": { "id": 1002, "type": "purchase", "affiliate_id": 123, "referred_user_id": 501, "value": 12.5, "base_value": 250, "base_value_currency": "USD", "paid": false, "created_at": "2024-07-29T13:05:00.000Z", "reference": "ORDER-123", "coupon_code_used": null } } ``` Error responses: `400` Invalid parameters. `404` Affiliate/user not found. `409` Duplicate conversion. #### Retrieve Conversion ``` GET /api/v1/conversions/:id ``` ```bash curl -X GET "https://refgrow.com/api/v1/conversions/1002" \ -H "Authorization: Bearer YOUR_API_KEY" ``` #### Update Conversion ``` PUT /api/v1/conversions/:id ``` Triggers `referral_updated` webhook event. Updatable fields: | Parameter | Type | Description | |----------------------|---------|--------------------------------| | `value` | number | Commission value | | `base_value` | number | Original transaction value | | `type` | string | `signup` or `purchase` | | `paid` | boolean | Payout status | | `reference` | string | Custom reference | | `coupon_code_used` | string | Coupon code used | | `base_value_currency`| string | Currency code | ```bash curl -X PUT "https://refgrow.com/api/v1/conversions/1002" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"paid": true}' ``` #### Delete Conversion ``` DELETE /api/v1/conversions/:id ``` Permanently deletes a conversion. Irreversible. ```bash curl -X DELETE "https://refgrow.com/api/v1/conversions/1002" \ -H "Authorization: Bearer YOUR_API_KEY" ``` Returns `204 No Content` on success. --- ### Referrals API #### List Referrals ``` GET /api/v1/referrals ``` Query parameters: | Parameter | Type | Required | Description | |----------------|---------|----------|-----------------------------------------------------| | `limit` | integer | Optional | Number to return (default: 20) | | `offset` | integer | Optional | Pagination offset (default: 0) | | `affiliate_id` | integer | Optional | Filter by affiliate ID | | `status` | string | Optional | 'pending', 'converted', 'direct', 'direct_signup' | ```bash curl -X GET "https://refgrow.com/api/v1/referrals?affiliate_id=123&status=converted" \ -H "Authorization: Bearer YOUR_API_KEY" ``` Example response (200 OK): ```json { "success": true, "data": [ { "id": 501, "user_email": "customer1@example.com", "conversion_status": "converted", "conversion_date": "2024-02-10T11:05:00.000Z", "created_at": "2024-02-01T09:00:00.000Z", "affiliate_id": 123, "affiliate_code": "REF123" } ], "pagination": { "limit": 20, "offset": 0, "total": 5, "has_more": false } } ``` #### Create Referral ``` POST /api/v1/referrals ``` Request body: | Parameter | Type | Required | Description | |----------------|---------------|----------|-----------------------------------------------------| | `email` | string | Yes | Referred user's email. Unique per project. | | `affiliate_id` | integer | Optional | Referring affiliate ID. Omit for direct signup. | | `status` | string | Optional | 'pending', 'converted', 'direct', 'direct_signup' | ```bash curl -X POST "https://refgrow.com/api/v1/referrals" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "email": "manual.customer@example.com", "affiliate_id": 123, "status": "converted" }' ``` Example response (201 Created): ```json { "success": true, "data": { "id": 502, "user_email": "manual.customer@example.com", "affiliate_id": 123, "conversion_status": "converted", "conversion_date": "2024-07-29T13:00:00.000Z", "created_at": "2024-07-29T13:00:00.000Z" } } ``` Error responses: `400` Invalid email. `404` Specified affiliate_id not found. `409` Email already exists. #### Retrieve Referral ``` GET /api/v1/referrals/:email ``` Email must be URL-encoded. ```bash curl -X GET "https://refgrow.com/api/v1/referrals/customer1%40example.com" \ -H "Authorization: Bearer YOUR_API_KEY" ``` #### Update Referral ``` PUT /api/v1/referrals/:email ``` Updatable fields: | Parameter | Type | Description | |----------------|-----------------|-----------------------------------------------------| | `email` | string | New email address | | `affiliate_id` | integer or null | Change affiliate or set null to disassociate | | `status` | string | Setting to 'converted'/'direct' updates conversion_date | ```bash curl -X PUT "https://refgrow.com/api/v1/referrals/manual.customer%40example.com" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"affiliate_id": null, "status": "direct"}' ``` --- ### Coupons API #### List Coupons ``` GET /api/v1/coupons ``` Returns all coupons associated with affiliates. Supports pagination and filtering by status, affiliate_id, or coupon_code search. #### Create Coupon ``` POST /api/v1/coupons ``` Request body: ```json { "affiliate_id": 42, "coupon_code": "JANE20", "stripe_coupon_id": "promo_xxx", "lemonsqueezy_discount_code": "LS_DISC_123", "status": "active" } ``` | Parameter | Type | Required | Description | |------------------------------|---------|----------|------------------------------------------| | `affiliate_id` | integer | Yes | Affiliate to link coupon to | | `coupon_code` | string | Yes | Coupon code (min 3 chars) | | `stripe_coupon_id` | string | Optional | Stripe coupon ID for auto-attribution | | `lemonsqueezy_discount_code` | string | Optional | LemonSqueezy discount code | | `status` | string | Optional | 'active' or 'inactive' (default: active) | #### Retrieve Coupon ``` GET /api/v1/coupons/:id ``` #### Update Coupon ``` PUT /api/v1/coupons/:id ``` #### Delete Coupon ``` DELETE /api/v1/coupons/:id ``` Permanently deletes a coupon. If linked to Stripe, also deleted from Stripe. --- ### Stripe Customer Referral Info ``` GET /api/v1/projects/:projectId/stripe-customer-referral-info/:stripeCustomerId ``` Get referral information for a Stripe customer within a project. --- ### Error Handling Error response format: ```json { "success": false, "error": "Affiliate not found" } ``` | Status | Meaning | |--------|--------------------------------------| | `200` | Success | | `201` | Created | | `204` | Deleted (no content) | | `400` | Bad request (missing/invalid params) | | `401` | Unauthorized (invalid/missing API key)| | `403` | Forbidden (no permission) | | `404` | Resource not found | | `409` | Conflict (duplicate resource) | | `429` | Rate limited | | `500` | Internal server error | ### Rate Limits - 100 requests per minute per API key Rate limit headers in every response: - `X-RateLimit-Limit` -- requests allowed per window - `X-RateLimit-Remaining` -- requests remaining - `X-RateLimit-Reset` -- Unix timestamp when window resets --- ## Webhook Events Refgrow sends HTTP POST notifications about events in your affiliate program. All webhooks are signed with HMAC-SHA256. ### Setup 1. Go to Project Settings > "Webhooks" tab 2. Click "Add Webhook" 3. Enter endpoint URL (e.g., `https://yourapp.com/webhooks/refgrow`) 4. Select events to receive 5. Optional: Generate a secret key for signature verification 6. Save ### Supported Events | Event | Description | Trigger | |-----------------------|--------------------------------------|--------------------------------------| | `referral_signed_up` | New user signed up via referral | User registers through referral link | | `referral_converted` | Referral converted to paying customer| Referred user makes a purchase | | `referral_canceled` | Conversion canceled or refunded | Payment refunded or canceled | | `referral_updated` | Conversion updated or modified | Conversion created/updated via API | ### Request Headers ``` Content-Type: application/json User-Agent: Refgrow-Webhooks/1.0 X-Refgrow-Event: referral_converted X-Refgrow-Signature: sha256=abc123... ``` ### Payload: referral_signed_up ```json { "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" } } ``` ### Payload: referral_converted ```json { "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" } } ``` ### Payload: referral_canceled ```json { "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" } } ``` ### Payload: referral_updated ```json { "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" } } ``` ### Payout Preferences Webhook payloads automatically include PayPal and Wise payout preferences in `referrer.payout_preferences` when the affiliate has configured them. This eliminates the need for additional API calls to enrich webhook data. ### Signature Verification (Node.js) ```javascript 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'); } const event = JSON.parse(req.body); console.log('Received event:', event.event); res.status(200).send('OK'); }); ``` ### Signature Verification (PHP) ```php function verifySignature($payload, $signature, $secret) { $expectedSignature = 'sha256=' . hash_hmac('sha256', $payload, $secret); return hash_equals($expectedSignature, $signature); } $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'); } ``` ### Express.js Webhook Handler ```javascript 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'); } }); ``` ### Webhook Delivery - Successful delivery: HTTP 200-299, response within 5 seconds - Failed delivery: HTTP 400+ or timeout; automatic retries (3 attempts) - Your endpoint must respond with HTTP 200-299 for successful delivery ### Best Practices - Always verify webhook signatures - Use HTTPS endpoints - Respond quickly (within 10 seconds) - Return HTTP 200 on success - Handle duplicate events (implement idempotency using event IDs) - Use queues for heavy processing operations --- ## Widget Customization ### Appearance Settings (configured in project dashboard) - Primary Color -- buttons and highlights - Secondary Color -- secondary elements and accents - Font Color -- text color - Title -- headline text - Description -- program explanation ### Branding Removal On paid plans (Starter and above), the "Powered by Refgrow" footer can be removed. ### Block Configuration Blocks can be enabled, disabled, and reordered via drag-and-drop in project settings. See the Widget Blocks section above for full list of available blocks and their IDs. ### i18n The widget loads translations from `/locales.json` and supports 20+ languages. Override auto-detection with `data-lang="fr"` on the embed div. ### CSP for Widget ``` script-src 'self' https://scripts.refgrowcdn.com https://refgrow.com; connect-src 'self' https://refgrow.com; ``` --- ## MCP Server The `@refgrow/mcp` package is a Model Context Protocol server that wraps the Refgrow REST API for use with AI assistants like Claude Desktop, Cursor, and Claude Code. ### Installation Runs via `npx` -- no global install needed: ``` npx @refgrow/mcp ``` ### Prerequisites - Node.js 18+ - A Refgrow API key (starts with `rgk_`) ### Getting an API Key 1. Log in to Refgrow dashboard 2. Navigate to project Settings tab 3. Scroll to API Keys section 4. Click "Generate API Key" 5. Copy the key (starts with `rgk_`, shown only once) ### Setup for Claude Desktop Config file: - macOS: `~/Library/Application Support/Claude/claude_desktop_config.json` - Windows: `%APPDATA%\Claude\claude_desktop_config.json` ```json { "mcpServers": { "refgrow": { "command": "npx", "args": ["-y", "@refgrow/mcp"], "env": { "REFGROW_API_KEY": "rgk_your_api_key_here" } } } } ``` ### Setup for Cursor Create or edit `.cursor/mcp.json` in your project root: ```json { "mcpServers": { "refgrow": { "command": "npx", "args": ["-y", "@refgrow/mcp"], "env": { "REFGROW_API_KEY": "rgk_your_api_key_here" } } } } ``` ### Setup for Claude Code Add to `.mcp.json` in your project root: ```json { "mcpServers": { "refgrow": { "command": "npx", "args": ["-y", "@refgrow/mcp"], "env": { "REFGROW_API_KEY": "rgk_your_api_key_here" } } } } ``` ### Environment Variables | Variable | Required | Description | |-------------------|----------|----------------------------------------------------| | `REFGROW_API_KEY` | Yes | Your Refgrow API key (starts with `rgk_`) | | `REFGROW_API_URL` | No | Custom API base URL (default: `https://refgrow.com/api/v1`) | ### Available MCP Tools (18 total) **Affiliates:** - `list_affiliates` -- List all affiliates with stats (clicks, signups, purchases, earnings). Supports filtering by status and pagination. - `get_affiliate_details` -- Get detailed info about a specific affiliate by email. - `create_affiliate` -- Create a new affiliate with optional custom referral code and partner slug. - `update_affiliate` -- Update affiliate email, referral code, status, or partner slug. - `delete_affiliate` -- Remove an affiliate and associated referral data. **Referrals:** - `list_referrals` -- List referred users. Filter by affiliate ID or conversion status (pending, converted, direct, direct_signup). - `get_referral_details` -- Get details for a specific referred user by email. - `create_referral` -- Manually create a referred user record, optionally linked to an affiliate. **Conversions:** - `list_conversions` -- List conversions with filters for type (signup/purchase), affiliate, date range (from/to ISO dates), paid status. Default limit: 50. - `get_conversion` -- Get a specific conversion by ID. - `create_conversion` -- Create a conversion. Commission auto-calculated from project settings if value omitted. Can identify affiliate by ID or referral code. - `update_conversion` -- Update conversion details or mark as paid. - `delete_conversion` -- Delete a conversion record. **Coupons:** - `list_coupons` -- List coupon codes with affiliate info. Filter by status, affiliate_id, or coupon_code search. - `get_coupon` -- Get a specific coupon by ID. - `create_coupon` -- Create a coupon linked to an affiliate, with optional Stripe coupon ID or LemonSqueezy discount code for automatic attribution. - `update_coupon` -- Update coupon code, linked affiliate, payment provider IDs, or status. - `delete_coupon` -- Delete a coupon (also removes from Stripe if linked). --- ## Framework Integration Examples ### React / Next.js -- Tracking Script ```typescript // components/RefgrowTracking.tsx "use client"; import Script from "next/script"; export function RefgrowTracking({ projectId }: { projectId: string }) { return (

My Website

Join Our Affiliate Program

``` ### Server-Side (Node.js + EJS) ```html Affiliate Program - <%= siteName %>

Our Affiliate Program

<% if (user) { %>
<% } else { %>
<% } %>
``` ### Node.js -- Creating a Conversion via API ```javascript const response = await fetch('https://refgrow.com/api/v1/conversions', { method: 'POST', headers: { 'Authorization': 'Bearer rgk_YOUR_API_KEY', 'Content-Type': 'application/json' }, body: JSON.stringify({ customer_email: 'customer@example.com', amount: 49.99, referral_code: 'REF123' }) }); const data = await response.json(); console.log('Conversion created:', data); ``` ### Stripe Checkout Session with Referral Code (Node.js) ```javascript const refCode = req.cookies.refgrow_ref_code; const session = await stripe.checkout.sessions.create({ line_items: [{ price: 'price_xxx', quantity: 1 }], mode: 'subscription', success_url: 'https://yoursite.com/success', cancel_url: 'https://yoursite.com/cancel', metadata: { referral_code: refCode || null } }); ``` --- ## Troubleshooting ### Referrals Not Being Tracked 1. Verify the tracking script is on all pages with the correct project ID 2. Check browser console for error messages 3. Ensure third-party cookies are not blocked 4. Test with a known referral link format (e.g., `?ref=CODE`) 5. Verify the referral parameter name matches project settings ### Conversions Not Attributing to Affiliates **For Stripe/LemonSqueezy/Paddle:** - Ensure webhooks are properly configured - Verify referral code is passed to the payment provider - Check webhook logs in your payment provider dashboard **For Manual Tracking:** - Ensure a valid email is passed to the `Refgrow()` function - Verify the cookie exists when making the call - Check browser console for API errors ### Affiliate Dashboard Issues 1. Verify the page.js script is loading properly 2. Check that the project ID is correct 3. Ensure no JavaScript errors on your page 4. Test on a clean page without other scripts 5. Verify your domain is configured in project settings ### Stripe Webhooks Not Working 1. Verify Stripe API key in project settings 2. Check webhook endpoint URL matches `https://refgrow.com/webhook/stripe/{your-project-id}` 3. Confirm all required events are enabled 4. Check Stripe dashboard for webhook delivery logs ### Webhook Signature Verification Failing - Ensure the webhook secret matches exactly - The raw request body must not be parsed by JSON middleware before signature verification - Use `express.raw({type: 'application/json'})` for the webhook endpoint ### Duplicate Conversions - Refgrow deduplicates by payment provider event ID - Check for multiple webhook endpoints pointing to the same project - Implement idempotency in your webhook handler using event IDs ### CSP Blocking Scripts Add to your Content Security Policy: ``` script-src 'self' https://scripts.refgrowcdn.com https://refgrow.com; connect-src 'self' https://refgrow.com; ``` ### MCP Server Issues - "Server not found": Ensure Node.js 18+ is installed, verify `npx` is available - "Authentication failed" / 401: Verify API key starts with `rgk_`, check it hasn't been revoked - "Tool not available": Restart your AI client, verify JSON config is valid --- ## Support - Email: support@refgrow.com - Docs: https://refgrow.com/docs - API Reference: https://refgrow.com/docs/api-reference