Every May 1 through May 18 ticket sale on the workbook ties to a specific Stripe charge, that charge ties to a specific Stripe payout, and that payout ties to a specific Southern First Bank deposit. Eleven deposits, eleven matches, no residual.
The Whoop Daily Sales Report is the canonical year-to-date ticket-sales ledger that feeds QuickBooks. Sheet 26 holds one row per money event (a card sale, an installment charge, a refund, a sponsor booking, a comp). Column T marks rows already posted to QB.
Rows 2 through 1425 (January 1 through April 30) were already reconciled by finance before this session and are unchanged at the value level. Rows 1426 through 1873 are the May 1 to May 18 11:42 ET append. New columns were added to make the file self-reconciling against the bank.
| Column | What it is |
|---|---|
| A to U | Existing columns. Sales, fees, classification routing. Unchanged structure. |
| V | NEW. Stripe Charge ID (ch_xxx) for every row that has a Vivenu transaction linkage. 572 rows populated. |
| W | NEW. Stripe Payout ID (po_xxx) that the charge settled into. 511 rows populated. |
| X | NEW. Bank Deposit Date for that payout (Stripe effective date + 1 business day). |
| Measure | Existing (rows 2-1425) | May (rows 1426-1873, 446 active) | Grand total |
|---|---|---|---|
| Amount (C) | $277,027.10 | $90,008.31 | $367,035.41 |
| Stripe fee (D) | $8,418.34 | $1,746.48 | $10,164.82 |
| Settled (E) | $268,545.73 | $88,261.83 | $356,807.56 |
| Vivenu fee (G) | $14,741.79 | $3,775.14 | $18,516.93 |
| Mauldin pass-through (H) | $22,807.50 | $4,640.00 | $27,447.50 |
Each row is bucketed by the actual Vivenu ticket category on the Accounting Transactions export. Untagged rows are everything that doesn’t fit a single bucket (single match, group, family pack, Summer of Soccer, Clemson, in-house, installment, refund).
| Bucket | Rows | Settled (E) | Routes to |
|---|---|---|---|
| Parking (season parking pass + single-match parking) | 52 | $7,282.74 | N (Parking) |
| Full Season ticket buys (Full Season, Half Season, Suite) | 40 | $10,338.09 | O (Full Season) |
| Sponsor | 7 | $34,260.00 | R (Sponsor / Reimb) |
| Untagged (single match, group, family pack, Summer of Soccer, Clemson, installment, refund) | 348 | $36,381.00 | — |
| Total May rows | 447 (1 cleared) | $88,261.83 |
The Stripe Itemized Payout Reconciliation export tags every charge with the specific payout (po_xxx) it settled into. That collapses the prior 2-business-day-lag guesswork into an exact answer. Stripe releases payouts in the evening of a business day; the bank shows them arriving the next business day. The 11 May deposits map cleanly onto 11 Stripe payouts.
| Bank arrival | Stripe payout ID | Charges | Stripe net | Bank deposit | Variance |
|---|---|---|---|---|---|
| Fri, May 1 | po_1TS5GOEiGAGag7IGaZtslLop | 3 | $537.04 | $537.04 | $0.00 |
| Mon, May 4 | po_1TTAQcEiGAGag7IGhOPSB9V9 | 9 | $2,988.81 | $2,988.81 | $0.00 |
| Tue, May 5 | po_1TTXBBEiGAGag7IG3d8yCHLX | 14 | $1,585.84 | $1,585.84 | $0.00 |
| Wed, May 6 | po_1TTu2wEiGAGag7IGnM2xh7Yn | 31 | $3,129.96 | $3,129.96 | $0.00 |
| Thu, May 7 | po_1TUFRPEiGAGag7IGmjS7GKaV | 19 | $3,020.79 | $3,020.79 | $0.00 |
| Fri, May 8 | po_1TUchKEiGAGag7IGBux0fp99 | 24 | $4,380.29 | $4,380.29 | $0.00 |
| Mon, May 11 | po_1TVhx3EiGAGag7IGLg453bqm | 31 | $6,015.03 | $6,015.03 | $0.00 |
| Tue, May 12 | po_1TW4W1EiGAGag7IGUsThPiJa | 48 | $3,958.03 | $3,958.03 | $0.00 |
| Wed, May 13 | po_1TWQZ7EiGAGag7IGh4N665Zd | 119 | $9,515.36 | $9,515.36 | $0.00 |
| Thu, May 14 | po_1TWnXlEiGAGag7IGNvhylsMe | 9 | $6,137.21 | $6,137.21 | $0.00 |
| Fri, May 15 | po_1TX9hpEiGAGag7IGb10cZTbg | 13 | $2,296.87 | $2,296.87 | $0.00 |
| Total | 320 | $43,565.23 | $43,565.23 | $0.00 |
The 11 May bank deposits totaling $43,565.23 exactly equal the sum of the 11 Stripe payouts containing the workbook's May charges. Variance: $0.00. Each Whoop row in column W is now tagged with the specific po_xxx it settled into, and column X holds the bank arrival date.
Each May sale moves through four systems. The Whoop row joins all four.
The Whoop May sales total ($90,008.31) is larger than the deposits ($43,565.23) for three structural reasons:
| Item | May value | Effect on deposits |
|---|---|---|
| Card sales hitting Stripe in May | $50,583.13 | Net to deposits |
| Sponsor bookings (paymentMethod = Sponsorship Payment) | $34,260.00 | None. Internal booking, not a Stripe charge. |
| Free comps (paymentMethod = none) | $5,165.18 | None. Internal, not a charge. |
| Refunds (negative rows) | −$297.50 | Netted inside the original deposit; Stripe keeps its original fee. |
| Date-range overlap (Stripe charges 4/29 to 4/30 settle into 5/1 to 5/4 deposits) | +~$2,400 | Adds to deposits, doesn't show in May Whoop sales. |
| May 1 to May 15 deposits | $43,565.23 | Matches Stripe-side payouts exactly. |
In short: Whoop is sales-side (every booking that happened, regardless of how the customer paid). Bank deposits are cash-side (only money that actually moved through Stripe). The Stripe payout reconciliation is the join.
These are the bugs that caused wrong numbers in earlier versions. Documenting so we catch them next time.
The Mauldin Facility Fee column was being populated with the customer-paid outer fee (outerCharge on the Vivenu transaction). That's the total customer-facing service fee, which on parking equals the Parking Processing Fee, not Mauldin. Result: 52 parking rows carried $28 Mauldin each when the truth is $0.
Fix: read only the line items whose name contains "Mauldin Facility Fee" from the Accounting Transactions export. Anything else is processing fee.
898 historical rows had Vivenu Fee equal to the per-ticket external fee schedule ($5 single, $2.50 group) rather than the actual innerCharge Triumph pays Vivenu. Over-stated platform cost by $3,085 across the year.
Fix: G = innerCharge from Vivenu /transactions. Sean's rule.
The Vivenu transactions export uses UTC (Z suffix). The Vivenu Accounting Transactions export uses Germany local time (+02:00). Same instant, different representation. Stripping the timezone without converting silently shifted accounting timestamps 2 hours forward and dropped three 5/18 morning transactions out of scope.
Fix: parse with datetime.fromisoformat, convert to UTC via astimezone(timezone.utc), then subtract 4 hours for ET.
The Accounting Transactions export has both an amount column and a totalPrice column. amount is the quantity (e.g. 4 tickets), totalPrice is the dollar value. Treating amount as dollars under-counts by orders of magnitude on multi-ticket rows.
Fix: always sum totalPrice, never amount. netPrice is also booby-trapped: per-unit on ticket lines, total on fee lines.
One Stripe charge can pay for several Vivenu transactions (Whitney Marrero bought 7 separate tickets in one $210 cart, becoming 7 transactions with the same Stripe charge ID). Putting the full charge total on one row and the per-ticket realPrice on the rest inflates the file. Putting the per-ticket realPrice on all rows is correct.
Fix: Amount column always equals realPrice on the transaction, not the Stripe charge amount.
A paymentplan transaction's psp field stores a payment-plan ID (pp_xxx) rather than a Stripe charge ID (ch_xxx). Joining payments to transactions purely by the Stripe ID misses the first installment.
Fix: when the txn payment method is paymentplan, match the payment to the transaction by Vivenu ObjectId timestamp prefix (the first 8 hex characters are the unix timestamp of creation, identical for objects created in the same Vivenu operation).
Vivenu's /transactions ledger records the original plan booking only. Subsequent installment charges live in /payments. Naively pulling /transactions misses them entirely.
Fix: union /transactions COMPLETE rows with /payments rows that have no May /transactions match. In May, 40 such installments were charged for plans booked earlier in the year. Per the rule, subsequent installments carry $0 Vivenu fee and $0 Mauldin (all plan fees were booked on the first installment).
The commission-side linker had a ±1 day tolerance on expected installment dates. Installments that drifted past 1 day (Bradley Durham 4/22, Justin Nobles 4/24) were silently dropped as "unmatched payment."
Fix: anchor on Stripe Card Name (the authoritative buyer identity) rather than date arithmetic. Order all SUCCEEDED payments under the parent plan by createdAt for installment numbering.
Stripe's automatic_payout_effective_at is the time Stripe RELEASED the payout to ACH (evening of business day D). The bank shows the deposit arriving the next business day (D+1). Lining them up by date directly looks off by one and produces a $24 "variance" that does not exist.
Fix: bank arrival = effective_at + 1 business day (skipping weekends).
Every May Whoop row is cross-checked against Vivenu /transactions, Vivenu /accounting, Vivenu /payments, and the Stripe payments export. Amount, Stripe fee, Settled, Vivenu fee, Mauldin, and refund amounts all tie to the source.
446 / 446 rows pass on the audit.
The Itemized Payout Reconciliation export tags every charge with its specific payout ID. Joining that into the Whoop file gives every row a payout and a bank arrival date. The 11 May deposits reconcile to $0.00 variance.
11 / 11 deposits, $0.00 variance.
The Mauldin column now sums the "Mauldin Facility Fee" line items from the Accounting Transactions export, never customer-paid outer fees. Parking rows correctly carry $0 Mauldin. 6/3+ single-match rows carry $2 per ticket. Season ticket plans carry $26 to $30 per package.
May Mauldin: $4,640. File-total Mauldin: $27,447.50.
898 historical rows were re-set to the actual Vivenu platform cut (innerCharge on the transaction). Net of corrections, the file's Vivenu Fee total dropped from $21,605 to $18,520. Aligns with Sean's documented methodology.
898 corrections, $3,085 movement.
Column V = Stripe Charge ID. Column W = Stripe Payout ID. Column X = Bank Deposit Date. Finance can pivot any sub-total on these and get the bank-side answer instantly. No more guessing which charges settled into which deposit.
572 rows tagged with charge ID; 511 of those further tagged with payout + bank date.
40 prior-plan installments charged in May carry $0 Vivenu fee and $0 Mauldin per the rule (all plan-level fees were booked on the original installment). First installments still carry the full plan fees.
$6,512 of installment revenue captured correctly.
Madison Wilson's $9,030 GE Vernova sponsorship carries $1,290 Mauldin pass-through ($30 x 43 P5 sponsor season tickets). Old convention zeroed sponsor Mauldin. Per the rule "season ticket = $2/match Mauldin" applies regardless of buyer type. Sponsor R column captures net of Mauldin pass-through.
7 May sponsor rows, $34,260 gross, $31,950 net to R column.
The two May refunds (Stacey Staggers 5/6 −$171.50, Elizabeth Melvin 5/8 −$126.00) appear as negative-amount rows. They reduce the original payout net; the Stripe fee on the original charge is not refunded by Stripe.
2 refund rows, −$297.50 combined.
Same convention as the pre-existing rows. Mark each row with Yes in column T as it posts.
| Column | QB GL account / handling |
|---|---|
| C Amount | The gross figure that was charged to the customer (or the booking value for sponsor/comp). |
| D Stripe CC Fee | Posts to Stripe fees expense. $0 on sponsor and comp rows (no Stripe charge). |
| E Settled | C minus D. The amount Stripe sends to the bank before payout-level adjustments. |
| G Vivenu Fee | Posts to Vivenu platform expense. Sourced from innerCharge. |
| H Mauldin Fee | Pass-through to Mauldin facility payable. Customer paid it inside the gross; Triumph remits to Mauldin. Sourced from the "Mauldin Facility Fee" accounting line item. |
| N Parking | Parking revenue. Subject to its own commission rate (2%) per the Commission Report. |
| O Full Season (M) | Full Season ticket buys only (Full Season, Half Season, Suite). Single-match and group tickets are intentionally left untagged. |
| R Sponsor / Reimb | Sponsor revenue, net of Mauldin pass-through (R = E minus H on sponsor rows). |
| V Stripe Charge ID | For reconciliation. ch_xxx. Click into the Stripe Dashboard for the original charge. |
| W Payout ID | For reconciliation. po_xxx. The Stripe payout this row settled into. |
| X Bank Deposit Date | The day this row's payout arrived at Southern First Bank ····5948. |
| T Posted in QB | "Yes" once the row is in QB. Reconciliation lookups can filter on this. |
Pick a row. Read column W to get the payout ID. Find that payout in Stripe Dashboard or in the Itemized Payout Reconciliation export. Sum all its charges; that's the deposit amount that arrived on column X's date. Reconciles to the cent.
May 2026 sales: Closed Bank deposits: Closed Variance: $0.00.