Pricing Consistency

Server-side fee calculation and validation for offers

Pricing Formula

Every offer has three price fields, all computed server-side:

FieldFormulaDescription
offerAmountCentInput from buyerWhat the talent receives
zoolyFeeCentMath.round(offerAmountCent × 0.20)20% Zooly platform fee
totalBrandPriceCentofferAmountCent + zoolyFeeCentWhat the brand pays

The client sends only offerAmountCent. The server computes and stores the other two values. Client-sent fee fields are ignored.

Where Fees Are Computed

On Offer Creation

createOffer() in packages/db/src/access/offers.ts computes zoolyFeeCent and totalBrandPriceCent from the provided offerAmountCent before inserting the row.

On Counter-Offers

When a counter-offer is submitted with a new counterAmountCent, updateOfferStatus() in packages/db/src/access/offers.ts recalculates the fees if the offer re-enters ADMIN_REVIEW status.

On Offer Submission

POST /api/offers/submit in apps/zooly-app/app/api/offers/submit/route.ts validates that offerAmountCent is a finite positive number. Any client-sent zoolyFeeCent or totalBrandPriceCent fields are stripped before reaching createOffer.

Payment Validation

When a payment intent is created for an offer, getOfferProduct() in packages/srv-stripe-payment/src/getProductByPayForId.ts performs a consistency check:

  1. Loads the offer by ID
  2. Asserts the stored zoolyFeeCent matches Math.round(offerAmountCent × 0.20)
  3. Asserts the stored totalBrandPriceCent matches offerAmountCent + zoolyFeeCent
  4. If either assertion fails, the payment intent creation is rejected

This prevents price drift if the fee percentage changes or if stored values are manually edited.

Price Data for Stripe

The computePriceData(amountCent, platformFeeCent) function in packages/srv-stripe-payment/src/getProductByPayForId.ts produces the full ProductPriceData breakdown used by Stripe:

  • Total charge amount (what brand pays)
  • Stripe processing fee (calculated via calculateStripeFees from @zooly/util)
  • Platform fee (the 20% Zooly fee)
  • Talent gross share (total minus Stripe fee minus platform fee)

This function is exported from @zooly/srv-stripe-payment for use in escrow release and other payment flows.

Key Files

FileRole
packages/db/src/access/offers.tsFee computation in createOffer and updateOfferStatus
apps/zooly-app/app/api/offers/submit/route.tsInput validation, strips client fee fields
packages/srv-stripe-payment/src/getProductByPayForId.tsPayment-time consistency assertion, computePriceData