Raff's commission tracking system automatically tracks orders that come through the platform and calculates commissions owed to Raff. The system uses tracking IDs embedded in product URLs to attribute orders back to Raff.
When a user clicks on a product in Raff:
-
Generate Tracking ID: A unique tracking ID is created using the format
raff_{random12chars}- Example:
raff_X4m9K2pL7nQw
- Example:
-
Create Click Record: A
ClickTrackingrecord is stored in the database with:trackingId: The unique IDproductId: The product being clickedmerchantId: The merchant who owns the productplatform: ZID or SALLAcommissionRate: Merchant's commission rate (default 5%)expiresAt: 30 days from clickipAddress,userAgent,referrerUrl: For fraud detection
-
Build Tracking URL: The destination URL is enhanced with tracking parameters:
https://store.zid.sa/products/123?ref=raff_X4m9K2pL7nQw&utm_source=raff&utm_medium=affiliate&utm_campaign=product-slug -
Redirect User: User is redirected to the merchant's store with the tracking URL
When a customer places an order on the merchant's platform (Zid or Salla):
-
Webhook Received: Merchant's platform sends order webhook to
/api/zid/webhookor/api/salla/webhook -
Extract Referrer Code: The webhook payload contains the
refparameter from the URL:{ "order_id": "456", "referrer": "https://store.zid.sa/products/123?ref=raff_X4m9K2pL7nQw", "total": 500.00, "currency": "SAR", "payment_status": "pending" } -
Find Click Tracking: Look up the
ClickTrackingrecord bytrackingId(raff_X4m9K2pL7nQw) -
Calculate Commission:
Commission Amount = (Order Total × Commission Rate) / 100 Example: (500.00 × 5.00) / 100 = 25.00 SAR -
Create Commission Record:
{ clickTrackingId: "click_abc123", merchantId: "merchant_xyz", orderId: "456", orderTotal: 500.00, orderCurrency: "SAR", commissionRate: 5.00, commissionAmount: 25.00, status: "PENDING" // Initially pending }
PENDING → APPROVED → PAID
↓
CANCELLED (if order cancelled/refunded)
- PENDING: Order created but payment not yet confirmed
- APPROVED: Payment confirmed (automatically triggers when
payment_status = "paid") - ON_HOLD: Suspicious activity detected (fraud prevention)
- PAID: Raff has received payment from merchant
- CANCELLED: Order was cancelled or refunded
The system tracks accumulated commissions per merchant:
-- Get merchant's total approved commissions
SELECT
merchantId,
SUM(commissionAmount) as totalOwed
FROM Commission
WHERE status IN ('APPROVED', 'PENDING')
GROUP BY merchantId
HAVING SUM(commissionAmount) >= 1000.00When a merchant reaches 1000 SAR in commissions:
- Admin reviews and marks commissions as
PAID - System records
paidAttimestamp - Invoice/receipt can be generated
model ClickTracking {
id String @id @default(cuid())
trackingId String @unique // "raff_X4m9K2pL7nQw"
productId String
merchantId String
platform Platform // ZID or SALLA
commissionRate Decimal? @db.Decimal(5, 2)
// Conversion tracking
converted Boolean @default(false)
convertedCount Int @default(0)
conversionValue Decimal? @db.Decimal(10, 2)
commissionValue Decimal? @db.Decimal(10, 2)
// Timestamps
clickedAt DateTime @default(now())
convertedAt DateTime?
lastConvertedAt DateTime?
expiresAt DateTime // 30 days from click
// Relations
orders Order[]
commissions Commission[]
}model Commission {
id String @id @default(cuid())
clickTrackingId String
clickTracking ClickTracking @relation(...)
merchantId String
merchant Merchant @relation(...)
orderId String
orderTotal Decimal @db.Decimal(10, 2)
orderCurrency String @default("SAR")
commissionRate Decimal @db.Decimal(5, 2) // 5.00 = 5%
commissionAmount Decimal @db.Decimal(10, 2) // 25.00 SAR
status CommissionStatus @default(PENDING)
paidAt DateTime?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
@@unique([merchantId, orderId]) // One commission per order
}model Order {
id String @id @default(cuid())
merchantId String
platform Platform
// Platform-specific IDs
zidOrderId String? @unique
sallaOrderId String? @unique
totalPrice Decimal @db.Decimal(10, 2)
currency String @default("SAR")
status OrderStatus
// Link to tracking
clickTrackingId String?
clickTracking ClickTracking? @relation(...)
}The system includes fraud prevention:
// If more than 3 orders from same tracking ID within 10 minutes
if (orderCount >= 3 && windowMinutes <= 10) {
// Mark as suspicious
status = CommissionStatus.ON_HOLD
// Create fraud signal
await FraudSignal.create({
signalType: "HIGH_FREQUENCY_ORDERS",
severity: "HIGH",
score: 70,
reason: "High frequency orders detected"
})
}RATE_LIMIT: Too many clicks from same IPBOT_UA: Bot or crawler user agent detectedINVALID_REFERRER: Click didn't come from Raff product pageSEC_FETCH_SITE: Security headers indicate suspicious originDUPLICATE_RECENT: Same user clicked same product within 15 secondsPRODUCT_INACTIVE: Product is no longer activeINVALID_DESTINATION: Destination URL doesn't match merchant's store
POST /api/track/click
Content-Type: application/json
{
"productId": "prod_123"
}
Response:
{
"success": true,
"qualified": true,
"trackingId": "raff_X4m9K2pL7nQw",
"redirectUrl": "https://store.zid.sa/products/123?ref=raff_X4m9K2pL7nQw&utm_source=raff&utm_medium=affiliate&utm_campaign=product-slug",
"expiresAt": "2026-02-07T12:00:00.000Z"
}POST /api/zid/webhook
X-Zid-Webhook-Secret: {secret}
Content-Type: application/json
{
"event": "order.create",
"order_id": "456",
"store_id": "789",
"total": 500.00,
"currency": "SAR",
"payment_status": "pending",
"referrer": "https://store.zid.sa/products/123?ref=raff_X4m9K2pL7nQw"
}
Response:
{
"success": true,
"message": "Commission pending",
"commission": 25.00
}const merchantCommissions = await prisma.commission.aggregate({
where: {
merchantId: "merchant_xyz",
status: {
in: ["PENDING", "APPROVED"]
}
},
_sum: {
commissionAmount: true
}
});
const totalOwed = merchantCommissions._sum.commissionAmount || 0;const merchantsAboveThreshold = await prisma.commission.groupBy({
by: ["merchantId"],
where: {
status: {
in: ["PENDING", "APPROVED"]
}
},
_sum: {
commissionAmount: true
},
having: {
commissionAmount: {
_sum: {
gte: 1000.00
}
}
}
});const commissions = await prisma.commission.findMany({
where: {
merchantId: "merchant_xyz",
status: "APPROVED"
},
include: {
clickTracking: {
select: {
trackingId: true,
product: {
select: {
name: true,
slug: true
}
}
}
}
},
orderBy: {
createdAt: "desc"
}
});# Commission Settings (in Merchant model, default 5%)
# No global env var needed
# Risk/Fraud Settings
ENABLE_RISK_SCORING=true
RISK_SCORE_THRESHOLD=70
RISK_TRACKING_WINDOW_MINUTES=10
RISK_TRACKING_ORDER_THRESHOLD=3
# Webhook Configuration
ZID_WEBHOOK_SECRET=your_secret
ZID_WEBHOOK_HEADER=X-Zid-Webhook-Secret
ZID_WEBHOOK_SIGNATURE_MODE=plain
SALLA_WEBHOOK_SECRET=your_secret
SALLA_WEBHOOK_HEADER=x-salla-signature
SALLA_WEBHOOK_SIGNATURE_MODE=hmac-sha256- Click a product in Raff → Get tracking URL
- Complete purchase on merchant's store using tracking URL
- Check database for
Commissionrecord withstatus: PENDING - Simulate payment webhook → Status should change to
APPROVED - Mark as
PAIDafter merchant reaches threshold
# Run webhook test suite
npm run test:webhooks
# Or use the test scripts
./scripts/test-webhooks.shSELECT
m.id,
m.name,
SUM(c.commissionAmount) as totalOwed,
COUNT(c.id) as orderCount
FROM Merchant m
JOIN Commission c ON c.merchantId = m.id
WHERE c.status IN ('PENDING', 'APPROVED')
GROUP BY m.id, m.name
HAVING SUM(c.commissionAmount) >= 800.00
ORDER BY totalOwed DESC;SELECT
c.id,
c.orderId,
c.commissionAmount,
c.status,
m.name as merchantName,
p.name as productName,
c.createdAt
FROM Commission c
JOIN Merchant m ON m.id = c.merchantId
JOIN ClickTracking ct ON ct.id = c.clickTrackingId
JOIN Product p ON p.id = ct.productId
WHERE c.commissionAmount >= 50.00
ORDER BY c.createdAt DESC
LIMIT 20;✅ Automatic Tracking: No manual intervention needed ✅ Idempotent: Duplicate webhooks don't create duplicate commissions ✅ Status Transitions: PENDING → APPROVED on payment confirmation ✅ Fraud Detection: High-frequency order detection ✅ Multi-Platform: Works with both Zid and Salla ✅ Commission Attribution: 30-day cookie window ✅ Revenue Threshold: Track when merchants owe 1000+ SAR
- Admin Dashboard: Build UI to view merchants above threshold
- Payment Processing: Integrate payment gateway for merchant payouts
- Invoicing: Generate invoices when marking commissions as PAID
- Notifications: Alert admin when merchant reaches threshold
- Reporting: Monthly commission reports per merchant