FarFISH Logo
FarFISHDocs

Referral API

The FarFISH referral system rewards both referrer and referee with 20 FRH each (40 FRH total per successful referral). Referral relationships are immutable once recorded.

Your referral code works across all FarFISH apps because it's derived from your wallet address.

Base URL

text
https://app.farfish.xyz/api/referral

All referral endpoints work identically across all FarFISH apps. Your referral code is universal - share once, works everywhere.


POST /api/referral/record

Record a new referral relationship and distribute rewards to both parties.

Request

Endpoint: POST /api/referral/record

Headers:

text
Content-Type: application/json

Body Schema:

typescript
{
  wallet: string;   // Referee wallet address (42 chars, 0x-prefixed)
  refCode: string;  // Referrer's 8-character code (lowercase)
}

Example Request:

json
{
  "wallet": "0x742d35cc6634c0532925a3b844bc9e7595f0beb9",
  "refCode": "95f0beb9"
}

Response

Success (200):

json
{
  "success": true,
  "referrer": "0x1234567890abcdef1234567890abcdef12345678"
}

Already Recorded (200):

json
{
  "success": true,
  "referrer": "0x1234567890abcdef1234567890abcdef12345678",
  "alreadyRecorded": true
}

Error (400/404):

json
{
  "error": "Cannot refer yourself"
}
json
{
  "error": "RefCode not found"
}

Validation Rules

RuleDescription
Wallet formatMust match /^0x[a-fA-F0-9]{40}$/
RefCode lengthExactly 8 characters
Self-referralRejected if wallet.slice(-8) === refCode
DuplicateIdempotent - returns success if already recorded
RefCode existenceMust resolve to valid wallet address

Reward Distribution

When a referral is successfully recorded:

  1. Referrer receives: +20 FRH (leaderboard score +1, ×20 = 20 FRH)
  2. Referee receives: +20 FRH (leaderboard score +1, ×20 = 20 FRH)
  3. Total distributed: 40 FRH per referral

Backend Operations:

text
1. Store referral relationship (wallet → referrer, createdAt)
2. Increment referrer's referral count
3. Update leaderboard score for referrer (+20 FRH)
4. Update leaderboard score for wallet (+20 FRH)
5. Track active referrers

Cache Rebuild Mechanism

If referral code cache entry is missing, the API automatically rebuilds it by scanning stored referral data.

This ensures referral links continue working even after cache eviction.

cURL Example

bash
curl -X POST https://app.farfish.xyz/api/referral/record \
  -H "Content-Type: application/json" \
  -d '{
    "wallet": "0x742d35cc6634c0532925a3b844bc9e7595f0beb9",
    "refCode": "95f0beb9"
  }'

JavaScript Example

typescript
async function recordReferral(wallet: string, refCode: string) {
  const response = await fetch('https://app.farfish.xyz/api/referral/record', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ wallet, refCode })
  });

  const data = await response.json();
  
  if (data.success) {
    console.log('Referral recorded! Referrer:', data.referrer);
    if (data.alreadyRecorded) {
      console.log('(Already had a referrer)');
    }
  } else {
    console.error('Error:', data.error);
  }
}

GET /api/referral/check

Check if a wallet already has a referrer assigned.

Request

Endpoint: GET /api/referral/check?wallet={address}

Query Parameters:

  • wallet (required) - Ethereum wallet address

Example:

text
GET /api/referral/check?wallet=0x742d35cc6634c0532925a3b844bc9e7595f0beb9

Response

Success (200):

json
{
  "hasReferrer": true,
  "wallet": "0x742d35cc6634c0532925a3b844bc9e7595f0beb9"
}
json
{
  "hasReferrer": false,
  "wallet": "0x742d35cc6634c0532925a3b844bc9e7595f0beb9"
}

cURL Example

bash
curl "https://app.farfish.xyz/api/referral/check?wallet=0x742d35cc6634c0532925a3b844bc9e7595f0beb9"

JavaScript Example

typescript
async function hasReferrer(wallet: string): Promise<boolean> {
  const response = await fetch(
    `https://app.farfish.xyz/api/referral/check?wallet=${wallet}`
  );
  const data = await response.json();
  return data.hasReferrer;
}

Get user's referral link and referral statistics.

Request

Endpoint: GET /api/referral/link?user={address}

Query Parameters:

  • user (required) - Ethereum wallet address

Alternative: Header x-user-wallet can provide wallet address

Example:

text
GET /api/referral/link?user=0x1234567890abcdef1234567890abcdef12345678

Response

Success (200):

json
{
  "bound": false,
  "referrer": "",
  "link": "https://app.farfish.xyz?ref=12345678",
  "referralsCount": 5
}

Fields:

  • bound - Does this user have a referrer?
  • referrer - Referrer's wallet address (empty if not bound)
  • link - This user's shareable referral link
  • referralsCount - Number of users this wallet has referred

RefCode Generation

RefCode is deterministic - always the last 8 characters of wallet address in lowercase:

text
Wallet:  0x1234567890abcdef1234567890abcdef12345678
RefCode: 12345678
Link:    https://app.farfish.xyz?ref=12345678

cURL Example

bash
curl "https://app.farfish.xyz/api/referral/link?user=0x1234567890abcdef1234567890abcdef12345678"

JavaScript Example

typescript
async function getReferralLink(wallet: string) {
  const response = await fetch(
    `https://app.farfish.xyz/api/referral/link?user=${wallet}`
  );
  const data = await response.json();
  
  console.log('Your referral link:', data.link);
  console.log('Total referrals:', data.referralsCount);
  
  return data.link;
}

GET /api/referral/wallet-by-code

Reverse lookup: find wallet address from refCode.

Request

Endpoint: GET /api/referral/wallet-by-code?code={refCode}

Query Parameters:

  • code (required) - 8-character refCode

Example:

text
GET /api/referral/wallet-by-code?code=12345678

Response

Success (200):

json
{
  "wallet": "0x1234567890abcdef1234567890abcdef12345678",
  "refCode": "12345678"
}

Not Found (404):

json
{
  "error": "RefCode not found"
}

Use Cases

  • Validate refCode before displaying referral attribution
  • Pre-fetch referrer profile information
  • Display "You were referred by " message

cURL Example

bash
curl "https://app.farfish.xyz/api/referral/wallet-by-code?code=12345678"

JavaScript Example

typescript
async function getWalletFromCode(refCode: string): Promise<string | null> {
  const response = await fetch(
    `https://app.farfish.xyz/api/referral/wallet-by-code?code=${refCode}`
  );
  
  if (response.status === 404) {
    return null; // Invalid refCode
  }
  
  const data = await response.json();
  return data.wallet;
}

Referral Flow Example

Complete user referral journey:

typescript
// User connects wallet
const wallet = '0x1234567890abcdef1234567890abcdef12345678';

// Get referral link
const response = await fetch(`/api/referral/link?user=${wallet}`);
const { link } = await response.json();
// link = "https://app.farfish.xyz?ref=12345678"

// User shares link on social media
typescript
// URL: https://app.farfish.xyz?ref=12345678
// Frontend automatically caches refCode in localStorage

useEffect(() => {
  const urlParams = new URLSearchParams(window.location.search);
  const refCode = urlParams.get('ref');
  
  if (refCode && refCode.length === 8) {
    localStorage.setItem('ff_pending_referral', refCode);
  }
}, []);

3. Referee Connects Wallet

typescript
// Referee connects wallet
const refereeWallet = '0x742d35cc6634c0532925a3b844bc9e7595f0beb9';

// Retrieve cached refCode
const refCode = localStorage.getItem('ff_pending_referral');

// Initialize user
await fetch('/api/user/init', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({ wallet: refereeWallet })
});

// Record referral (if refCode present)
if (refCode) {
  const result = await fetch('/api/referral/record', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ wallet: refereeWallet, refCode })
  });
  
  const data = await result.json();
  if (data.success) {
    // Both parties receive +20 FRH!
    console.log('Referral successful!');
    localStorage.removeItem('ff_pending_referral');
  }
}

Error Handling

ErrorHTTP StatusMeaningAction
Invalid wallet address400Wallet format invalidValidate format client-side
RefCode not found404RefCode doesn't existCheck for typos, verify referrer initialized
Cannot refer yourself400Self-referral detectedClear cached refCode
Already has referrer200Duplicate referral (idempotent)No action needed

Cross-App Behavior

Referral limitation: Users can only be referred within the same app domain they first connect from. A user who clicks a Web App referral link (app.farfish.xyz?ref=...) and connects wallet there cannot be referred via Base App (baseapp.farfish.xyz) link later.

Why? localStorage is domain-isolated. RefCode cached on app.farfish.xyz is not accessible from baseapp.farfish.xyz.

Best Practice: Use the same app variant for referral campaigns (e.g., all Base App users share Base App links).


Last updated: October 12, 2026