Skip to content

Implementation handoff ​

This plan is for a later implementation agent. It is dependency-ordered and intentionally starts with provider proof and accounting invariants, not a Whop call. Re-read the repository and current Whop docs at implementation time; the research snapshot is 2026-09-01.

Non-negotiable implementation rules ​

  • Do not add Whop dispatch to utils/rails/dispatcher.ts or either current payout send route.
  • Do not let metric-scraper calculate earnings, choose rates, deplete budgets, or call Whop.
  • Do not make a provider call inside a Prisma/Postgres transaction.
  • Do not automatically retry a timeout with a new idempotency key.
  • Do not trust WhopIdentity as a payment mapping without the new verification flow.
  • Do not use floats for new money/rate fields.
  • Do not hard-delete a financially referenced campaign, submission, journal entry, payout item, provider operation, webhook, or audit event.
  • Existing payout data is development-only and need not migrate, but preserve it until the cutover phase explicitly retires its code paths.

Phase 0 — freeze decisions and prove provider capability ​

Current execution status and the copy-ready provider request are maintained in 08-phase-0-execution.md.

Work ​

  1. Owners answer 07-open-decisions.md and record a signed-off policy version.
  2. Whop answers the provider questions in 02-whop-money-api-research.md, including direct user_… capability and exact scopes. The source is not open for redesign: it must resolve to BloxClips' owner-confirmed Whop business balance.
  3. Run the read-only then minimal sandbox sequence in 05-sandbox-validation.md. Preserve redacted evidence.
  4. Confirm legal/tax owner requirements for automatic balance credits. Do not assume the existing external-payout tax gate carries over unchanged.
  5. Select and record the API pin; as of research it is 2026-08-31. Recheck the changelog and installed SDK compatibility before coding.

Acceptance criteria/tests ​

  • Sandbox host/key/origin/recipient are separately identified; the origin is demonstrably the sandbox BloxClips business balance, and no production secret/ID is used.
  • Account identity, balance fields, direct recipient, one minimal transfer, same-key replay, retrieval/list, and signed webhook each have pass/fail evidence.
  • Exact current permissions and BloxClips account enablement are documented by dashboard evidence or Whop support.
  • Every owner choice is translated into named constants/policy fields and expected examples.

Gate ​

Do not start Phase 1 until the product policy is frozen enough to define schema units and the primary/fallback destination type is known. If sandbox ledger transfer is unavailable, Phase 1 may proceed only as provider-neutral local accounting work; no Whop adapter/dispatch work may be represented as validated.

Phase 1 — add exact money primitives and append-only schema ​

Likely files/modules ​

  • Bloxclips-backend/prisma/schema.prisma
  • new migration under Bloxclips-backend/prisma/migrations/<timestamp>_add_earning_and_payout_ledger/
  • new Bloxclips-backend/src/domain/money.ts
  • new Bloxclips-backend/src/domain/earnings/ modules for policy types, state transitions, and invariants
  • new Bloxclips-backend/src/domain/payouts/ modules for state transitions and audit commands
  • backend test helpers/fixtures alongside those modules

Work ​

  1. Implement integer micro-USD parsing/formatting/arithmetic with no implicit number conversion. Define sign conventions and cumulative-target rounding.
  2. Add policy/version, earning/state, campaign-budget, payout-run/item/allocation, provider-operation/attempt, webhook inbox, payment identity, and financial audit models from the target architecture.
  3. Add database constraints/indexes: unique source keys, effective-interval protection, unique active payment identity, unique allocation, unique schedule slot, unique idempotency/provider IDs per environment, check constraints for currency/amount/state, and restricted deletes.
  4. Implement state-transition functions that reject illegal transitions and require actor/reason/correlation. The mutation and audit insert occur in one transaction.
  5. Add projection/reconciliation queries, but make journals authoritative.
  6. Leave all current payout routes and calculations unchanged during this phase; new tables receive no production dispatch.

Acceptance criteria/tests ​

  • Property/table tests prove many small view deltas equal one cumulative calculation under the chosen rate segment.
  • Values at zero, one view, sub-cent, cap boundary, BigInt limit, and negative correction serialize correctly through Prisma/API DTOs.
  • Duplicate source/allocation/scheduled slot/idempotency/provider event is rejected by the database, not only application code.
  • Illegal state transitions, missing audit actor/reason, currency mismatch, and hard delete fail.
  • Sum-based invariants can be recomputed from journals with no mutable counter dependency.
  • Migration applies to a fresh dev database and rolls back in a disposable database without touching current dev payout rows.

Gate ​

Do not start Phase 2 until schema constraints, money property tests, transition tests, and fresh-database migration pass. No route may read the new projection as authoritative yet.

Phase 2 — implement rate policy and shadow accrual at the metric boundary ​

Likely files/modules ​

  • Bloxclips-backend/src/utils/tracking/scrapeJobs.ts
  • Bloxclips-backend/src/utils/tracking/runTrackingTick.ts
  • Bloxclips-backend/src/utils/campaignBudget.ts (retain old exports temporarily; route new accrual around them)
  • Bloxclips-backend/src/utils/calculateSubmissionEarnings.ts (shadow comparator only)
  • Bloxclips-backend/src/api/routes/admin.ts campaign/submission mutations
  • Bloxclips-backend/src/api/routes/adminClipperGroups.ts
  • Bloxclips-backend/src/utils/clipperGroups/domain.ts
  • Bloxclips-backend/src/utils/clipperGroups/campaignLifecycle.ts
  • new src/domain/earnings/accrueMetricDelta.ts, resolveRate.ts, correctEarning.ts, and reconciliation service
  • frontend campaign/group form/API/type files under features/admin/campaign-management/ and features/admin/clipper-groups/

Work ​

  1. Add distinct CPM/default RPM inputs with explicit per-1,000 units and currency. Add group RPM and creator/campaign override management with immutable effective versions.
  2. Enforce launch/funding/rate/cap policy and the chosen group-membership rule.
  3. In the backend ScrapeJob application transaction, lock campaign/submission, calculate accepted delta, allocate CPM budget, and post earning/budget/state/audit entries exactly once.
  4. Keep the scraper result technical. Delete no direct payout-rescrape code yet, but ensure the new journal never calls it.
  5. Implement approval, rejection, late-result, campaign-end/depletion, group auto-archive, cap, flat-fee, and correction commands.
  6. Run new accrual in shadow mode. Compare old mutable estimates only as diagnostics; differences caused by intended CPM/RPM separation or snapshots need classified explanations, not forced equality.
  7. Prevent new hard deletes when a source has financial entries; add soft-delete/archive behavior.

Acceptance criteria/tests ​

  • Rate precedence tests cover individual > group > campaign, no override, archived group, effective-time change, invalid overlaps, and RPM above CPM exception policy.
  • Budget tests cover simultaneous submissions, partial last delta, duplicate job, top-up, correction, depletion without auto-reopen, and CPM unchanged when RPM falls.
  • Lifecycle tests cover pre-approval metrics, approval catch-up, later views, rejection before/after reserve, campaign end, final grace scrape, group auto/manual archive, and late correction.
  • The same ScrapeJob applied twice produces one earning and one budget effect.
  • Two concurrent job applications cannot exceed campaign funding.
  • Shadow reports identify every discrepancy by policy category and contain no unclassified amount drift.

Gate ​

Do not start Phase 3 until accrual/budget concurrency tests pass, all shadow differences are explained, and no scraper module contains financial/provider policy.

Phase 3 — payment identity, Whop adapter, and webhook inbox with dispatch disabled ​

Likely files/modules ​

  • Bloxclips-backend/src/utils/whopClient.ts (retain chat client compatibility; introduce explicit environment/API pin)
  • new Bloxclips-backend/src/integrations/whop/payoutClient.ts
  • new Bloxclips-backend/src/integrations/whop/transferMapper.ts
  • new Bloxclips-backend/src/domain/payouts/paymentIdentity.ts
  • new route Bloxclips-backend/src/api/routes/payoutIdentity.ts
  • new money webhook route/module, separate from chat side effects, near src/api/routes/webhooks/whop.ts
  • Bloxclips-backend/src/api/index.ts for raw-body ordering/registration
  • Bloxclips-backend/.env.template for explicitly separate payout environment/base/key/origin/webhook/API-date variables
  • frontend payout identity API/types/components under BloxClips-frontend/features/payouts/

Work ​

  1. Build a money-specific SDK client factory that asserts environment/host/origin, pins API date, sets bounded timeout, disables SDK automatic retries, and never logs secrets.
  2. Implement typed adapter methods only for validated balance/recipient/create/retrieve/list operations. Map responses exhaustively; unknown status/shape is an error requiring review.
  3. Implement creator payment-identity connect/confirm/revoke/revalidate. Existing WhopIdentity may prefill a candidate but not activate it.
  4. Add webhook raw-body verification, five-minute replay check through the official helper, unique inbox insertion, account/environment/API-date validation, and async processing that retrieves current transfer state.
  5. Build an in-memory/fake Whop adapter for deterministic failure/crash tests. Keep real dispatch feature disabled.

Acceptance criteria/tests ​

  • Client refuses production hostname with sandbox mode and refuses an origin/environment mismatch.
  • No browser bundle/API response contains key, webhook secret, signature, or privileged token.
  • Identity tests cover absent/stale/duplicate/mismatch/revocation and chat mapping not being sufficient.
  • Webhook tests cover valid, tampered, stale, duplicate, out-of-order, wrong account, wrong API date, unknown event, and failed-example inconsistency followed by retrieve.
  • Adapter tests cover exact amount/currency/parties, processing/succeeded/failed, unknown fields, timeout, 409, 429, and 5xx without hidden SDK retry.

Gate ​

Do not start Phase 4 until payment identity is demonstrably consented/unique, webhook inbox is durable/idempotent, adapter contract tests match sandbox evidence, and real dispatch remains off.

Phase 4 — durable automatic reservation, dispatch, retry, and reconciliation ​

Likely files/modules ​

  • new Bloxclips-backend/src/domain/payouts/createRun.ts
  • new reservePayableEarnings.ts, dispatchProviderOperation.ts, reconcileProviderOperation.ts, and processWebhookInbox.ts
  • new Bloxclips-backend/src/utils/payouts/scheduler.ts or equivalent durable scheduler module
  • Bloxclips-backend/src/api/index.ts / src/scheduler.ts for startup registration
  • do not reuse src/utils/payouts/processRequest.ts, rescrape.ts, or utils/rails/dispatcher.ts

Work ​

  1. Add daily scheduled-slot creation under PostgreSQL advisory lock.
  2. Reserve one creator/currency item using row locks/SKIP LOCKED, unique allocations, threshold, holds, identity, negative balance, tax/legal gate, and exact sub-cent carry.
  3. Implement prepare/claim/external/result transaction boundaries with leases and attempt records.
  4. Implement the documented retry classification. Timeouts and ambiguous conflicts become UNKNOWN; reconcile before any resend.
  5. Add 15-minute open-operation, daily seven-day-window, and weekly aggregate reconciliation.
  6. Add structured metrics/logging and alerts. Real adapter remains restricted to sandbox.
  7. Provide constrained admin commands: reconcile, release known-safe retry, resolve identity/funding issue, cancel before possible send, and propose exceptional supersession. No arbitrary amount or key input.

Acceptance criteria/tests ​

  • Two schedulers create one run; two workers reserve an earning once; two dispatch calls claim one operation.
  • Crash at every boundary (before call, request accepted/response lost, response received/commit lost, webhook before response) converges to one transfer.
  • Repeated schedule execution and duplicate event delivery do not change total paid.
  • Timeout never becomes retryable solely by elapsed time; after 24 hours, create is blocked absent formal no-movement evidence.
  • Failed-then-succeeded/reversed provider states produce monotonic audit and correct local recovery state.
  • Insufficient funds, permission failure, stale identity, amount mismatch, and reconciliation mismatch alert/block correctly.
  • Every state mutation has same-transaction audit and every provider attempt has a correlation record.

Gate ​

Do not start Phase 5 until deterministic concurrency/chaos tests prove exactly-once economic effect and at-most-one semantic provider operation, and the complete sandbox validation passes with dispatch restricted to sandbox.

Phase 5 — replace creator/admin read and control surfaces ​

Backend likely files ​

  • replace behavior in Bloxclips-backend/src/api/routes/payouts.ts with ledger balance/history/identity reads; remove creator request from primary contract
  • new admin reconciliation routes rather than extending adminPayoutReview.ts
  • Bloxclips-backend/src/api/routes/admin.ts to remove legacy eligible/process exposure after cutover gate
  • Bloxclips-backend/src/api/index.ts registration

Frontend likely files ​

  • BloxClips-frontend/features/payouts/api/payouts.ts, types.ts, lib/status.ts, hooks and overview components
  • surfaces/content-rewards/screens/payouts/PayoutOverviewScreen.tsx and its balance/history/notices components
  • retire primary method UI under surfaces/.../payouts/method/ in favor of Whop identity/connect and “withdraw in Whop” guidance
  • admin payout list/detail feature APIs/types/formatters/screens/components
  • admin user detail payout action and status components
  • submission/campaign displays that currently show mutable estimates or ambiguous custom rate units

Work ​

  1. Creator API returns separately: held/estimated, payable, reserved/scheduled, paid, recovery/hold reasons, sub-cent carry, threshold, next sweep, and payment identity status.
  2. Remove “request cashout” as the normal action. Provide connect/revalidate Whop and link to Whop withdrawal after paid.
  3. Admin UI becomes reconciliation/incident visibility, not a per-creator approval/send queue. Exceptional actions reflect role and state-machine commands.
  4. Use shared backend DTO schemas/status vocabulary. Unknown states render as “needs review,” never success.
  5. Decide/refactor referral/tax presentation according to owner decision; do not silently add affiliate balance to creator content payout.

Acceptance criteria/tests ​

  • Frontend displayed totals equal backend ledger projections for fixtures including holds, carries, corrections, reservations, unknown, failed, paid, and reversed.
  • No creator request or staff send button can reach old endpoints under new mode.
  • Creator cannot access another identity/ledger or any reconcile/retry command.
  • Support/operator/finance permissions match the matrix; TOTP/step-up remains for exceptional finance commands where required.
  • Accessibility and copy distinguish credit to Whop from external withdrawal.

Gate ​

Do not start Phase 6 until contract/E2E tests pass and every creator/admin money number has one documented backend projection.

Phase 6 — shadow verification and clean development cutover ​

Work ​

  1. Deploy schema and shadow accrual with dispatch off. Run journal invariants and compare accepted sources/rate decisions/budget against manually calculated fixtures.
  2. Since existing payout data is development-only, choose a cutover timestamp and start the new ledger from a clean explicitly seeded baseline. Do not delete old rows; mark old UI/routes read-only/disabled by feature flag.
  3. Stop POST /api/payouts/request, adminPayoutReview approve/send, and admin.ts eligible/process/bulk routes. Stop processPayoutRequest startup resume and payout-time rescrapeForPayout calls.
  4. Switch authoritative balance/history reads to the new ledger.
  5. Confirm there are zero old in-flight states that could still dispatch and no process still calls legacy rails for creator earnings. Existing unrelated provider/tax code may remain isolated.

Acceptance criteria/tests ​

  • Code search and route tests prove all creator-money writes go through new domain commands.
  • No REQUESTED, SCRAPING, READY_FOR_REVIEW, AWAITING_SEND, or legacy process worker can call an external rail.
  • No new accounting reads Submission.paidOut, paidAmount, paidViewsTotal, paidAmountTotal, PayoutItem.grossAmount, or mutable rate/view totals.
  • Journal/budget/allocation/provider aggregates reconcile exactly at cutover.
  • Rollback feature flag restores old read-only UI if needed, but never re-enables both send systems concurrently.

Gate ​

Do not start Phase 7 until the old send paths are proven inert, shadow invariants remain clean for the agreed observation period, and rollback cannot activate two money movers.

Phase 7 — sandbox end-to-end rollout ​

Work ​

  1. Enable automatic scheduling and Whop dispatch only in a seeded development/staging environment pointed at sandbox.
  2. Execute every test in 05-sandbox-validation.md, plus multi-creator batching, holds, insufficient balance, unknown timeout harness, duplicate run, and webhook/reconciliation recovery.
  3. Run for at least two complete scheduled cycles with no manual database correction.
  4. Produce a go/no-go evidence report with totals: earned, budget debited, payable, reserved, provider succeeded/failed/fees, paid, carry, and differences (must be zero except explicitly modeled fees/carry).

Gate ​

Do not start Phase 8 until all sandbox and chaos acceptance tests pass, Whop reconfirms production capability/limits, finance funds the origin/buffer, security reviews secrets/webhooks/roles, and owners sign the report.

Phase 8 — controlled production activation ​

This phase requires separate explicit authorization; the current audit does not grant it.

  1. Deploy with accrual authoritative but production dispatch off.
  2. Verify that the production origin is exactly BloxClips' Whop business balance, then verify API pin, scopes, webhook delivery, available/pending/reserve fields, alerts, and dashboards through read-only checks.
  3. Enable dispatch for a tiny allowlisted cohort and a low daily aggregate cap. No synthetic/real transfer solely for testing without authorization.
  4. Reconcile each canary manually via API and balance before widening cohort/cap.
  5. Increase gradually only after scheduled observation windows and zero unexplained mismatch.
  6. Keep legacy creator rails permanently disabled; remove their code/schema only in a later cleanup migration after retention requirements are set.

Production acceptance ​

  • Every transfer links to immutable earnings, provider operation, signed event/API state, and audit.
  • Alerting/on-call runbooks have been exercised.
  • Provider and local daily totals reconcile exactly, with fees/carries separate.
  • Creators see correct Whop credit and use Whop—not BloxClips—to withdraw externally.

Rollback strategy ​

Rollback is stop-dispatch and reconcile, never “switch back to the legacy payer.”

  1. Disable creation/claim of new provider operations with a server-side kill switch; leave webhook ingestion and reconciliation running.
  2. Allow already possible/sent operations to settle or become UNKNOWN; never release their reservations or resend until provider state is known.
  3. Keep accrual/budget journals running if correct. If accrual itself is suspect, pause new accrual application while preserving ScrapeJob results for later idempotent replay.
  4. Revert frontend to read-only held/payable/history messaging; do not restore cashout/send actions.
  5. Restore application binaries only if schema is backward compatible. Do not drop new journal tables or erase audit while money is unresolved.
  6. After reconciliation, cancel only operations proven never sent, release their allocations transactionally, and document every action.
  7. Correct accounting with new entries; never edit original earnings, paid states, provider IDs, or evidence.

Exact starting instruction for the next agent ​

Begin with Phase 0 only: obtain owner decisions and a clearly isolated Whop sandbox/account-capability result. If provider validation remains unavailable, proceed only with a reviewed Phase 1 provider-neutral schema/ADR proposal—do not write a Whop transfer call or connect the existing payout flows.