Diff -- /var/www/vhosts/3dshawn.com/affiliate.3dshawn.com/index.cgi
Diff

/var/www/vhosts/3dshawn.com/affiliate.3dshawn.com/index.cgi

added on local at 2026-07-01 13:47:22

Added
+824
lines
Removed
-0
lines
Context
0
unchanged
Blobs
from
to 15f2f529672d
Restore this content →
Unified diff
Naive LCS-based line diff. Additions in emerald, deletions in rose. Both sides decompressed live from BLOB_STORE.
1#!/usr/bin/perl
2#======================================================================
3# AffSoft -- public landing page + 8 marketing/legal pages.
4#
5# Consolidates about.cgi, contact.cgi, faq.cgi, features.cgi, help.cgi,
6# privacy.cgi, terms.cgi, why.cgi into this file via SCRIPT_NAME
7# dispatch. Each of the 8 files is now a 3-line wrapper that `do`s
8# this file. Larger marketing pages (tour, tutorials, pricing) stay
9# standalone by design.
10#
11# Default entry (index.cgi):
12# Signed in -> 302 to /dashboard.cgi
13# Signed out -> render the affiliate-program marketing landing page.
14#======================================================================
15use strict;
16use warnings;
17
18use lib '/var/www/vhosts/3dshawn.com/affiliate.3dshawn.com';
19use CGI;
20use CGI::Carp qw(fatalsToBrowser);
21use MODS::Login;
22use MODS::AffSoft::Wrapper;
23
24my $auth = MODS::Login->new;
25my $wrap = MODS::AffSoft::Wrapper->new;
26my $userinfo = $auth->login_verify;
27
28my $entry = ($ENV{SCRIPT_NAME} || '') =~ m{/([^/]+)\.cgi$} ? $1 : 'index';
29
30if ($entry eq 'about') { _mkt_about(); }
31elsif ($entry eq 'contact') { _mkt_contact(); }
32elsif ($entry eq 'faq') { _mkt_faq(); }
33elsif ($entry eq 'features') { _mkt_features(); }
34elsif ($entry eq 'help') { _mkt_help(); }
35elsif ($entry eq 'privacy') { _mkt_privacy(); }
36elsif ($entry eq 'terms') { _mkt_terms(); }
37elsif ($entry eq 'why') { _mkt_why(); }
38else { _mkt_landing(); }
39exit;
40
41#======================================================================
42# / (index.cgi) : landing page + logged-in redirect
43#======================================================================
44sub _mkt_landing {
45 if ($userinfo && $userinfo->{user_id}) {
46 print "Status: 302 Found\r\nLocation: /dashboard.cgi\r\n\r\n";
47 return;
48 }
49
50 print "Content-Type: text/html; charset=utf-8\r\nCache-Control: no-store, no-cache, must-revalidate, max-age=0\r\nPragma: no-cache\r\nExpires: 0\r\n\r\n";
51
52 my $body = <<'HTML';
53<!-- ── Hero ───────────────────────────────────────────────────── -->
54<section class="hero">
55 <div class="hero-grid-bg"></div>
56 <div class="hero-glow-1"></div>
57 <div class="hero-glow-2"></div>
58 <div class="hero-glow-3"></div>
59
60 <div class="hero-inner">
61 <div>
62 <span class="hero-pill">
63 <span class="dot"></span> Trackable links &middot; Attribution &middot; Payouts &middot; Branded portals
64 </span>
65 <h1 class="hero-title" style="font-size:clamp(28px,4.2vw,52px);line-height:1.12;letter-spacing:-0.02em;max-width:780px">
66 No more tracking affiliates in spreadsheets and chasing down payouts. <span class="grad">AffSoft mints the links, attributes the sales, and runs the payouts &mdash; automatically.</span>
67 </h1>
68 <p class="hero-sub" style="max-width:680px">
69 Trackable referral links, real-time conversion attribution with a real cookie window, custom commission tiers,
70 automated monthly payouts, and branded affiliate portals. Built for SaaS, ecom, agencies, and creators.
71 </p>
72 <div class="hero-cta">
73 <a href="/signup.cgi" class="btn btn-primary btn-lg">Start free trial</a>
74 <a href="/tour.cgi" class="btn btn-secondary btn-lg">See the platform</a>
75 </div>
76 <div class="hero-trust">
77 <div class="hero-trust-item">
78 <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polyline points="20 6 9 17 4 12"/></svg>
79 No credit card required
80 </div>
81 <div class="hero-trust-item">
82 <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polyline points="20 6 9 17 4 12"/></svg>
83 Server-to-server webhook &middot; HMAC ready
84 </div>
85 <div class="hero-trust-item">
86 <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polyline points="20 6 9 17 4 12"/></svg>
87 Every click + conversion is a row
88 </div>
89 </div>
90 </div>
91
92 <!-- Stacked floating dashboard cards -->
93 <div class="hero-visual">
94 <div class="float-card fc-1">
95 <div class="flex justify-between items-center mb-1">
96 <span class="text-xs text-dim" style="letter-spacing:1.5px;text-transform:uppercase">Commissions &middot; MTD</span>
97 <span class="pill success" style="padding:2px 8px;font-size:10px">+24.6%</span>
98 </div>
99 <div style="font-family:var(--font-display);font-size:28px;font-weight:700;color:#fff">$4,287.40</div>
100 <div class="text-xs text-dim mt-1">Across 38 affiliates &middot; 142 conversions</div>
101 </div>
102
103 <div class="float-card fc-2">
104 <div class="text-xs text-dim mb-2" style="letter-spacing:1.5px;text-transform:uppercase">Top affiliates</div>
105 <div class="flex items-center gap-3 mb-1">
106 <span class="dot-status green"></span>
107 <span class="text-sm fw-600">@anna.creates</span>
108 <span class="text-xs text-dim" style="margin-left:auto">$842.10</span>
109 </div>
110 <div class="flex items-center gap-3 mb-1">
111 <span class="dot-status green"></span>
112 <span class="text-sm fw-600">@growth-loop</span>
113 <span class="text-xs text-dim" style="margin-left:auto">$618.00</span>
114 </div>
115 <div class="flex items-center gap-3 mb-1">
116 <span class="dot-status yellow"></span>
117 <span class="text-sm fw-600">@reviewbox</span>
118 <span class="text-xs text-dim" style="margin-left:auto">$494.20</span>
119 </div>
120 <div class="flex items-center gap-3">
121 <span class="dot-status green"></span>
122 <span class="text-sm fw-600">@indiestack</span>
123 <span class="text-xs text-dim" style="margin-left:auto">$370.50</span>
124 </div>
125 </div>
126
127 <div class="float-card fc-3">
128 <div class="flex items-center justify-between mb-2">
129 <span class="text-xs text-dim" style="letter-spacing:1.5px;text-transform:uppercase">Approval queue</span>
130 <span class="pill brand" style="padding:2px 8px;font-size:10px">7 PENDING</span>
131 </div>
132 <div class="flex justify-between mb-1">
133 <span class="text-sm">Conv #2148 &middot; @anna.creates</span>
134 <span class="text-sm fw-600 tabular">$24.90</span>
135 </div>
136 <div class="progress mb-2"><div class="progress-fill" style="width:62%"></div></div>
137 <div class="flex justify-between mb-1">
138 <span class="text-sm">Conv #2149 &middot; @growth-loop</span>
139 <span class="text-sm fw-600 tabular text-success">$48.00</span>
140 </div>
141 <div class="progress"><div class="progress-fill" style="width:94%"></div></div>
142 <div class="text-xs text-dim mt-1">One-click approve &middot; refund-protected commissions</div>
143 </div>
144 </div>
145 </div>
146</section>
147
148
149<!-- ── What you save vs the rest ────────────────────────────── -->
150<section class="section" style="padding:48px 24px 24px">
151 <div style="max-width:920px;margin:0 auto">
152 <div style="text-align:center;font-size:11px;text-transform:uppercase;letter-spacing:2px;color:#94a3b8;font-weight:700;margin-bottom:8px">Why merchants switch</div>
153 <h2 style="text-align:center;font-size:clamp(22px,2.8vw,30px);margin:0 0 28px;font-weight:700">Same features. Lower bill. No payout cut.</h2>
154 <div style="display:grid;grid-template-columns:repeat(auto-fit,minmax(280px,1fr));gap:14px">
155 <div style="background:rgba(148,163,184,0.06);border:1px solid rgba(148,163,184,0.15);border-radius:12px;padding:22px">
156 <div style="font-size:10px;text-transform:uppercase;letter-spacing:1.5px;color:#94a3b8;font-weight:700;margin-bottom:14px">Most affiliate platforms</div>
157 <ul style="list-style:none;padding:0;margin:0;font-size:13px;color:#cbd5e1;line-height:1.7">
158 <li style="display:flex;gap:8px;margin-bottom:6px"><span style="color:#94a3b8;flex-shrink:0">&times;</span><span>&#36;89&ndash;&#36;300/mo, per-seat scaling</span></li>
159 <li style="display:flex;gap:8px;margin-bottom:6px"><span style="color:#94a3b8;flex-shrink:0">&times;</span><span>2&ndash;5% cut on every payout</span></li>
160 <li style="display:flex;gap:8px;margin-bottom:6px"><span style="color:#94a3b8;flex-shrink:0">&times;</span><span>Affiliate portals locked to enterprise</span></li>
161 <li style="display:flex;gap:8px;margin-bottom:6px"><span style="color:#94a3b8;flex-shrink:0">&times;</span><span>Merchant has to manually approve every signup</span></li>
162 <li style="display:flex;gap:8px;margin-bottom:0"><span style="color:#94a3b8;flex-shrink:0">&times;</span><span>Annual contracts</span></li>
163 </ul>
164 </div>
165 <div style="background:linear-gradient(135deg,rgba(168,85,247,0.10) 0%,rgba(124,58,237,0.10) 100%);border:1px solid rgba(168,85,247,0.4);border-radius:12px;padding:22px">
166 <div style="font-size:10px;text-transform:uppercase;letter-spacing:1.5px;color:#a855f7;font-weight:700;margin-bottom:14px">AffSoft</div>
167 <ul style="list-style:none;padding:0;margin:0;font-size:13px;color:#e6ecf6;line-height:1.7">
168 <li style="display:flex;gap:8px;margin-bottom:6px"><span style="color:#22c55e;flex-shrink:0">&#10003;</span><span>Free forever, paid from <span class="dlr">&#36;</span>9/mo</span></li>
169 <li style="display:flex;gap:8px;margin-bottom:6px"><span style="color:#22c55e;flex-shrink:0">&#10003;</span><span>0% cut on payouts &mdash; ever</span></li>
170 <li style="display:flex;gap:8px;margin-bottom:6px"><span style="color:#22c55e;flex-shrink:0">&#10003;</span><span>Branded affiliate portals included</span></li>
171 <li style="display:flex;gap:8px;margin-bottom:6px"><span style="color:#22c55e;flex-shrink:0">&#10003;</span><span>Public marketplace to get found by affiliates</span></li>
172 <li style="display:flex;gap:8px;margin-bottom:0"><span style="color:#22c55e;flex-shrink:0">&#10003;</span><span>Monthly billing &middot; cancel any time</span></li>
173 </ul>
174 </div>
175 </div>
176 </div>
177</section>
178
179<!-- ── Stack strip ───────────────────────────────────────────── -->
180<section class="section" style="padding-top:0">
181 <div class="card" style="padding:28px 32px;display:flex;align-items:center;justify-content:space-between;gap:32px;flex-wrap:wrap">
182 <div class="text-xs text-dim" style="letter-spacing:2px;text-transform:uppercase;font-weight:700">Drop-in for</div>
183 <div class="flex items-center gap-6" style="flex-wrap:wrap;font-family:var(--font-display);color:var(--col-text-2);font-size:18px;letter-spacing:1px">
184 <span>Stripe Checkout</span><span class="text-dim">&middot;</span>
185 <span>WooCommerce</span><span class="text-dim">&middot;</span>
186 <span>Shopify</span><span class="text-dim">&middot;</span>
187 <span>Gumroad</span><span class="text-dim">&middot;</span>
188 <span>Lemon Squeezy</span><span class="text-dim">&middot;</span>
189 <span>Paddle</span><span class="text-dim">&middot;</span>
190 <span>Custom backends</span>
191 </div>
192 </div>
193</section>
194
195
196<!-- ── How it works (3 steps) ───────────────────────────────── -->
197<section class="section" id="how">
198 <span class="section-eyebrow">How it works</span>
199 <h2 class="section-title">Three steps. <span class="grad">No tag manager required.</span></h2>
200 <p class="section-sub">
201 AffSoft is small on purpose. You launch a program, hand affiliates a link,
202 and fire one webhook from your checkout. The rest is bookkeeping &mdash; and
203 we do the bookkeeping.
204 </p>
205
206 <div class="feature-grid">
207 <div class="feature">
208 <div class="feature-icon"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="12" cy="12" r="10"/><text x="12" y="16" text-anchor="middle" font-size="11" font-weight="700" stroke="none" fill="currentColor">1</text></svg></div>
209 <div class="feature-title">Create a program</div>
210 <p class="feature-desc">Name it, pick a commission model (percent of order, flat per sale, or CPA), and set the attribution window. Public discover-page listing is optional.</p>
211 </div>
212 <div class="feature">
213 <div class="feature-icon"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="12" cy="12" r="10"/><text x="12" y="16" text-anchor="middle" font-size="11" font-weight="700" stroke="none" fill="currentColor">2</text></svg></div>
214 <div class="feature-title">Affiliates grab links</div>
215 <p class="feature-desc">12-character tokens with optional <code>?s=sub_id</code> for campaign tagging. Affiliates self-serve from their own dashboard &mdash; you don&rsquo;t mint links by hand.</p>
216 </div>
217 <div class="feature">
218 <div class="feature-icon"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="12" cy="12" r="10"/><text x="12" y="16" text-anchor="middle" font-size="11" font-weight="700" stroke="none" fill="currentColor">3</text></svg></div>
219 <div class="feature-title">POST a conversion</div>
220 <p class="feature-desc">Server-to-server: <code>POST /conv.cgi</code> from your checkout success handler. We match against the visitor&rsquo;s most-recent in-window click and write a pending row.</p>
221 </div>
222 </div>
223</section>
224
225
226<!-- ── Attribution module deep-dive ─────────────────────────── -->
227<section class="section" id="attribution">
228 <div class="dash-grid" style="align-items:center">
229 <div>
230 <span class="section-eyebrow">Attribution Module</span>
231 <h2 class="section-title" style="font-size:38px">Real attribution. <span class="grad">No mystery math.</span></h2>
232 <p class="section-sub" style="margin-bottom:24px">
233 Every click writes a row. Every conversion runs the same matching query
234 you could write yourself: most-recent click in this program for this
235 visitor inside the window. Click trail, attribution decision, and
236 commission calculation are all auditable in SQL.
237 </p>
238 <ul class="price-list" style="margin:0 0 28px">
239 <li><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3"><polyline points="20 6 9 17 4 12"/></svg> Per-program cookie window (1&ndash;365 days)</li>
240 <li><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3"><polyline points="20 6 9 17 4 12"/></svg> Last-click match against most-recent in-window click</li>
241 <li><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3"><polyline points="20 6 9 17 4 12"/></svg> Commission stored in cents &mdash; zero rounding drift</li>
242 <li><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3"><polyline points="20 6 9 17 4 12"/></svg> Sub-id passthrough for campaign attribution</li>
243 </ul>
244 <a href="/signup.cgi" class="btn btn-primary">Start free trial &rarr;</a>
245 </div>
246
247 <div class="card card-elevated" style="padding:0;overflow:hidden">
248 <div style="padding:18px 22px;border-bottom:1px solid var(--col-border);display:flex;align-items:center;justify-content:space-between">
249 <div class="flex items-center gap-3">
250 <div class="module-icon" style="width:30px;height:30px"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M3 3v18h18"/><path d="m7 14 4-4 4 4 5-5"/></svg></div>
251 <span class="module-title">Click trail &middot; visitor 9F2A&hellip;</span>
252 </div>
253 <span class="pill brand">Matched</span>
254 </div>
255 <div class="table-wrap" style="border:none;border-radius:0">
256 <table class="table">
257 <thead><tr><th>When</th><th>Link</th><th>Affiliate</th><th class="num">Status</th></tr></thead>
258 <tbody>
259 <tr><td class="text-dim">12:04</td><td><strong>r/8kQp&hellip;</strong></td><td>@anna.creates</td><td><span class="pill success"><span class="dot-status green"></span>Counted</span></td></tr>
260 <tr><td class="text-dim">11:48</td><td><strong>r/8kQp&hellip;</strong></td><td>@anna.creates</td><td><span class="pill info">Click</span></td></tr>
261 <tr><td class="text-dim">11:12</td><td><strong>m/X2Vy&hellip;</strong></td><td>@growth-loop</td><td><span class="pill info">Click (older)</span></td></tr>
262 <tr><td class="text-dim">10:36</td><td><strong>r/8kQp&hellip;</strong></td><td>@anna.creates</td><td><span class="pill info">Click</span></td></tr>
263 <tr><td class="text-dim">&mdash;</td><td colspan="2"><em>Conversion @ 12:14 &middot; matched most-recent click in window</em></td><td class="num text-success">+$24.90</td></tr>
264 </tbody>
265 </table>
266 </div>
267 </div>
268 </div>
269</section>
270
271
272<!-- ── Payouts strip ─────────────────────────────────────────── -->
273<section class="section" id="payouts">
274 <div class="dash-grid" style="grid-template-columns:1fr 1fr;align-items:center">
275 <div class="card card-elevated" style="padding:0;overflow:hidden">
276 <div style="height:280px;background:linear-gradient(160deg, #160e28 0%, #2b1853 100%);position:relative;overflow:hidden">
277 <div style="position:absolute;inset:0;background-image:radial-gradient(rgba(255,255,255,0.06) 1px, transparent 1px);background-size:32px 32px"></div>
278 <div style="position:absolute;top:24px;left:24px;color:#fff;font-family:var(--font-display);font-size:22px;font-weight:600">Payout #142</div>
279 <div style="position:absolute;top:54px;left:24px;color:var(--col-text-3);font-size:12px">Manual mode &middot; PayPal txn 8AB29</div>
280 <div style="position:absolute;bottom:24px;left:24px;right:24px;display:grid;grid-template-columns:repeat(3,1fr);gap:12px">
281 <div style="padding:14px;background:rgba(124,58,237,0.20);border:1px solid rgba(124,58,237,0.45);border-radius:10px">
282 <div style="font-size:10px;letter-spacing:1.5px;text-transform:uppercase;color:var(--col-violet-bright);font-weight:700">Approved</div>
283 <div style="font-family:var(--font-display);font-size:18px;font-weight:700;color:#fff">$842.10</div>
284 </div>
285 <div style="padding:14px;background:rgba(124,58,237,0.20);border:1px solid rgba(124,58,237,0.45);border-radius:10px">
286 <div style="font-size:10px;letter-spacing:1.5px;text-transform:uppercase;color:var(--col-violet-bright);font-weight:700">Refunded</div>
287 <div style="font-family:var(--font-display);font-size:18px;font-weight:700;color:#fff">$0.00</div>
288 </div>
289 <div style="padding:14px;background:rgba(34,197,94,0.15);border:1px solid rgba(34,197,94,0.40);border-radius:10px">
290 <div style="font-size:10px;letter-spacing:1.5px;text-transform:uppercase;color:#86efac;font-weight:700">Sent</div>
291 <div style="font-family:var(--font-display);font-size:18px;font-weight:700;color:#fff">$842.10</div>
292 </div>
293 </div>
294 </div>
295 <div style="padding:18px 22px;display:flex;justify-content:space-between;align-items:center">
296 <div>
297 <div class="text-xs text-dim" style="letter-spacing:1.5px;text-transform:uppercase">Period</div>
298 <div style="font-family:var(--font-display);font-size:16px;font-weight:700;color:#fff">Jun 01 &ndash; Jun 30</div>
299 </div>
300 <div>
301 <div class="text-xs text-dim" style="letter-spacing:1.5px;text-transform:uppercase">Conversions</div>
302 <div style="font-family:var(--font-display);font-size:16px;font-weight:700;color:#fff">37</div>
303 </div>
304 <div>
305 <div class="text-xs text-dim" style="letter-spacing:1.5px;text-transform:uppercase">Status</div>
306 <div style="font-family:var(--font-display);font-size:16px;font-weight:700;color:var(--col-success)">Sent</div>
307 </div>
308 </div>
309 </div>
310
311 <div>
312 <span class="section-eyebrow">Payouts Module</span>
313 <h2 class="section-title" style="font-size:38px">Approve. Pay. <span class="grad">Paper trail.</span></h2>
314 <p class="section-sub" style="margin-bottom:24px">
315 Conversions land as <em>pending</em>. You approve or reject. When you
316 cut a payout, AffSoft sums the affiliate&rsquo;s approved-but-unpaid
317 commissions, writes the payout row, and links every conversion to it
318 through a <code>payout_lines</code> table &mdash; so refunds and audits
319 stay sane.
320 </p>
321 <ul class="price-list" style="margin:0 0 28px">
322 <li><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3"><polyline points="20 6 9 17 4 12"/></svg> One-click approve / reject / refund per conversion</li>
323 <li><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3"><polyline points="20 6 9 17 4 12"/></svg> Manual-mode payouts today (PayPal txn / wire ref / Stripe id)</li>
324 <li><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3"><polyline points="20 6 9 17 4 12"/></svg> Stripe Connect automated transfers (rolling out)</li>
325 <li><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3"><polyline points="20 6 9 17 4 12"/></svg> Affiliate-side earnings dashboard included</li>
326 </ul>
327 <a href="/signup.cgi" class="btn btn-primary">Launch a program &rarr;</a>
328 </div>
329 </div>
330</section>
331
332
333<!-- ── Discover / affiliate-side strip ───────────────────────── -->
334<section class="section" id="discover">
335 <span class="section-eyebrow">For affiliates</span>
336 <h2 class="section-title">Both sides of the deal. <span class="grad">One account.</span></h2>
337 <p class="section-sub">
338 Every AffSoft account is both a merchant and an affiliate. Run your own
339 program AND promote someone else&rsquo;s from the same login. Discover
340 public programs, mint your own tracking links, and watch earnings land
341 in real time.
342 </p>
343
344 <div class="dash-grid-3">
345 <div class="card card-elevated">
346 <div class="card-head"><div class="card-title"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="11" cy="11" r="7"/><path d="m21 21-4.3-4.3"/></svg> Discover programs</div></div>
347 <p class="text-secondary text-sm">Browse every public program on the platform. Filter by commission rate, attribution window, or category. Join with one click; auto-approve or merchant-review per program.</p>
348 </div>
349
350 <div class="card card-elevated">
351 <div class="card-head"><div class="card-title"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg> Mint your links</div></div>
352 <p class="text-secondary text-sm">Self-service from your affiliate dashboard. Add as many sub-id tags as you want for campaign-level attribution &mdash; we keep them all in the click row.</p>
353 </div>
354
355 <div class="card card-elevated">
356 <div class="card-head"><div class="card-title"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><line x1="12" y1="1" x2="12" y2="23"/><path d="M17 5H9.5a3.5 3.5 0 0 0 0 7h5a3.5 3.5 0 0 1 0 7H6"/></svg> Watch earnings</div></div>
357 <p class="text-secondary text-sm">Pending / approved / paid broken out per program. Payout history with every line item the merchant reconciled. No black boxes between you and the cheque.</p>
358 </div>
359 </div>
360</section>
361
362
363<!-- ── Pricing teaser ─────────────────────────────────────────── -->
364<section class="section" id="pricing">
365 <span class="section-eyebrow">Pricing</span>
366 <h2 class="section-title">Honest pricing. <span class="grad">No per-conversion tax.</span></h2>
367 <p class="section-sub">Pick a plan based on program count and affiliate roster size. No nickel-and-diming on tracked conversions, no take rate on commissions paid.</p>
368
369 <div class="pricing-grid">
370 <div class="price-card">
371 <div class="price-tier">Free</div>
372 <div class="price-amt">$0<span class="per"> /mo</span></div>
373 <div class="price-desc">Kick the tires &middot; one program, 5 affiliates</div>
374 <ul class="price-list">
375 <li><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3"><polyline points="20 6 9 17 4 12"/></svg> 1 program</li>
376 <li><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3"><polyline points="20 6 9 17 4 12"/></svg> Up to 5 affiliates</li>
377 <li><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3"><polyline points="20 6 9 17 4 12"/></svg> Server-to-server webhook</li>
378 <li><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3"><polyline points="20 6 9 17 4 12"/></svg> Manual payouts</li>
379 </ul>
380 <a href="/signup.cgi" class="btn btn-secondary btn-block" style="margin-top:auto">Start free</a>
381 </div>
382
383 <div class="price-card">
384 <div class="price-tier">Starter</div>
385 <div class="price-amt">$9<span class="per"> /mo</span></div>
386 <div class="price-desc">Small programs that need real attribution</div>
387 <ul class="price-list">
388 <li><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3"><polyline points="20 6 9 17 4 12"/></svg> 3 programs</li>
389 <li><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3"><polyline points="20 6 9 17 4 12"/></svg> 50 affiliates</li>
390 <li><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3"><polyline points="20 6 9 17 4 12"/></svg> Sub-id passthrough</li>
391 <li><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3"><polyline points="20 6 9 17 4 12"/></svg> CSV exports</li>
392 </ul>
393 <a href="/signup.cgi" class="btn btn-secondary btn-block" style="margin-top:auto">Start trial</a>
394 </div>
395
396 <div class="price-card featured">
397 <div class="price-tier">Pro</div>
398 <div class="price-amt">$29<span class="per"> /mo</span></div>
399 <div class="price-desc">Most folks land here</div>
400 <ul class="price-list">
401 <li><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3"><polyline points="20 6 9 17 4 12"/></svg> 10 programs</li>
402 <li><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3"><polyline points="20 6 9 17 4 12"/></svg> 500 affiliates</li>
403 <li><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3"><polyline points="20 6 9 17 4 12"/></svg> HMAC-signed webhooks</li>
404 <li><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3"><polyline points="20 6 9 17 4 12"/></svg> Stripe Connect payouts</li>
405 <li><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3"><polyline points="20 6 9 17 4 12"/></svg> Priority email support</li>
406 </ul>
407 <a href="/signup.cgi" class="btn btn-primary btn-block" style="margin-top:auto">Start 14-day trial</a>
408 </div>
409
410 <div class="price-card">
411 <div class="price-tier">Studio</div>
412 <div class="price-amt">$99<span class="per"> /mo</span></div>
413 <div class="price-desc">Multi-brand operators</div>
414 <ul class="price-list">
415 <li><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3"><polyline points="20 6 9 17 4 12"/></svg> Unlimited programs</li>
416 <li><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3"><polyline points="20 6 9 17 4 12"/></svg> Unlimited affiliates</li>
417 <li><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3"><polyline points="20 6 9 17 4 12"/></svg> Team seats + 2FA</li>
418 <li><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3"><polyline points="20 6 9 17 4 12"/></svg> Per-program webhook secrets</li>
419 </ul>
420 <a href="/signup.cgi" class="btn btn-secondary btn-block" style="margin-top:auto">Start trial</a>
421 </div>
422 </div>
423
424 <div style="text-align:center;margin-top:14px">
425 <a href="/pricing.cgi" class="text-sm" style="color:var(--col-violet-bright)">See full pricing &rarr;</a>
426 </div>
427</section>
428
429
430<!-- ── Final CTA ──────────────────────────────────────────────── -->
431<section class="section">
432 <div class="card-glow card" style="text-align:center;padding:64px 32px">
433 <h2 class="section-title" style="margin:0 auto 16px">Ready to run referrals <span class="grad">like a real channel?</span></h2>
434 <p class="section-sub" style="margin: 0 auto 32px">Start free trial. No credit card. First link minted in 60 seconds.</p>
435 <div class="flex justify-center gap-3">
436 <a href="/signup.cgi" class="btn btn-primary btn-lg">Start free trial</a>
437 <a href="/tour.cgi" class="btn btn-secondary btn-lg">Tour the product</a>
438 </div>
439 </div>
440</section>
441
442
443<!-- ── Footer ─────────────────────────────────────────────────── -->
444<footer class="site-foot">
445 <div class="foot-grid">
446 <div class="foot-col">
447 <div class="flex items-center gap-3 mb-2">
448 <div class="brand-mark" style="width:32px;height:32px;font-size:15px">A<span style="color:#a78bfa">S</span></div>
449 <div class="brand-text"><span class="brand-name">AffSoft</span></div>
450 </div>
451 <p class="text-sm text-secondary" style="max-width:340px">The hosted affiliate platform that doesn&rsquo;t make you build attribution from scratch.</p>
452 </div>
453 <div class="foot-col">
454 <h5>Platform</h5>
455 <ul>
456 <li><a href="/features.cgi">Features</a></li>
457 <li><a href="/tour.cgi">Tour</a></li>
458 <li><a href="/why.cgi">Why AffSoft</a></li>
459 <li><a href="/pricing.cgi">Pricing</a></li>
460 <li><a href="/faq.cgi">FAQ</a></li>
461 </ul>
462 </div>
463 <div class="foot-col">
464 <h5>Company</h5>
465 <ul>
466 <li><a href="/about.cgi">About</a></li>
467 <li><a href="/contact.cgi">Contact</a></li>
468 </ul>
469 </div>
470 <div class="foot-col">
471 <h5>Legal &amp; Trust</h5>
472 <ul>
473 <li><a href="/privacy.cgi">Privacy</a></li>
474 <li><a href="/terms.cgi">Terms of Service</a></li>
475 </ul>
476 </div>
477 </div>
478 <div class="foot-bottom">
479 <span>&copy; 2026 AffSoft &middot; All rights reserved.</span>
480 <span>Made for operators who treat referrals like a channel.</span>
481 </div>
482</footer>
483HTML
484
485 $wrap->render({
486 userinfo => undef,
487 title => 'Affiliate program software for growth teams',
488 body => $body,
489 });
490}
491
492#======================================================================
493# /about.cgi
494#======================================================================
495sub _mkt_about {
496 print "Content-Type: text/html; charset=utf-8\r\nCache-Control: no-store, no-cache, must-revalidate, max-age=0\r\nPragma: no-cache\r\nExpires: 0\r\n\r\n";
497
498 my $body = <<'HTML';
499<div class="page-pad" style="padding:64px 32px">
500 <div style="color:#a78bfa;font-size:12px;text-transform:uppercase;letter-spacing:.1em;font-weight:600;margin-bottom:14px">About AffSoft</div>
501 <h1 style="margin:0 0 18px;font-size:42px;letter-spacing:-.02em;line-height:1.1">Affiliate software that doesn't make you build attribution from scratch.</h1>
502 <p style="color:#aaa;font-size:18px;line-height:1.6;margin:0 0 32px;max-width:600px">AffSoft is a hosted affiliate program platform. Spin up a referral program in minutes, hand out tracking links, and watch conversions land. We handle attribution windows, click + conversion bookkeeping, and merchant-side approval; you keep the product and the customer relationship.</p>
503
504 <h2 style="margin:40px 0 12px;font-size:22px;letter-spacing:-.01em">Who it's for</h2>
505 <p style="color:#bbb;line-height:1.6;margin:0 0 20px">SaaS founders, indie e-commerce stores, and growth teams who want a referral channel without standing up their own pixel, cookie store, and payout pipeline. If you'd rather spend your sprint shipping product than tracking sub_id parameters, AffSoft is for you.</p>
506
507 <h2 style="margin:40px 0 12px;font-size:22px;letter-spacing:-.01em">Who it's not for</h2>
508 <p style="color:#bbb;line-height:1.6;margin:0 0 20px">Enterprises that already have a real attribution stack. AffSoft is opinionated and lean by design &mdash; one tracking-link format, one webhook contract, one cookie name. If your compliance team needs custom data residency or your team needs SSO and SCIM today, you'll outgrow us.</p>
509
510 <h2 style="margin:40px 0 12px;font-size:22px;letter-spacing:-.01em">Where we are</h2>
511 <p style="color:#bbb;line-height:1.6;margin:0 0 28px">Early. The platform is live, attribution works, payouts go out manually while we wire the automated path. If you want a low-traffic pilot or you're rebuilding from a heavier tool, get in touch.</p>
512
513 <div style="display:flex;gap:12px;margin-top:32px">
514 <a href="/signup.cgi" class="btn btn-primary">Start free trial</a>
515 <a href="/pricing.cgi" class="btn" style="background:rgba(255,255,255,.08);color:#fff;border:1px solid rgba(255,255,255,.12)">See pricing</a>
516 </div>
517</div>
518HTML
519
520 $wrap->render({
521 userinfo => $userinfo,
522 title => 'About',
523 body => $body,
524 });
525}
526
527#======================================================================
528# /contact.cgi -- template-driven
529#======================================================================
530sub _mkt_contact {
531 require MODS::Template;
532 my $tfile = MODS::Template->new;
533 $| = 1;
534 print "Content-Type: text/html; charset=utf-8\nCache-Control: no-store, no-cache, must-revalidate, max-age=0\nPragma: no-cache\nExpires: 0\n\n";
535 my $body = join('', $tfile->template('webstls_contact.html', {}, $userinfo));
536 $wrap->render({ userinfo => $userinfo, title => 'Contact', body => $body });
537}
538
539#======================================================================
540# /faq.cgi
541#======================================================================
542sub _mkt_faq {
543 print "Content-Type: text/html; charset=utf-8\r\nCache-Control: no-store, no-cache, must-revalidate, max-age=0\r\nPragma: no-cache\r\nExpires: 0\r\n\r\n";
544
545 my @QAS = (
546 {
547 q => 'Do I have to embed any JavaScript on my site?',
548 a => 'No. Tracking links are HTTP redirects that drop an attribution cookie on the visitor. Conversions are server-to-server webhooks fired from your checkout. Nothing runs in your customers\' browsers from us.',
549 },
550 {
551 q => 'What\'s the attribution model?',
552 a => 'Last-click within a configurable cookie window (1&ndash;365 days, per program). When a conversion comes in, we match the visitor_token to the most recent click on that program within the window and attribute it to that affiliate.',
553 },
554 {
555 q => 'How do you handle refunds?',
556 a => 'Conversions land as pending. You approve them after your refund window closes. Until you approve, no commission becomes payable. Refunded conversions can be flipped to refunded status (separate from rejected) so audit trails stay clean.',
557 },
558 {
559 q => 'How are payouts made today?',
560 a => 'Manual marking in v1 &mdash; you cut the check (or PayPal, or wire) and click "mark sent" so the affiliate dashboard reflects it. Stripe Connect transfers are scheduled for v1.1.',
561 },
562 {
563 q => 'Can one person be both a merchant and an affiliate?',
564 a => 'Yes. Roles are implied by data ownership, not by an account flag. You can run programs you own and join programs other merchants run, all from one login. The dashboard shows both sides at once.',
565 },
566 {
567 q => 'Is the webhook authenticated?',
568 a => 'v1: no. Anyone with your program_id and a valid visitor_token can POST a conversion. Pending status forces your manual approval before money moves, which limits the blast radius. v1.1 adds per-program HMAC signing of the conversion payload.',
569 },
570 {
571 q => 'What\'s the data retention policy?',
572 a => 'Clicks and conversions are retained indefinitely for audit. Personal data (IPs, user agents) on click rows can be redacted on request &mdash; we keep aggregate counts and the visitor_token so attribution still works.',
573 },
574 {
575 q => 'Can I export everything?',
576 a => 'Yes. Every dashboard view has a CSV export (coming in the next release). The underlying SQL schema is documented and you have read-only access to it on Studio plan.',
577 },
578 {
579 q => 'Do you charge a take-rate on conversions?',
580 a => 'No. The platform fee is the monthly subscription. You keep 100% of what your affiliates earn and pay 100% to them. We don\'t skim conversions.',
581 },
582 {
583 q => 'What if AffSoft goes down?',
584 a => 'Tracking links 502 instead of redirecting until we\'re back up &mdash; visitors will hit a brief error. Your conversion webhook is queue-and-retry-friendly on your side; we recommend retrying on 5xx. Status page is at status.affiliate.3dshawn.com (planned).',
585 },
586 );
587
588 my $faq_html = '';
589 foreach my $qa (@QAS) {
590 my $q = $qa->{q}; $q =~ s/'/&apos;/g;
591 my $a = $qa->{a};
592 $faq_html .= qq~
593 <details style="border:1px solid rgba(255,255,255,.08);border-radius:12px;background:rgba(20,20,30,.4);overflow:hidden">
594 <summary style="padding:18px 22px;cursor:pointer;font-weight:600;color:#fff;list-style:none;display:flex;justify-content:space-between;align-items:center;gap:12px">
595 <span>$q</span>
596 <span style="color:#666;font-size:18px;flex-shrink:0">+</span>
597 </summary>
598 <div style="padding:0 22px 20px;color:#bbb;line-height:1.6;font-size:14px">$a</div>
599 </details>
600 ~;
601 }
602
603 my $body = <<HTML;
604<div class="page-pad" style="padding:64px 32px">
605 <div style="color:#a78bfa;font-size:12px;text-transform:uppercase;letter-spacing:.1em;font-weight:600;margin-bottom:14px">FAQ</div>
606 <h1 style="margin:0 0 36px;font-size:42px;letter-spacing:-.02em;line-height:1.1">Questions, answered.</h1>
607
608 <div style="display:flex;flex-direction:column;gap:10px">
609 $faq_html
610 </div>
611
612 <div style="margin-top:48px;padding:24px;border:1px dashed rgba(255,255,255,.12);border-radius:12px;color:#aaa">
613 Still have a question? Email <a href="mailto:programmershawn\@gmail.com" style="color:#a78bfa">programmershawn\@gmail.com</a>.
614 </div>
615</div>
616HTML
617
618 $wrap->render({
619 userinfo => $userinfo,
620 title => 'FAQ',
621 body => $body,
622 });
623}
624
625#======================================================================
626# /features.cgi
627#======================================================================
628sub _mkt_features {
629 print "Content-Type: text/html; charset=utf-8\r\nCache-Control: no-store, no-cache, must-revalidate, max-age=0\r\nPragma: no-cache\r\nExpires: 0\r\n\r\n";
630
631 my $body = <<'HTML';
632<div class="page-pad" style="padding:64px 32px">
633 <div style="color:#a78bfa;font-size:12px;text-transform:uppercase;letter-spacing:.1em;font-weight:600;margin-bottom:14px;text-align:center">Features</div>
634 <h1 style="margin:0 0 14px;font-size:42px;letter-spacing:-.02em;line-height:1.1;text-align:center">Everything you need to run a referral program. Nothing you don't.</h1>
635 <p style="color:#aaa;font-size:18px;line-height:1.6;margin:0 auto 56px;max-width:660px;text-align:center">AffSoft is intentionally narrow. Every feature is something you'd have to build anyway. We built it once so you don't have to.</p>
636
637 <div style="display:grid;grid-template-columns:repeat(auto-fit,minmax(280px,1fr));gap:18px">
638
639 <div style="padding:28px;border:1px solid rgba(255,255,255,.08);border-radius:14px;background:rgba(20,20,30,.4)">
640 <div style="font-size:24px;margin-bottom:14px">&#128279;</div>
641 <h3 style="margin:0 0 8px;font-size:18px">Per-affiliate tracking links</h3>
642 <p style="color:#aaa;line-height:1.55;margin:0;font-size:14px">12-character tokens, optional <code style="color:#a78bfa">?s=sub_id</code> tags for campaign attribution. Mint as many as you want per program.</p>
643 </div>
644
645 <div style="padding:28px;border:1px solid rgba(255,255,255,.08);border-radius:14px;background:rgba(20,20,30,.4)">
646 <div style="font-size:24px;margin-bottom:14px">&#128202;</div>
647 <h3 style="margin:0 0 8px;font-size:18px">Click + conversion attribution</h3>
648 <p style="color:#aaa;line-height:1.55;margin:0;font-size:14px">Configurable cookie window per program (1&ndash;365 days). Last-click attribution against the most recent matching click within window.</p>
649 </div>
650
651 <div style="padding:28px;border:1px solid rgba(255,255,255,.08);border-radius:14px;background:rgba(20,20,30,.4)">
652 <div style="font-size:24px;margin-bottom:14px">&#128176;</div>
653 <h3 style="margin:0 0 8px;font-size:18px">Three commission models</h3>
654 <p style="color:#aaa;line-height:1.55;margin:0;font-size:14px">Percent of order, flat per sale, or CPA (cost per acquisition). Commission is computed at conversion time and stored in cents to avoid rounding drift.</p>
655 </div>
656
657 <div style="padding:28px;border:1px solid rgba(255,255,255,.08);border-radius:14px;background:rgba(20,20,30,.4)">
658 <div style="font-size:24px;margin-bottom:14px">&#127867;</div>
659 <h3 style="margin:0 0 8px;font-size:18px">Server-to-server webhook</h3>
660 <p style="color:#aaa;line-height:1.55;margin:0;font-size:14px">POST <code style="color:#a78bfa">/conv.cgi</code> from your checkout. No JS pixels, no third-party scripts on your customers' browsers.</p>
661 </div>
662
663 <div style="padding:28px;border:1px solid rgba(255,255,255,.08);border-radius:14px;background:rgba(20,20,30,.4)">
664 <div style="font-size:24px;margin-bottom:14px">&#127916;</div>
665 <h3 style="margin:0 0 8px;font-size:18px">Self-service affiliate signup</h3>
666 <p style="color:#aaa;line-height:1.55;margin:0;font-size:14px">List your program publicly and let affiliates join themselves. Auto-approve or require manual review &mdash; per program.</p>
667 </div>
668
669 <div style="padding:28px;border:1px solid rgba(255,255,255,.08);border-radius:14px;background:rgba(20,20,30,.4)">
670 <div style="font-size:24px;margin-bottom:14px">&#128274;</div>
671 <h3 style="margin:0 0 8px;font-size:18px">Approval-gated payouts</h3>
672 <p style="color:#aaa;line-height:1.55;margin:0;font-size:14px">Conversions land as <em>pending</em>. You approve before they become payable &mdash; refund-protect your commission math.</p>
673 </div>
674
675 <div style="padding:28px;border:1px solid rgba(255,255,255,.08);border-radius:14px;background:rgba(20,20,30,.4)">
676 <div style="font-size:24px;margin-bottom:14px">&#128737;</div>
677 <h3 style="margin:0 0 8px;font-size:18px">Per-side dashboards</h3>
678 <p style="color:#aaa;line-height:1.55;margin:0;font-size:14px">One account is both a merchant and an affiliate. Run your own program AND promote someone else's.</p>
679 </div>
680
681 <div style="padding:28px;border:1px solid rgba(255,255,255,.08);border-radius:14px;background:rgba(20,20,30,.4)">
682 <div style="font-size:24px;margin-bottom:14px">&#128270;</div>
683 <h3 style="margin:0 0 8px;font-size:18px">Auditable</h3>
684 <p style="color:#aaa;line-height:1.55;margin:0;font-size:14px">Every click, conversion, approval, and payout is a row. You can ask any question your auditor will and answer it in SQL.</p>
685 </div>
686
687 <div style="padding:28px;border:1px solid rgba(91,33,182,.35);border-radius:14px;background:linear-gradient(135deg, rgba(91,33,182,.10), rgba(46,16,101,.04))">
688 <div style="font-size:24px;margin-bottom:14px">&#128737;&#65039;</div>
689 <h3 style="margin:0 0 8px;font-size:18px">Built-in fraud protection</h3>
690 <p style="color:#aaa;line-height:1.55;margin:0;font-size:14px">Every conversion is scanned the moment it lands. We watch for cookie stuffing, self-referral, velocity abuse, duplicate orders, and a host of other patterns. Suspicious activity is held in a review queue with a plain-English explanation of <em>why</em> &mdash; you decide, automated payouts never touch unreviewed flags. Our detection model evolves with every confirmed-fraud decision.</p>
691 </div>
692
693 </div>
694
695 <div style="text-align:center;margin-top:56px">
696 <a href="/signup.cgi" class="btn btn-primary btn-lg">Start free trial</a>
697 <div style="color:#666;font-size:13px;margin-top:10px">No credit card required &middot; 14-day full access</div>
698 </div>
699</div>
700HTML
701
702 $wrap->render({
703 userinfo => $userinfo,
704 title => 'Features',
705 body => $body,
706 });
707}
708
709#======================================================================
710# /help.cgi -- login-gated. Renders webstls_help.html template.
711#======================================================================
712sub _mkt_help {
713 require MODS::Template;
714 my $tfile = MODS::Template->new;
715 $| = 1;
716
717 # help.cgi is one of the few marketing-family pages that requires
718 # login (it's a "where do I do X" router into the app itself).
719 if (!$userinfo) {
720 print "Status: 302 Found\nLocation: /login.cgi\n\n";
721 return;
722 }
723
724 print "Content-Type: text/html; charset=utf-8\nCache-Control: no-store, no-cache, must-revalidate, max-age=0\nPragma: no-cache\nExpires: 0\n\n";
725
726 my $body = join('', $tfile->template('webstls_help.html', {}, $userinfo));
727
728 $wrap->render({
729 userinfo => $userinfo,
730 page_key => '',
731 title => 'Help',
732 body => $body,
733 });
734}
735
736#======================================================================
737# /privacy.cgi -- template-driven
738#======================================================================
739sub _mkt_privacy {
740 require MODS::Template;
741 my $tfile = MODS::Template->new;
742 $| = 1;
743 print "Content-Type: text/html; charset=utf-8\nCache-Control: no-store, no-cache, must-revalidate, max-age=0\nPragma: no-cache\nExpires: 0\n\n";
744 my $body = join('', $tfile->template('webstls_privacy.html', {}, $userinfo));
745 $wrap->render({ userinfo => $userinfo, title => 'Privacy Policy', body => $body });
746}
747
748#======================================================================
749# /terms.cgi -- template-driven
750#======================================================================
751sub _mkt_terms {
752 require MODS::Template;
753 my $tfile = MODS::Template->new;
754 $| = 1;
755 print "Content-Type: text/html; charset=utf-8\nCache-Control: no-store, no-cache, must-revalidate, max-age=0\nPragma: no-cache\nExpires: 0\n\n";
756 my $body = join('', $tfile->template('webstls_terms.html', {}, $userinfo));
757 $wrap->render({ userinfo => $userinfo, title => 'Terms of Service', body => $body });
758}
759
760#======================================================================
761# /why.cgi
762#======================================================================
763sub _mkt_why {
764 print "Content-Type: text/html; charset=utf-8\r\nCache-Control: no-store, no-cache, must-revalidate, max-age=0\r\nPragma: no-cache\r\nExpires: 0\r\n\r\n";
765
766 my $body = <<'HTML';
767<div class="page-pad" style="padding:64px 32px">
768 <div style="color:#a78bfa;font-size:12px;text-transform:uppercase;letter-spacing:.1em;font-weight:600;margin-bottom:14px">Why AffSoft</div>
769 <h1 style="margin:0 0 18px;font-size:42px;letter-spacing:-.02em;line-height:1.1">"Why don't I just build this myself?"</h1>
770 <p style="color:#aaa;font-size:18px;line-height:1.6;margin:0 0 48px">You can. Here's what you're signing up for.</p>
771
772 <div style="display:grid;grid-template-columns:1fr;gap:28px">
773
774 <div style="padding:24px 28px;border-left:3px solid #a78bfa;background:rgba(102,99,255,.04);border-radius:0 10px 10px 0">
775 <h3 style="margin:0 0 6px;font-size:18px;color:#fff">A redirect endpoint that records a click</h3>
776 <p style="color:#bbb;line-height:1.55;margin:0;font-size:14px">Sounds simple. Then you need rate limiting, bot filtering, IPv6 packing, X-Forwarded-For chain parsing, attribution-cookie scoping for subdomains, and a way to never double-count the same click from a retry. Two weeks if you're lucky.</p>
777 </div>
778
779 <div style="padding:24px 28px;border-left:3px solid #a78bfa;background:rgba(102,99,255,.04);border-radius:0 10px 10px 0">
780 <h3 style="margin:0 0 6px;font-size:18px;color:#fff">A conversion webhook with deduplication</h3>
781 <p style="color:#bbb;line-height:1.55;margin:0;font-size:14px">Your checkout retries. Stripe's webhook retries. Affiliates submit refunds 30 days later. Your dedup key has to survive all three. Without dedup you pay out the same conversion twice.</p>
782 </div>
783
784 <div style="padding:24px 28px;border-left:3px solid #a78bfa;background:rgba(102,99,255,.04);border-radius:0 10px 10px 0">
785 <h3 style="margin:0 0 6px;font-size:18px;color:#fff">Last-click attribution within an N-day window</h3>
786 <p style="color:#bbb;line-height:1.55;margin:0;font-size:14px">Two affiliates link the same visitor. Visitor buys. Who gets paid? The one with the most recent click within the program's window &mdash; and you'd better have an index on <code>(visitor_token, occurred_at)</code> or every conversion does a table scan.</p>
787 </div>
788
789 <div style="padding:24px 28px;border-left:3px solid #a78bfa;background:rgba(102,99,255,.04);border-radius:0 10px 10px 0">
790 <h3 style="margin:0 0 6px;font-size:18px;color:#fff">An affiliate dashboard with their own stats</h3>
791 <p style="color:#bbb;line-height:1.55;margin:0;font-size:14px">Affiliates want to see clicks, conversions, earnings, payout status. You'll build it three times before they're satisfied. We've already built it twice.</p>
792 </div>
793
794 <div style="padding:24px 28px;border-left:3px solid #a78bfa;background:rgba(102,99,255,.04);border-radius:0 10px 10px 0">
795 <h3 style="margin:0 0 6px;font-size:18px;color:#fff">A payout pipeline that ties to Stripe Connect</h3>
796 <p style="color:#bbb;line-height:1.55;margin:0;font-size:14px">Approving conversions, batching them, kicking off transfers, reconciling failed payouts, surfacing the failure to the affiliate so they update their account. Six weeks. Minimum.</p>
797 </div>
798
799 <div style="padding:24px 28px;border-left:3px solid #a78bfa;background:rgba(102,99,255,.04);border-radius:0 10px 10px 0">
800 <h3 style="margin:0 0 6px;font-size:18px;color:#fff">All the tax + compliance work</h3>
801 <p style="color:#bbb;line-height:1.55;margin:0;font-size:14px">1099-K thresholds, W-9 collection, GDPR-compliant cookie disclosure, the affiliate terms-of-service that protects you when one of them spam-blasts your URL. None of this ships product.</p>
802 </div>
803
804 <div style="padding:24px 28px;border-left:3px solid #a78bfa;background:rgba(102,99,255,.04);border-radius:0 10px 10px 0">
805 <h3 style="margin:0 0 6px;font-size:18px;color:#fff">Fraud detection &amp; reviewer tooling</h3>
806 <p style="color:#bbb;line-height:1.55;margin:0;font-size:14px">Cookie stuffers, self-referrers, velocity bots, duplicate-order resubmissions. The patterns mutate constantly. Real-time scanning + a reviewer UI that explains <em>why</em> each flag fired is a six-month engineering effort on its own &mdash; assuming you have the data to learn from.</p>
807 </div>
808
809 </div>
810
811 <div style="margin-top:48px;padding:32px;background:linear-gradient(135deg,rgba(102,99,255,.10),rgba(167,139,250,.06));border:1px solid rgba(167,139,250,.25);border-radius:14px;text-align:center">
812 <h2 style="margin:0 0 10px;font-size:24px;letter-spacing:-.01em">Or skip all that.</h2>
813 <p style="color:#bbb;margin:0 0 22px;max-width:480px;margin-left:auto;margin-right:auto">Sign up, create a program, share your tracking link. We handle the rest.</p>
814 <a href="/signup.cgi" class="btn btn-primary btn-lg">Start free trial</a>
815 </div>
816</div>
817HTML
818
819 $wrap->render({
820 userinfo => $userinfo,
821 title => 'Why AffSoft',
822 body => $body,
823 });
824}
Keyboard: j next diff k previous diff g top G bottom r restore c compile-check ? help