Skip to main content
Testnet values — not real money. Any concrete feeRateBps, k, or bps numbers quoted on this page apply to the ADI-testnet deployment (chainId 99999) and are placeholder rates used for partner integration and load-testing — no real money flows. The formula (fee = k × P × (1 − P) × outcomeTokens) and the integration contract (market.feeTakerBps as the canonical signing input) are stable across environments.

The formula

fee = k × P × (1 − P) × outcomeTokens
  • P is the execution price, 0 < P < 1.
  • k is a period-specific coefficient.
  • outcomeTokens is the number of outcome tokens traded.
  • The curve peaks at P = 0.5 (max uncertainty) and decays to 0 at the extremes.
  • Both sides of every fill pay this fee. CTFExchange._chargeFee fires on each leg of _matchOrders / _fillFacingExchange — the same feeRateBps value the user signed into the EIP-712 Order is deducted from the asset they’re receiving (collateral on SELL, outcome tokens on BUY). Earlier docs claimed “maker fee is always 0”; that matched a transitional MVP path where signed orders carried feeRateBps = 0. As of the on-chain-fees rollout, every signed Order carries the live feeTakerBps and the contract takes the fee on both legs.

Why quadratic (not linear)?

The linear min(P, 1−P) curve (Polymarket’s default) is twice as expensive at the top of the book. For tail markets the linear curve still charges meaningful fees; the quadratic curve naturally eases to zero. Holding feeRateBps constant, the curves compare as follows (illustrative — the absolute % depends on the rate set on the market):
PLinear peakQuadratic (PS)Ratio
0.05100% of peak19%5.3× lower
0.25100% of peak75%1.33× lower
0.5100%100%1× (curves meet)
0.75100% of peak75%1.33× lower
0.95100% of peak19%5.3× lower
Effective feeRateBpsk: feeRateBps = k × 10_000. Per-wallet fee tier (and the resulting makerBps / takerBps) is available at GET /api/me/fee-tier.

Three fee surfaces — which one to use

The API exposes three fee values; partners often ask which one “actually applies.” Short answer:
SurfaceWhere it comes fromWhat it meansUse it when
market.feeTakerBpsGET /api/markets/{symbol}The per-market on-chain fee that the EIP-712 Order MUST be signed with — CTFExchange reconstructs the canonical Order with this value and verifies your signature against it. Mismatch ⇒ bad_signature.Always — for signing. This is the only one that goes into Order.feeRateBps in the signed struct.
/api/platform/fee-configPlatform period policyThe platform-level current period rate: {currentPeriod, feeMakerBps, feeTakerBps}. Same value for every wallet, set by policy. Mostly informational — surfaces the active period so partners can label fee disclosures.UI/disclosure only. Don’t use for signing — the per-market value (market.feeTakerBps) is the source of truth and may briefly differ around period boundaries until the market refreshes.
/api/me/fee-tierPer-wallet VIP tierYour effective post-discount rate: {tier, makerBps, takerBps} after VIP / volume tier discount. Lower than the platform default for tier-1+ wallets.Reporting what you actually paid in /api/me/fees; UI display of “your tier”. Don’t use for signing.
Only market.feeTakerBps belongs in the signed Order. Signing with the platform period rate or your tier rate produces a digest that doesn’t match the CTFExchange reconstruction → bad_signature on every order. Always pull feeTakerBps from the per-market response and pass it into your signing helper unmodified.
A worked example for a tier-1 partner on a market with feeTakerBps = 400:
SurfaceValue
market.feeTakerBps400sign with this
/api/platform/fee-config.feeTakerBps400 (matches market for steady-state markets)
/api/me/fee-tier.takerBps350 (your effective post-discount rate)
The on-chain charge uses 400 (because that’s what the signed Order carries); the per-fill /api/me/fees row records 350 (your post-discount rate after the platform refunds the difference via the rebate ledger). The two values reconcile in the rebate accrual, not at fill time.

Charging direction

The asset the fee is taken in is determined by which side of the fill each party held — the same rule applies regardless of maker/taker role:
  • Seller (whichever side is sending outcome tokens for collateral): fee deducted from collateral proceeds. fee_collateral = k × P × (1−P) × outcomeTokens.
  • Buyer (whichever side is sending collateral for outcome tokens): fee deducted in outcome tokens. fee_tokens = k × (1−P) × outcomeTokens.
Both give the same USD value for the same fill — just denominated in the asset that side is receiving. On a single match the contract charges both legs; per-fill /api/me/fees carries one row per denomination per trade (unit ∈ {USDC, OUTCOME_TOKENS}, role ∈ {maker, taker}).

How fees appear in the response

Every Trade object carries:
{
  "id": "...",
  "price": "0.52",
  "quantity": "100",
  "fee": "0.2496",
  "side": "buy"
}
For per-fill audit, use GET /api/me/fees.

On-chain equivalence

The off-chain fee matches the on-chain fee charged by CTFExchange at settlement time, modulo integer-division rounding (≤ 1 atomic USDC unit). Same feeRateBps value signs into the EIP-712 Order.

Fee cap

Contract enforces feeRateBps ≤ MAX_FEE_RATE_BIPS (1000). Peak-at-0.5 at the cap is 2.5%. Raising requires Board approval and redeploy.

Examples

// BUY 100 YES at P=0.52 with k=0.04 (feeRateBps = 400)
const price = 0.52;
const quantity = 100;
const k = 0.04;
const feeTokens = k * (1 - price) * quantity;           // 1.92 YES tokens
const feeUsd    = k * price * (1 - price) * quantity;   // 1.00 USDC equiv

// SELL 100 YES at P=0.80 with k=0.014 (feeRateBps = 140)
const feeUsd = 0.014 * 0.80 * 0.20 * 100;               // 0.224 USDC

Rebates

The schedule covers fees. Mirror-image rebates to market makers are a separate system (PS-MM Rebate Model v7 §2). Rebates settle monthly. Contact partners@predictstreet.com.