Payment Tracking (Stripe)
Payment tracking captures completed purchases and triggers commission calculation. This is where partners actually earn money.
Integration Methods
Section titled “Integration Methods”Choose based on your setup:
| Method | How it works | Best for |
|---|---|---|
| Affitor Pay | Redirect to Affitor checkout | Fastest setup, no Stripe changes |
| Bill Flow | Add metadata to your Stripe checkout | Existing Stripe integration |
Coming Soon: Split Pay – Automatic fund splitting via Stripe Connect
Affitor Pay
Section titled “Affitor Pay”Redirect affiliate-referred customers to Affitor’s hosted checkout. Affitor handles payment collection and tracking automatically.
Implementation
Section titled “Implementation”npm SDK (Recommended):
import { loadAffitor } from '@affitor/tracker';
// When customer clicks "Buy" or "Subscribe"const affitor = await loadAffitor('YOUR_PROGRAM_ID');affitor?.redirectToCheckout({ price: 99.99, currency: 'USD', product_name: 'Pro Plan'});Script tag:
// When customer clicks "Buy" or "Subscribe"var checkoutData = { price: 99.99, currency: 'USD', product_name: 'Pro Plan' };
if (window.affitor) { window.affitor.redirectToCheckout(checkoutData);} else { window.affitorQueue = window.affitorQueue || []; window.affitorQueue.push(['redirectToCheckout', checkoutData]);}Parameters
Section titled “Parameters”| Parameter | Type | Required | Description |
|---|---|---|---|
price | number | Yes | Product price |
currency | string | No | Currency code (default: USD) |
product_name | string | No | Product name for checkout |
How It Works
Section titled “How It Works”- Customer clicks buy →
redirectToCheckout()called - Affitor creates Stripe Checkout session with tracking metadata
- Customer completes payment on Affitor-hosted page
- Webhook fires → conversion tracked → commission calculated
- You receive payment minus commission and platform fee
Pros: Zero Stripe configuration needed
Cons: Customers see Affitor checkout, not your branded checkout
Bill Flow
Section titled “Bill Flow”Add Affitor metadata to your existing Stripe Checkout sessions. You collect payment normally; Affitor tracks via webhooks and invoices you weekly.
Implementation
Section titled “Implementation”Include these metadata fields when creating Stripe Checkout:
One-Time Payment:
Section titled “One-Time Payment:”// Helper to read Affitor cookiesfunction getCookie(name) { const value = `; ${document.cookie}`; const parts = value.split(`; ${name}=`); if (parts.length === 2) return parts.pop().split(';').shift(); return null;}
const customerCode = getCookie('customer_code');
const session = await stripe.checkout.sessions.create({ line_items: [{ price: 'price_xxx', quantity: 1, }], mode: 'payment', success_url: 'https://yoursite.com/success', cancel_url: 'https://yoursite.com/cancel',
// ✅ REQUIRED: All three tracking fields metadata: { customer_code: customerCode, user_id: currentUser.id, program_id: 'YOUR_PROGRAM_ID' }});Subscription:
Section titled “Subscription:”// Helper to read Affitor cookiesfunction getCookie(name) { const value = `; ${document.cookie}`; const parts = value.split(`; ${name}=`); if (parts.length === 2) return parts.pop().split(';').shift(); return null;}
const customerCode = getCookie('customer_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',
// ✅ REQUIRED: Session metadata (first payment) metadata: { customer_code: customerCode, user_id: currentUser.id, program_id: 'YOUR_PROGRAM_ID' },
// ✅ REQUIRED: Subscription metadata (recurring payments) subscription_data: { metadata: { customer_code: customerCode, user_id: currentUser.id, program_id: 'YOUR_PROGRAM_ID' } }});Server-Side Example (Node.js)
Section titled “Server-Side Example (Node.js)”// In your checkout endpointapp.post('/api/create-checkout', async (req, res) => { // Extract customer_code from cookies (sent in request headers) const cookies = req.headers.cookie || ''; const customerCode = cookies.split('; ') .find(row => row.startsWith('customer_code=')) ?.split('=')[1];
// Get user from your authentication system const userId = req.user.id;
const session = await stripe.checkout.sessions.create({ line_items: [{ price: 'price_xxx', quantity: 1 }], mode: 'payment', success_url: 'https://yoursite.com/success', cancel_url: 'https://yoursite.com/cancel',
// ✅ REQUIRED: All three tracking fields metadata: { customer_code: customerCode, user_id: userId, program_id: process.env.AFFITOR_PROGRAM_ID } });
res.json({ url: session.url });});How It Works
Section titled “How It Works”- Customer clicks affiliate link → tracked with internal cookies
- Customer signs up → calls
trackLead({ user_id })with your internal user ID - Customer clicks buy → your checkout with
user_idin metadata - Customer completes payment via your Stripe
- Stripe webhook fires → Affitor receives event
- Affitor looks up customer-partner using
user_id→ attributes to partner - Commission calculated → Affitor invoices you weekly
Pros: Simple integration, use your existing checkout, no cookie reading required
Cons: Requires metadata setup, weekly invoice payment
Attribution Lookup Strategy
Section titled “Attribution Lookup Strategy”When Affitor receives a payment webhook from Stripe, it uses a 4-step fallback mechanism to find the customer-partner relationship and attribute the sale correctly.
The Lookup Flow
Section titled “The Lookup Flow”Payment Event Received (Stripe webhook) ↓Step 1: Lookup by customer_code (from cookie) ↓ Found? ──Yes──→ ✅ Link to attribution ↓ No (cookies deleted) ↓Step 2: Lookup by email ↓ Found? ──Yes──→ ✅ Link + Update stripe_customer_id │ 📍 Last-click attribution calculated from here │ (CPL/CPS tracking from lead/signup event) ↓ No ↓Step 3: Lookup by stripe_customer_id (returning customer) OR email_hash (from Stripe email) ↓ Found? ──Yes──→ ✅ Link to attribution ↓ No ↓Step 4: Lookup by advertiser_user_id (if provided) ↓ Found? ──Yes──→ ✅ Link to attribution ↓ No ↓❌ No attribution found (organic sale) → Payment NOT tracked (discarded)Why Multiple Lookup Steps?
Section titled “Why Multiple Lookup Steps?”| Scenario | Lookup Method | Example |
|---|---|---|
| Normal flow | customer_code (Step 1) | Customer has cookies intact |
| Cookies cleared | email (Step 2) | Customer cleared browser data |
| Returning customer | stripe_customer_id (Step 3) | Customer made previous purchase |
| Cross-device | email_hash (Step 3) | Customer clicked on mobile, bought on desktop |
| Custom tracking | advertiser_user_id (Step 4) | You provided custom user ID |
What Affitor Receives from Stripe
Section titled “What Affitor Receives from Stripe”When the webhook fires, Affitor extracts:
- Payment confirmation
program_idfrom metadatacustomer_codefrom metadata (if available)user_idfrom metadata (if available)- Customer email from Stripe
stripe_customer_idfrom Stripe
After Successful Lookup
Section titled “After Successful Lookup”Once a customer-partner relationship is found:
- Verifies attribution is within 60-day window
- Creates commission record
- Updates
stripe_customer_idif not already set (Step 2)
Organic Sales
Section titled “Organic Sales”If no attribution is found after all 4 steps, the payment is considered an organic sale and is NOT tracked (discarded). This ensures only affiliate-referred sales generate commissions.
Metadata Reference
Section titled “Metadata Reference”| Field | Type | Required | Description |
|---|---|---|---|
customer_code | string | Yes | Customer identifier from Affitor cookie (set automatically when user clicks affiliate link) |
user_id | string | Yes | Your internal user ID (must match the value from trackLead()) |
program_id | string | Yes | Your Affitor program ID |
All three fields are required for reliable payment attribution.
Important Notes
Section titled “Important Notes”- Customer Code: Set automatically by Affitor tracker when user clicks affiliate link. Read from cookie using the helper function.
- User ID Must Match: The
user_idmust exactly match the value you passed duringtrackLead(). - Program ID: Find your program ID in the Affitor dashboard under Settings.
- Hybrid Attribution: Backend tries
customer_codefirst (primary), falls back touser_idif cookies are blocked.
Verifying Payment Tracking
Section titled “Verifying Payment Tracking”Dashboard Verification
Section titled “Dashboard Verification”- Go to Affitor dashboard → Settings → Payments Tracker
- Stripe Connect Integration should show “Connected” after you’ve completed a connect
- Payments Tracker should show a blue checkmark
Troubleshooting
Section titled “Troubleshooting”Conversion Not Tracked
Section titled “Conversion Not Tracked”Check:
- All three required fields included in Stripe metadata:
customer_code(from Affitor cookie)user_id(your internal user ID)program_id(your Affitor program ID)
- Cookie reading function working correctly
- Cookies not blocked by browser (check browser console)
user_idmatches the value used intrackLead()during signup- Webhook endpoint configured correctly
- Webhook events selected (
checkout.session.completed) - User signed up via affiliate link (customer-partner record exists)
Wrong Partner Attributed
Section titled “Wrong Partner Attributed”Check:
- Customer clicked partner’s link before signing up
trackLead()was called during signup with correctuser_id- Customer-partner relationship exists in database
customer_codein metadata matches the cookie valueuser_idin Stripe metadata exactly matches signupuser_id
Subscription Renewals Not Tracked
Section titled “Subscription Renewals Not Tracked”Check:
subscription_data.metadataincludes all three fields:customer_codeuser_idprogram_id
invoice.payment_succeededwebhook event selected- Partner within commission duration window
- Original checkout has customer-partner relationship
Next Steps
Section titled “Next Steps”Payment tracking is set up. See the complete flow: