Skip to content

Status note (2026-09-25): Dated implementation and sandbox evidence. Do not infer payment settlement or production behavior from creation/retrieval tests; verify current backend source and provider evidence.

Campaign invoice fee policy — implementation results ​

TL;DR: what was actually built and sandbox-tested for invoice fees as of 2026-09-15. An evidence checkpoint, not live status — payment/fee/net settlement still awaited checkout completion at the time of writing.

Date: 2026-09-15. Implementation is local on codex/invoice-fee-handling in both repositories. Sandbox credentials subsequently became available: both fee-mode invoices have now been created and retrieved through the canonical flow. Payment/fee/net validation is awaiting checkout completion. The deferred-test sections below describe the earlier checkpoint; see the latest sandbox evidence at the end.

Implementation ​

BloxClips policyWhop requestCampaign base price
ABSORBcharge_buyer_fee: falseUnchanged
CHARGE_BUYERcharge_buyer_fee: trueUnchanged

The owner/admin API requires an explicit fee choice. Initial and top-up dialogs expose both choices; retries retain the original payload and reject policy changes under the same request identity. The canonical adapter sends one budget line and the same plan price. It creates no percentage, gross-up, or fee line. CHARGE_BUYER enables Whop's buyer-fee surcharge; it does not promise that every actual merchant/provider fee is passed through. Public invoice payment links no longer require an upfront fee quote.

The canonical flow remains: CampaignInvoice → verified CampaignFundingReceipt → CampaignFundingAllocation → CampaignFundingEntry / payout journal. The retired duplicate invoice-intent writer remains retired.

Corrected ABSORB accounting ​

The provider-mock integration test proves:

FactAmount
Campaign purchase$100
Actual provider receipt$97
Explicit BloxClips cost (providerCostAmount)$3
Campaign funding allocation / journal entitlement$100

Receipt cash plus the explicit contribution equals purchased entitlement. Repeated reconciliation produces exactly one funding entry and one balanced EXTERNAL → AVAILABLE journal entry. This is the existing campaign conservation journal, not a provider bank balance. Provider liquidity checks remain unchanged.

Both modes preserve the purchased budget. CHARGE_BUYER does not imply or predict a guaranteed merchant net or complete provider-fee reimbursement. The observed base-to-net difference is recorded separately from the actual provider fee records; no fee rate is inferred.

Payment retrieval collects all pages of Whop fee evidence (amount, currency, name, type). Lookup failure is retained as unknown, blocks funding recognition, and can be retried without resending the invoice. Payment total, customer charge, fees, and net remain distinct evidence.

Sandbox buyer-fee finding ​

Sandbox evidence established that Whop's native buyer-fee setting is a surcharge, not an exact pass-through guarantee. On a USD 100.00 sandbox invoice, the buyer-fee-enabled checkout charged USD 105.00 and recorded USD 5.37 of actual provider fees, leaving USD 99.63 net. The equivalent buyer-fee-disabled checkout charged USD 100.00, recorded the same USD 5.37 of actual provider fees, and left USD 94.63 net. The USD 5.00 buyer surcharge offset most, but not all, of the actual fees. These results are evidence for that payment configuration only; BloxClips does not hardcode or predict them.

For sandbox payment pay_oLJyWTGuaIunj6, payments.listFees returned all five fee records and their USD 0.43 total: fixed processing 0.30, Radar 0.07, percentage processing 0.03, cross-border 0.02, and orchestration 0.01. Its payment record reported USD 1.05 charged, USD 1.00 creator-visible total, and USD 0.62 after fees. The installed SDK's paginated fee iterator retrieved the complete set with a two-item page size. This validates post-payment evidence collection, not pre-payment fee prediction.

Schema ​

No migration. The existing database-protected immutable CampaignInvoice.feeQuoteEvidence snapshot stores { version: 1, feeHandling }. Existing CampaignFundingEntry.providerCostAmount and receipt evidence represent the BloxClips contribution. Historical quoted invoices retain their original contract.

Files changed ​

Backend:

  • src/utils/campaignFunding/{domain,service,whopProvider,accounting,receiptFunding}.ts
  • src/utils/payoutAccounting/sourceFunding.ts
  • src/api/routes/{admin,campaignInvoicePublic}.ts
  • Tests: campaignFunding domain/service integration, provider and receiptFunding unit tests; admin/public invoice routes; payout authority and canonical top-up integration.
  • docs/campaign-invoice-fees.md, docs/whop-integration.md, and six docs/payout-e2e-readiness/*.md documents.

Frontend:

  • features/admin/campaign-management/types/campaignInvoices.ts
  • surfaces/content-rewards/screens/admin/campaign-management/components/CampaignInvoiceDialog.tsx
  • surfaces/content-rewards/screens/admin/campaign-management/components/CampaignInvoiceFeeBreakdown.tsx
  • surfaces/content-rewards/screens/invoice/PublicCampaignInvoiceScreen.tsx
  • tests/campaign-invoice-api.test.tsx
  • tests/campaign-invoice-dialog.test.tsx

Automated validation ​

Commands executed in their respective Treehouse worktrees. Integration databases are task-created loopback PostgreSQL databases with the repository's existing migrations.

Backend:

sh
env CAMPAIGN_FUNDING_TEST_DATABASE_URL=postgresql://kirbysmashyeet@127.0.0.1:55432/invoice_fees_final_test npm run test:campaign-funding
# 52 passed, 0 failed, 0 skipped; exit 0

npm test -- src/utils/campaignFunding/whopProvider.test.ts src/utils/campaignFunding/receiptFunding.test.ts
# 9 passed, 0 failed, 0 skipped; exit 0

env TEST_AUTHORITY_DATABASE_URL=postgresql://kirbysmashyeet@127.0.0.1:55432/invoice_fees_complete_authority_test npm run test:authority
# 38 passed, 0 failed, 0 skipped; exit 0

npm run build
# Exit 0

The first complete authority run had 37 passes and one stale schema-target fixture failure (the fixture pinned an older migration set). The test now derives its expected migration set from repository migration directories; the production preflight guard is unchanged.

Frontend:

sh
env DEBUG_PRINT_LIMIT=600 node --import tsx --test tests/campaign-invoice-api.test.tsx tests/campaign-invoice-dialog.test.tsx
# 23 passed, 0 failed, 0 skipped; exit 0

npx tsc --noEmit
# Exit 0

git diff --check passes in both repositories. Scoped searches found no 2.7, gross-up implementation, or removed fee-quote resolver in canonical invoice runtime, and no guessed percentages/amounts in the invoice screens. Historical quote display/validation remains only for existing records.

Sandbox — absorb fees ​

Not executed. The configured key returned HTTP 401, “Authentication failed,” from a read-only request to sandbox-api.whop.com/api/v1/invoices. The owner then explicitly deferred sandbox testing. No invoice was sent.

Campaign base price, checkout total, provider payment total/ID, fee records, net, entitlement, and journal result: not available. Intended flag for the future test: false; not a claim about a created invoice.

Sandbox — charge buyer ​

Not executed for the same reason. Campaign base price, checkout total, provider payment total/ID, buyer fee, fee records, net, entitlement, and journal result: not available. Intended flag: true. No result comparison is possible yet.

Earlier $10 → $9.13 investigation ​

No identified payment ID or accessible sandbox fee evidence. No fee type, amount breakdown, or rate has been inferred. The $0.87 difference remains unexplained pending retrieval of that specific payment and its fee records.

Remaining blockers / deferred work ​

Live invoice and payout E2E evidence is deferred until a sandbox API key and matching sandbox company ID are configured with WHOP_ENVIRONMENT=sandbox; do not substitute production credentials. A test-payer email and the earlier payment ID will support the requested two-mode test and historical investigation.

No unknown invoice fee-percentage/quote blocker remains. Other runtime payout authority, recipient, transfer, and liquidity readiness have not been re-certified against a live sandbox in this task; local tests are not evidence of live readiness.

Workspace handoff ​

All repository changes were made through the Treehouse skill in isolated worktrees, never primary checkouts. Both primary checkouts were confirmed clean.

  • Backend commit: edc2888 on codex/invoice-fee-handling (based on origin/dev). Clean backend lease returned through the harness.
  • Frontend commit: 37bcd20 on codex/invoice-fee-handling (based on origin/dev). No tracked changes remain. The pre-existing untracked AGENTS.md and CLAUDE.md are untouched and prevent a clean return; explicitly handing off its retained lease f22a1b389fbf603cca9611be6c00696a at /home/kirbysmashyeet/.treehouse/BloxClips-frontend-207dad/1/BloxClips-frontend.
  • No push, merge, deployment, or real invoice/payment operation was performed.
  • Task-created local PostgreSQL data is retained at /tmp/bloxclips-invoice-fees.xLZ8h6/data; it contains mock integration evidence, not sandbox payment evidence.

Latest sandbox evidence — 2026-09-15 ​

The owner supplied a sandbox invoice recipient and requested focusing on these invoices, excluding the earlier $10 payment (a different sandbox business/app/account).

Sandbox invoice and payment list access returned HTTP 200. Initial lists were empty. The canonical sendCampaignInvoice service created these invoices in the real Whop sandbox, backed by a separate local database, invoice_fees_live_sandbox on 127.0.0.1:55432. No production database or provider host was used.

EvidenceABSORBCHARGE_BUYER
Campaign ID (local)12
CampaignInvoice ID401e2caf-751f-4262-982d-e8c7b5265a1e44a7372d-cf4b-4701-a411-1cd0154ef1c0
Whop invoice IDinv_XhU2B00wCD1WOSinv_KynViGaigSYQYG
Whop plan IDplan_39AylIbJjYdXsplan_qNnzfk7NGnYuP
Campaign base / provider budget lineUSD 1.00USD 1.00
Retrieved charge_buyer_feefalsetrue
Collection methodsend_invoicesend_invoice
Retrieved invoice statusopenopen
Payment IDnullnull
Checkout totalNot observedNot observed
Provider payment total / fee records / netNot available before paymentNot available before payment
Purchased budget on invoiceUSD 1.00USD 1.00
Verified receipt / allocation count0 / 00 / 0
Journal fundingNone; awaiting verified paymentNone; awaiting verified payment

Each invoice has one provider budget line, quantity 1, unit price 1, total 1. Canonical request retries returned the same invoice with exactly one create attempt each. A changed policy under each existing idempotent request was rejected. Canonical reconciliation of both open invoices completed without an error and without fabricating a receipt, allocation, or verified status.

Whop accepted send_invoice, but its response does not prove email delivery. Payment links were provided directly to the owner. A read-only checkout inspection could not run because the installed Playwright package has no matching browser executable; no checkout total was inferred and no payment was submitted.

Backend lease a3e081258f51dc64875bf65331fc6db0 is explicitly handed off at /home/kirbysmashyeet/.treehouse/Bloxclips-backend-326cdd/1/Bloxclips-backend, on the committed fee-policy branch, with no tracked changes. The local database and lease are retained for reconciliation after payment. Its credentials remain in the ignored .env, never copied into this report.