{{ t('title_dashboard') }}
{{ s.label }}
{{ s.value }}
Clicks (MTD)
{{ dashExtra.clicks_mtd || 0 }}
FTDs (MTD)
{{ dashExtra.ftds_mtd || 0 }} {{ dashExtra.ftds_pct >= 0 ? '+' : '' }}{{ dashExtra.ftds_pct }}%
{{ t('lbl_kpi_regs_mtd') }}
{{ dashExtra.registrations_mtd || 0 }} {{ dashExtra.registrations_pct >= 0 ? '+' : '' }}{{ dashExtra.registrations_pct }}%
{{ t('lbl_kpi_conv_rate') }}
{{ dashExtra.conversion_rate || '0.00' }}%
{{ t('lbl_kpi_comm_mtd') }}
${{ (dashExtra.commission_mtd||0).toFixed(2) }}
{{ t('lbl_kpi_dep_ytd') }}
${{ (dashExtra.deposits_ytd||0).toFixed(2) }}
{{ t('lbl_ftds_by_day') }}
{{ t('lbl_clicks_by_country') }}
{{ i+1 }} {{ c.country || 'Unknown' }}
{{ c.clicks }}
{{ t('no_data') }}
{{ t('welcome') }}, {{ userName }}

{{ t('welcome_sub') }}

{{ t('title_users') }}
{{ t('col_name') }}{{ t('col_email') }}{{ t('col_role') }}{{ t('col_status') }}{{ t('col_payments') }}{{ t('col_joined') }}{{ t('col_action') }}
{{ u.name }} {{ u.email }} {{ u.role }} {{ u.status }} {{ t('lbl_pay_frozen') }} {{ t('lbl_pay_active') }} {{ u.created_at?.slice(0,10) }}
{{ t('title_products') }}
{{ t('col_name') }}{{ t('col_vertical') }}{{ t('col_owner') }}{{ t('col_status') }}{{ t('col_action') }}
{{ p.name }} {{ p.vertical }} {{ p.owner_name }} {{ p.status }}
{{ t('title_conversions') }}
{{ t('col_affiliate') }}{{ t('col_product') }}{{ t('col_player_id') }}{{ t('col_event') }}{{ t('col_amount') }}{{ t('col_commission') }}{{ t('col_status') }}{{ t('col_date') }}
{{ c.affiliate_name }} {{ c.product_name }} {{ c.external_id || '—' }} {{ c.event_type }} ${{ c.amount }} ${{ c.commission }} {{ c.status }} {{ c.created_at?.slice(0,10) }}
{{ t('title_payouts') }}
{{ t('col_affiliate') }}{{ t('col_amount') }}{{ t('col_method') }}{{ t('col_status') }}{{ t('col_date') }}{{ t('col_action') }}
{{ p.affiliate_name }} ${{ p.amount }} {{ p.method }} {{ p.status }} {{ p.created_at?.slice(0,10) }}
{{ t('title_my_products') }}
{{ t('col_name') }}{{ t('col_vertical') }}{{ t('th_url') }}{{ t('col_status') }}{{ t('col_action') }}
{{ p.name }} {{ p.vertical }} {{ p.url.slice(0,30) }}… {{ t('status_'+p.status) || p.status }}
{{ t('title_my_affiliates') }}
{{ t('th_name') }}{{ t('th_email') }}{{ t('th_product') }}{{ t('th_tracking_code') }}{{ t('th_status') }}{{ t('th_joined') }}
{{ a.name }}{{ a.email }}{{ a.product_name }} {{ a.tracking_code }} {{ t('status_'+a.status) || a.status }} {{ a.created_at?.slice(0,10) }}
{{ t('title_my_conversions') }}
{{ t('th_affiliate') }}{{ t('th_event') }}{{ t('th_amount') }}{{ t('th_commission') }}{{ t('th_status') }}{{ t('th_date') }}
{{ c.affiliate_name }} {{ c.event_type }} ${{ c.amount }} ${{ c.commission }} {{ t('status_'+c.status) || c.status }} {{ c.created_at?.slice(0,10) }}
{{ t('title_campaigns') }}
{{ t('col_name') }}{{ t('col_product') }}{{ t('col_status') }}{{ t('th_start') }}{{ t('th_end') }}
{{ c.name }}{{ c.product_name }} {{ t('status_'+c.status) || c.status }} {{ c.start_date || '—' }}{{ c.end_date || '—' }}
{{ t('title_browse') }}
{{ p.name }}
{{ p.vertical }}
{{ p.description }}
{{ p.model?.toUpperCase() }} ${{ p.cpa_amount }} CPA {{ p.rev_pct }}% RevShare
⏳ Pending Approval ✓ Approved ✗ Rejected
{{ t('title_my_links') }}
{{ l.product_name }} {{ t('status_'+l.status) || l.status }}
{{ l.vertical }} {{ l.campaign_name ? '· '+l.campaign_name : '' }}
{{ t('lbl_tracking_link') }}
{{ t('lbl_sub_ids') }}
{{ t('no_links') }}
{{ t('title_my_conv') }}
{{ t('th_product') }}{{ t('th_event') }}{{ t('th_amount') }}{{ t('th_commission') }}{{ t('th_status') }}{{ t('th_date') }}
{{ c.product_name }} {{ c.event_type }} ${{ c.amount }} ${{ c.commission }} {{ t('status_'+c.status) || c.status }} {{ c.created_at?.slice(0,10) }}
{{ t('title_earnings') }}
{{ t('th_type') }}{{ t('th_amount') }}{{ lang==='es'?'Saldo Después':'Balance After' }}{{ t('th_note') }}{{ t('th_date') }}
{{ e.type }} ${{ Math.abs(e.amount).toFixed(2) }} ${{ e.balance_after?.toFixed(2) }} {{ e.note || '—' }} {{ e.created_at?.slice(0,10) }}
{{ t('title_my_payouts') }}
{{ t('lbl_available_balance') }}
${{ stats.find(s=>s.label==='Balance')?.raw?.toFixed(2) || '0.00' }}
{{ t('lbl_request_payout') }}

{{ payoutSuccess }}

{{ payoutError }}

{{ t('lbl_payout_history') }}
{{ t('th_amount') }}{{ t('th_method') }}{{ t('th_status') }}{{ t('th_date') }}
${{ p.amount }}{{ p.method }} {{ p.status }} {{ p.created_at?.slice(0,10) }}
{{ t('lbl_from') }} {{ t('lbl_to') }}
{{ t('lbl_player_report') }}
{{ t('th_player_id') }}{{ t('th_affiliate') }}{{ t('th_product') }}{{ t('th_events') }}{{ t('th_total_deposit') }}{{ t('th_commission') }}{{ t('th_first_seen') }}
{{ p.player_id }} {{ p.affiliate_name }} {{ p.product_name }} {{ p.event_types }} ${{ (p.total_deposit||0).toFixed(2) }} ${{ (p.commission||0).toFixed(2) }} {{ p.first_seen?.slice(0,10) }}
{{ t('no_player_data') }}
{{ t('lbl_by_traffic_source') }}
{{ t('th_source') }}{{ t('th_clicks') }}{{ t('th_unique') }}{{ t('th_affiliate') }}
{{ s.source }} {{ s.clicks }} {{ s.unique_clicks }} {{ s.affiliates }}
No data
{{ t('lbl_by_country') }}
{{ t('th_country') }}{{ t('th_clicks') }}{{ t('th_unique') }}
{{ c.country }}{{ c.clicks }}{{ c.unique_clicks||c.clicks }}
{{ t('no_data') }}
{{ t('lbl_affiliate_activity') }}
{{ t('th_name') }}{{ t('th_email') }}{{ t('th_clicks') }}{{ t('th_conversions') }}{{ t('th_commission') }}{{ t('lbl_last_click') }}
{{ a.name }} {{ a.email }} {{ a.clicks||0 }} {{ a.conversions||0 }} ${{ (a.commission||0).toFixed(2) }} {{ a.last_click?.slice(0,16) || '—' }}
{{ t('lbl_no_activity') }}
Monthly Clicks (last 12 months)
Monthly Conversions & Commission
{{ t('lbl_monthly_trend') }}
{{ t('th_month') }}{{ t('th_clicks') }}{{ t('th_conversions') }}{{ t('th_commission') }}
{{ m.month }} {{ m.clicks || 0 }} {{ m.conversions || 0 }} ${{ (m.commission||0).toFixed(2) }}
{{ t('no_monthly_data') }}
{{ t('lbl_ftds_by_day') }}
{{ t('th_day') }}{{ t('th_ftds') }}{{ t('th_share') }}
{{ d.day }} {{ d.ftds }}
{{ ftdDayTotal>0 ? Math.round((d.ftds/ftdDayTotal)*100) : 0 }}%
{{ t('no_ftd_data') }}
{{ t('lbl_media_by_type') }}
{{ t('th_type') }}{{ t('th_items') }}{{ t('th_downloads') }}
{{ m.type }} {{ m.count }} {{ m.downloads || 0 }}
{{ t('no_media_data') }}
{{ t('lbl_media_by_cat') }}
{{ t('th_category') }}{{ t('th_items') }}
{{ m.category || (lang==='es'?'Sin categoría':'Uncategorized') }} {{ m.count }}
{{ t('no_data') }}
{{ t('lbl_recent_uploads') }}
{{ lang==='es'?'Título':'Title' }}{{ t('th_type') }}{{ lang==='es'?'Dimensiones':'Dimensions' }}{{ lang==='es'?'Idioma':'Language' }}{{ lang==='es'?'Subido':'Uploaded' }}
{{ m.title }} {{ m.type }} {{ m.width && m.height ? m.width+'×'+m.height : '—' }} {{ m.language }} {{ m.created_at?.slice(0,10) }}
{{ t('no_recent_uploads') }}
{{ t('th_clicks') }}
{{ reportData.clicks || 0 }}
{{ t('th_conversions') }}
{{ reportData.conversions || 0 }}
{{ t('th_commission') }}
${{ (reportData.commission||0).toFixed(2) }}
{{ lang==='es'?'Afiliados Activos':'Active Affiliates' }}
{{ reportData.active_affiliates || 0 }}
Volume
${{ (reportData.volume||0).toFixed(2) }}
Clicks Over Time
Conversions by Vertical
Performance by Product
ProductClicksConv.Commission
{{ p.name }}{{ p.clicks }}{{ p.conversions }} ${{ p.commission?.toFixed(2) }}
{{ t('lbl_top_affiliates') }}
#{{ t('th_name') }}{{ t('th_email') }}{{ t('th_clicks') }}{{ t('th_conversions') }}{{ t('th_conv_rate') }}{{ t('th_commission') }}
{{ i+1 }} {{ a.name }} {{ a.email }} {{ a.clicks||0 }} {{ a.conversions||0 }} {{ a.conv_rate||0 }}% ${{ (a.commission||0).toFixed(2) }}
{{ t('lbl_clicks_by_country') }}
{{ t('th_country') }}{{ t('th_clicks') }}
{{ c.country || 'Unknown' }}{{ c.clicks }}
{{ t('lbl_product_perf') }}
{{ t('th_product') }}{{ t('col_vertical') }}{{ t('th_clicks') }}{{ t('th_conversions') }}{{ t('th_conv_rate') }}{{ t('th_commission') }}
{{ p.name }}{{ p.vertical }}{{ p.clicks||0 }} {{ p.conversions||0 }}{{ p.conv_rate||0 }}% ${{ (p.commission||0).toFixed(2) }}
{{ t('title_applications') }}
{{ t('no_applications') }}
{{ t('th_affiliate') }}{{ t('th_email') }}{{ t('th_product') }}{{ t('th_applied') }}{{ t('th_actions') }}
{{ a.affiliate_name }} {{ a.affiliate_email }} {{ a.product_name }} {{ a.created_at?.slice(0,10) }}
{{ t('title_security') }}
{{ t('lbl_setup_2fa') }}

{{ t('lbl_security_sub') }}

{{ t('lbl_scan_instr') }}

{{ t('lbl_2fa_secret') }} {{ twoFaSecret }}

{{ twoFaMsg }}

{{ t('lbl_disable_2fa_section') }}

{{ t('lbl_disable_2fa_desc') }}

{{ t('lbl_how_it_works') }}

1. Click Generate QR Code and scan with Google Authenticator, Authy, or any TOTP app.

2. Enter the 6-digit code shown in your app to verify and activate.

3. Next time you log in, after entering your password you'll be asked for a 6-digit code.

4. Codes expire every 30 seconds.

⚠ Save your secret key — if you lose access to your authenticator app and don't have the secret, you'll need database access to recover.
🎨 {{ lang==='es'?'Marca Blanca':'White-Label Branding' }}
{{ t('lbl_brand_settings') }}
{{ t('lbl_colors_section') }}

{{ brandMsg }}

{{ t('lbl_live_preview') }}
{{ brandForm.company_name || 'Your Company' }}
AFFILIATE PORTAL
Email
Password
Sign In
{{ brandForm.footer_text }}
{{ t('lbl_custom_domain_setup') }}

To use your own domain for the affiliate portal:

  1. Add a CNAME record in your DNS:
Type: CNAME
Name: {{ brandForm.custom_domain ? brandForm.custom_domain.split('.')[0] : 'affiliates' }}
Value: p24-affiliate.pages.dev

2. Enter the full domain above and save.

3. Contact admin to activate SSL for your domain.

🎨 Owner Branding Management
{{ t('lbl_all_owners') }}
OwnerCompany NamePrimary ColorCustom DomainAction
{{ b.owner_name }} {{ b.company_name || '—' }} {{ b.primary_color }} Default {{ b.custom_domain }}
🚨 Fraud Detection
Total Duplicate Clicks
{{ fraudData.summary?.total_dup || 0 }}
Affiliates with Dups
{{ fraudData.summary?.affected_affiliates || 0 }}
Suspended
{{ fraudData.suspended?.length || 0 }}
Top Duplicate Click Offenders
AffiliateEmailDuplicate ClicksLast SeenAction
{{ a.name }} {{ a.email }} {{ a.dup_count }} {{ a.last_seen?.slice(0,16) }}
No duplicate click offenders detected
Currently Suspended Affiliates
NameEmailSuspended SinceAction
{{ a.name }}{{ a.email }} {{ a.created_at?.slice(0,10) }}
No suspended affiliates
🎯 Pixels & Tags
{{ t('lbl_your_pixels') }}

{{ t('lbl_pixels_desc') }}

{{ t('th_platform') }}{{ t('th_pixel_id_col') }}{{ t('th_event_name') }}{{ t('col_product') }}{{ t('th_server_api') }}{{ t('col_status') }}{{ t('th_actions') }}
{{ px.platform }} {{ px.pixel_id }} {{ px.event_name }} {{ px.product_name || (lang==='es'?'Todos los Productos':'All Products') }} {{ (px.platform==='facebook'||px.platform==='tiktok') && px.access_token ? '✅' : '—' }} {{ px.is_active ? t('lbl_pixel_active') : t('lbl_pixel_paused') }}
{{ t('no_pixels') }}
🖼️ {{ t('nav_media') }}
{{ m.name }}
{{ m.product_name || 'All Products' }} · {{ m.size || '—' }}
{{ m.type }} {{ m.status }}
{{ t('no_media_yet') }}
🎟️ {{ t('nav_promos') }}
{{ t('th_code') }}{{ t('col_product') }}{{ t('col_owner') }}{{ t('col_affiliate') }}{{ t('col_type') }}{{ t('th_value') }}{{ t('th_uses') }}{{ t('th_expires') }}{{ t('col_status') }}{{ t('col_action') }}
{{ p.code }} {{ p.product_name || (lang==='es'?'Todos':'All') }} {{ p.owner_name || '—' }} {{ p.affiliate_name || (lang==='es'?'Todos':'All') }} {{ p.bonus_type }} {{ p.bonus_value || '—' }} {{ p.uses_count||0 }}{{ p.max_uses ? '/'+p.max_uses : '' }} {{ p.expires_at?.slice(0,10) || t('lbl_never_expires') }} {{ p.status }}
{{ t('no_promos') }}
🖼️ {{ lang==='es'?'Mis Medios':'My Media' }}
{{ m.name }}
{{ m.size || '—' }} · {{ m.type }}
{{ t('no_owner_media') }}
🎟️ {{ t('nav_promos') }}
{{ t('th_code') }}{{ t('col_product') }}{{ t('col_affiliate') }}{{ t('col_type') }}{{ t('th_value') }}{{ t('th_uses') }}{{ t('th_expires') }}{{ t('col_action') }}
{{ p.code }} {{ p.product_name || '—' }} {{ p.affiliate_name || (lang==='es'?'Todos':'All') }} {{ p.bonus_type }} {{ p.bonus_value || '—' }} {{ p.uses_count||0 }}{{ p.max_uses ? '/'+p.max_uses : '' }} {{ p.expires_at?.slice(0,10) || t('lbl_never_expires') }}
{{ t('no_promos') }}
🖼️ {{ t('title_creatives') }}

{{ t('lbl_creatives_desc') }}

{{ m.name }}
{{ m.product_name || (lang==='es'?'Todos los Productos':'All Products') }} · {{ m.type }}
{{ t('lbl_no_creatives_aff') }}
💎 Commission Management
{{ cr.product_name }} — {{ cr.model?.toUpperCase() }}
No products with commission rules yet.
AffiliateProductPlanModelCPARev%CAPCarryoverAction
{{ p.affiliate_name }}
{{ p.affiliate_email }}
{{ p.product_name }} {{ p.plan_name }} {{ p.model }} ${{ p.cpa_amount || '—' }} {{ p.rev_pct ? p.rev_pct+'%' : '—' }} {{ p.cpa_cap ? p.cpa_cap+'/'+p.cpa_cap_period : '—' }} {{ p.negative_carryover ? 'Yes' : 'No' }}
No custom plans. All affiliates use the default product commission.
Current Period CPA CAP Usage
AffiliateProductUsedLimit% UsedPeriod
{{ c.affiliate_name }} {{ c.product_name }} {{ c.count }} {{ c.cap_limit || '∞' }}
{{ Math.round((c.count/c.cap_limit)*100) }}%
No cap
{{ c.period }}
No CPA activity this period
💎 Commission Settings
{{ cr.product_name }} — {{ cr.model?.toUpperCase() }}
Set commission rules first via My Products.
🤝 Referral Commission
Referral Relationships
ReferrerSub-AffiliateJoinedTheir EarningsReferral Earned
{{ r.referrer_name }}
{{ r.referrer_email }}
{{ r.referee_name }}
{{ r.referee_email }}
{{ r.created_at?.slice(0,10) }} ${{ (r.total_referral_earned||0).toFixed(2) }}
No referral relationships yet
Global Commission Rate

Affiliates earn this % of their sub-affiliates' commissions.

{{ referralMsg }}

🧾 Invoices
Invoice #AffiliateAmountStatusCreatedActions
{{ inv.invoice_number || '#'+inv.id }} {{ inv.affiliate_name }}
{{ inv.affiliate_email }}
${{ inv.amount?.toFixed(2) }} {{ inv.currency }} {{ inv.status }} {{ inv.created_at?.slice(0,10) }}
No invoices yet. They are auto-created when payouts are approved.
💬 Messages
ToSubjectTypeDate
{{ m.is_broadcast ? '📢 All Affiliates' : (m.to_name||m.to_id) }} {{ m.subject }} {{ m.is_broadcast ? 'Broadcast' : 'Direct' }} {{ m.created_at?.slice(0,16) }}
No messages sent yet
🎟️ Available Promo Codes

Use these promo codes in your promotions. Click a code to copy it.

CodeProductBonus TypeValueExpires
{{ p.code }} ✓ Copied! {{ p.product_name || 'All Products' }} {{ p.bonus_type }} {{ p.bonus_value || '—' }} {{ p.expires_at?.slice(0,10) || 'Never' }}
No promo codes available for your products yet.
🤝 Refer & Earn
Your Referral Link

Share this link to recruit other affiliates. You earn a % of their commissions automatically.

Code: {{ refCode }}
Sub-Affiliates
{{ myReferrals.length }}
Total Earned
${{ refEarningsTotal.toFixed(2) }}
How It Works

1. Share your referral link with other marketers

2. When they register and get approved, they become your sub-affiliate

3. Every time they earn a commission, you automatically earn a percentage

4. Your referral earnings appear in your earnings ledger

My Sub-Affiliates
NameEmailStatusTheir ClicksTheir ConversionsJoined
{{ r.name }} {{ r.email }} {{ r.status }} {{ r.clicks || 0 }} {{ r.their_commission?.toFixed(2) ? '$'+r.their_commission.toFixed(2) : '—' }} {{ r.created_at?.slice(0,10) }}
No sub-affiliates yet. Share your referral link to get started!
🧾 My Invoices
Invoice #AmountStatusCreatedPaid
{{ inv.invoice_number || '#'+inv.id }} ${{ Number(inv.amount).toFixed(2) }} {{ inv.currency }} {{ inv.status }} {{ inv.created_at?.slice(0,10) }} {{ inv.paid_at?.slice(0,10) || '—' }}
No invoices yet. Invoices are generated automatically when your payout is approved.
💬 Messages
{{ m.subject }} New {{ m.created_at?.slice(0,16) }}
{{ m.body }}
No messages yet.
🔑 {{ t('nav_docs_tokens') }}

{{ t('docs_token_desc') }}

Name Token Type Expires Created
No tokens yet. Create one to share docs.
{{ t.name }}
{{ t.token }}
{{ t.type }} {{ t.expires_at || '—' }} {{ t.created_at?.slice(0,10) }}
📖 Docs URLs
Brands: https://p24-docs.pages.dev?key={token} → shows brand docs
Affiliates: https://p24-docs.pages.dev?key={token} → shows affiliate docs
Create Docs Access Token
🏷️ Brands
BrandOwnerWebsiteProductsStatusAction
{{ b.name }}
{{ b.owner_name || '—' }} {{ b.website }} {{ b.product_count || 0 }} products {{ b.status }}
No brands yet. Add a brand to categorize your products.
🏷️ My Brands
BrandWebsiteProductsColor
{{ b.name }}
{{ b.website }} {{ b.product_count || 0 }} products {{ b.primary_color }}
No brands yet.
💱 Exchange Rates (from USD)
Add / Update Rate

{{ rateMsg }}

Current Rates
FromToRateUpdatedAction
USD {{ r.to_currency }} {{ r.rate }} {{ r.updated_at?.slice(0,16) }}
No exchange rates configured
🌍 Country Tax Rules
Add / Update Rule

{{ taxMsg }}

Country Tax Rules
CountryTax RateApplies ToAction
{{ t.country }} {{ t.tax_rate }}% {{ t.applies_to }}
No tax rules configured
✅ Payment Qualification Rules
Add Rule

{{ qualMsg }}

Active Rules
TypeMin ClicksMin Conv.Min BalanceAction
{{ q.is_global ? 'Global' : 'Product' }} {{ q.min_clicks || 0 }} {{ q.min_conversions || 0 }} ${{ q.min_balance || 0 }}
No qualification rules — all affiliates can request payout
{{ toastMsg }}