Summary
Manual affiliate payout requests can pay any pending conversion without checking settles_at. The auto-payout cron correctly filters for settled conversions with .lte("settles_at", now), but POST /api/affiliates/offers/[id]/conversions/pay only checks status and commission amount before transferring funds.
Why this matters
Affiliate offers expose a settlement delay so sellers can hold commissions before payout. If the manual pay endpoint bypasses that delay, a pending conversion can be paid before the configured review/settlement window has elapsed.
Expected
The manual payout endpoint should reject conversions whose settles_at timestamp is still in the future, before looking up wallets or initiating a Lightning transfer.
Actual
Any pending conversion with a positive commission can be paid immediately through the manual payout endpoint.
Proposed fix
Select settles_at with the conversion, return a 400 response when it has not settled yet, and add route coverage proving no wallet lookup or transfer is attempted for unsettled conversions.
Related paid testing gig: https://ugig.net/gigs/4741218f-a723-46bb-82cb-6516120331ae
Summary
Manual affiliate payout requests can pay any pending conversion without checking
settles_at. The auto-payout cron correctly filters for settled conversions with.lte("settles_at", now), butPOST /api/affiliates/offers/[id]/conversions/payonly checks status and commission amount before transferring funds.Why this matters
Affiliate offers expose a settlement delay so sellers can hold commissions before payout. If the manual pay endpoint bypasses that delay, a pending conversion can be paid before the configured review/settlement window has elapsed.
Expected
The manual payout endpoint should reject conversions whose
settles_attimestamp is still in the future, before looking up wallets or initiating a Lightning transfer.Actual
Any pending conversion with a positive commission can be paid immediately through the manual payout endpoint.
Proposed fix
Select
settles_atwith the conversion, return a 400 response when it has not settled yet, and add route coverage proving no wallet lookup or transfer is attempted for unsettled conversions.Related paid testing gig: https://ugig.net/gigs/4741218f-a723-46bb-82cb-6516120331ae