Why We Killed Hold Windows in Our Affiliate Marketplace

Published: (May 1, 2026 at 09:35 PM EDT)
3 min read
Source: Dev.to

Source: Dev.to

Overview

We spent weeks building a settlement system for our affiliate marketplace—hold windows, clawbacks, carry‑forwards, commission auto‑approval schedulers, the works. Then we deleted it all.

The idea was straightforward: when an affiliate drives a conversion, don’t pay them immediately. Hold the commission for X days. If the customer refunds, claw back the commission. If there’s a remainder below the payout threshold, carry it forward to the next month. Sounds reasonable, right? Every major affiliate network does something like this.

Implementation we built

  • Hold windows — configurable per campaign (7, 14, 30 days)
  • Clawback logic — refunds during the hold period reduce the affiliate’s balance
  • Carry‑forwards — sub‑threshold amounts roll to the next settlement period
  • Auto‑approval scheduler — commissions move from HELD → APPROVED after the hold window

Why we scrapped it

Legal review flagged the feature as a regulatory risk:

  • Money‑transmission concerns – holding and releasing funds on a schedule can be considered money transmission in some jurisdictions.
  • Dispute‑resolution requirements – clawbacks need a formal dispute process, not just an automatic deduction.
  • Accounting complexity – carry‑forwards create accrued liabilities that require proper bookkeeping.
  • Tax reporting – uncertainty about when the income is earned (conversion, hold expiry, or payout).

We’re a URL shortener that added an affiliate marketplace, not a payment processor. Building the compliance infrastructure for hold windows would have cost more than the feature was worth.

Deleted assets

// CommissionAutoApprovalScheduler.java (deleted)
  • holdWindowDays field (removed from campaigns)
  • clawbackAmount, previousCarryForward (removed from settlements)
  • HELD commission status (removed)

What we replaced it with

  • Firm offers – brands mark campaigns as non‑negotiable; publishers accept the commission as‑is.
  • Immediate settlement – conversions are confirmed by Stripe webhooks. When Stripe says the charge succeeded, the commission is earned.
  • Monthly payouts – simple monthly settlement with no holds. If there’s a refund, the brand absorbs it (they can adjust their commission rates accordingly).

The simplification freed up time for features that actually matter:

  • Partnership lifecycle – pause, resume, terminate partnerships with full event tracking.
  • Multi‑channel notifications – email, in‑app, and push notifications for partnership events.
  • Campaign budgets and expiry – brands set a maximum spend and end date; campaigns auto‑pause when limits are hit.
  • Firm offers – skip the negotiation dance when the brand knows what it wants to pay.

Metrics

MetricBeforeAfter
Settlement‑related DB tables52
Commission statuses6 (PENDING, HELD, APPROVED, CLAWED_BACK, PAID, FAILED)3 (PENDING, APPROVED, PAID)
Settlement logic (lines)~800~200
Legal questionsManyFew

Takeaways

  • Legal review before building – ask “can we hold affiliate funds?” before writing a single line of code.
  • Complexity is a liability – every line of settlement logic is a potential bug, legal issue, and support ticket. Less code = less risk.
  • Copy the leader carefully – “Amazon Associates holds windows” doesn’t mean you should; Amazon has a legal team.
  • Simpler products attract more users – publishers want to drive traffic and get paid, not learn about hold windows and carry‑forwards.
  • KISS isn’t lazy, it’s strategic – deleting working code can be the highest‑ROI engineering decision.

Ever deleted a feature you spent weeks building? What was the hardest “kill your darlings” moment in your product? Share below.

Building jo4.io – a URL shortener with an affiliate marketplace that pays publishers without the complexity.

0 views
Back to Blog

Related posts

Read more »