EXR Commercial Developer Documentation

EXR Commercial Lease Commission Calculation Guide

This guide is self-contained context for EXR Back Office, Vault, or another
financial consumer that needs to read or independently reproduce the commercial
lease commission calculation from EXR's public Deal data.

It applies only to lease and sublease transactions. It does not define a
sales-deal commission engine and should not be used to infer commission for
sale, loan_debt, or valuation_advisory deals.

Use the public Developer API under /api/v1, not the authenticated in-product
routes. The public API returns parsed financial objects and stable money
representations. The complete, current field shape is available from
GET /api/v1/openapi.json.

1. Access and source-of-truth rules

Required API access

- Read deals through GET /api/v1/deals (page with limit and the opaque
cursor) or GET /api/v1/deals/{id}.
- deal.created and deal.updated webhooks carry the same full public deal
object, including financials when the delivery is authorized for them.
- A token needs deals:financials:read for the financials object. If
financials is absent, that is an authorization limitation, not proof
that the deal has no financial data. Do not substitute zeroes.

Precedence for consuming values

1. For an existing EXR deal, prefer the server-computed
financials.grossCommissionCents, financials.gciCents,
financials.team[].payoutCents, and
financials.team[].installments as the operational values. When a
consumer needs the year-by-year figures behind gross (base rent, free rent,
excluded charges, net rent, commissionable rent, and commission per row),
read financials.leaseSchedule rather than rebuilding it. It is the
calculator's own row output, already rounded (section 3).
2. Use financials.leaseTerms as the calculator input record, together with
the deal-level financials.referralInvoiceMethod, and the formulas below
for independent parity checks, audits, previews, or a calculation before
EXR has returned its computed values. leaseSchedule comes from the same
server calculation as gross, so it is a display and reconciliation aid, not
an independent check of that calculation.
3. Treat financials.potentialCommissionCents as a headline/stored value, not
an independent calculator result. EXR replaces it with calculated gross
commission when a lease calculation produces a billable result; it can
otherwise remain a manually entered estimate.
4. Never use financials.commissionSchedule to calculate the lease
calculator's gross commission. It is a separate agreement-style description
(explained in section 4).

When values are absent, zero, or incomplete

ConditionPublic financial interpretation
financials absentThe caller lacks the financial-read scope. Stop rather than guessing.
leaseTerms is nullThe stored calculator field was empty or not readable as JSON. This says nothing about the caller's scope because, with insufficient scope, the entire financials object would be absent.
leaseSchedule is nullPresent under exactly the same conditions as grossCommissionCents: it is null when the transaction is not lease or sublease or the terms are not readable. A readable but partial terms object still yields a schedule, possibly with no rows or zero figures.
Transaction is not lease or subleasegrossCommissionCents, gciCents, and leaseSchedule are null by design; calculator terms are not applicable.
Lease/sublease has a readable but partial terms objectEXR can still expose calculated fields, often as "0". A zero is not proof that all commercial terms are complete. Inspect the inputs and rates.
Sliding calculation has no positive starting rent, no rows, or no positive row rateIt has no billable sliding commission.
Fixed calculation has a zero gross resultIt has no billable fixed commission.

The calculator tolerates older and partial records. Missing optional inputs use
the defaults in this guide. Unknown or invalid enum values also fall back to
those defaults rather than creating a new calculation mode.

The formal public contract defines leaseTerms as an object or null.
Historical malformed storage can expose other successfully decoded JSON values
even though they are outside that contract. Treat such a value as invalid
calculator input; do not reinterpret it as a lease schedule. The server-computed
summary remains authoritative.

Team payouts are derived from a zero GCI input when no lease calculation is
available. Consequently, a team member can have payoutCents = "0" even while
gross and GCI are null. With a valid payment schedule this can include
zero-valued labeled installments; otherwise installments is empty. Do not
interpret that derived zero as evidence that lease terms exist.

2. Universal units, precision, and rounding

These conventions apply before any formula is evaluated.

Value categoryRepresentation and interpretation
Public summary moneyInteger cents serialized as a string, in the financials summary fields and throughout leaseSchedule. For example, "12500000" is $125,000.00. Preserve it as an integer; divide by 100 only for display.
leaseTerms money inputsNon-negative integer cents represented as numeric fields: for example, startingRentAnnualCents, years[].excludedChargesAnnualCents, and fixedAmountCents.
RatesBasis points (bps): 10,000 bps = 100%; 325 bps = 3.25%. Commission, referral, and co-brokerage rates preserve one decimal bps, which is 0.001 percentage-point precision. Escalation is whole bps.
Square footageWhole square feet.
DatesISO YYYY-MM-DD; an empty string inside lease terms means “not entered.”
Missing valuesnull means not entered, not zero. Do not turn null into zero when aggregating.

All calculations operate in cents. At every round(...) in this guide, round to
the nearest whole cent; an exact half-cent rounds up. Keep each specified
intermediate result as an integer cent value before using it in the next step.

This is important: the sum of rounded amortized free-rent slices can differ by
a few cents from the one-time total free-rent valuation, and gross commission
is the sum of rounded row commissions, not one percentage applied to an
unrounded aggregate.

3. Public deal and financial field dictionary

Deal context needed to interpret financials

FieldMeaning and use
transactionTypelease or sublease activates this guide. Other transaction types do not use this calculator.
representationDeal-side context such as landlord_rep, tenant_rep, sublessor_rep, or sublessee_rep. It does not change the formulas below.
statusPipeline status. Commission invoice and payout status are operationally meaningful after deal_closed; status does not change the calculation.
parties.tenant, parties.landlordParty display context.
property.address, property.unitNumberProperty display context.
expectedCloseDate, actualCloseDateDeal dates. actualCloseDate can supply the displayed date for a “Lease Execution” payment milestone; it does not change the commission arithmetic.

`financials` summary and computed outputs

FieldUnitInput or outputMeaning
potentialCommissionCentsstring cents or nullStored headlineManual estimate when no billable lease calculation replaces it; for a calculated lease it is normally the gross commission.
grossCommissionCentsstring cents or nullServer-computed outputGross lease commission before referral and co-brokerage.
gciCentsstring cents or nullServer-computed outputEXR GCI: gross less co-brokerage, less the referral only when referralInvoiceMethod deducts it (section 5.5). It is a residual, not a separate calculator input.
referralInvoiceMethodincluded_on_exr_invoice, invoiced_separately, or nullDeal-level calculator inputHow the referral fee is invoiced. invoiced_separately: the referral is deducted from GCI. included_on_exr_invoice: the referral stays visible and still reduces the co-brokerage base, but it is not deducted from GCI. null (no active referral, or a legacy deal whose method was never classified) deducts like invoiced_separately. It is returned beside leaseTerms, not inside it.
coBrokerageInvoiceMethodincluded_in_exr_invoice, invoiced_separately, or nullInformationalHow the cooperating broker's share is invoiced. It never changes any calculation: co-brokerage is deducted from GCI under every value.
ownerSplitBpsbpsTeam allocation inputOwner's deal-team split.
team[]arrayInputs plus computed outputsEach member has identity/display fields and splitBps; EXR computes the member payout and, when valid, its milestone installments.
leaseTermsobject or nullCalculator inputsThe per-year lease rent and commission terms defined in the next sections.
leaseScheduleobject or nullServer-computed outputThe per-year rows and column totals behind grossCommissionCents: the B_i, R_i, X_i, Net_i, C_i, and Q_i of section 5, already rounded, plus the normalized modes the calculator applied. Defined in the next subsection.
commissionScheduleobject or nullAgreement-style dataSeparate agreement/document schedule; not a source for lease-calculator math.
paymentScheduleobject or nullPayout-timing inputSeparate agreement-style milestone schedule used only to divide each team payout into installments.

For every team[] member:

FieldUnitMeaning
userId, name, emailtext/nullMember identity and display information.
splitBpsbpsShare used to compute that member's GCI payout. Deal-team splits are expected to total 10,000 bps across the team.
payoutCentsstring cents or nullRounded member share of GCI. It is derived, not an additional amount to add to GCI.
installments[]ordered arrayOptional derived {label, amountCents} breakdown of that member's payout. An empty array means show the member's payout as one lump sum.

`leaseSchedule`: the server-computed row output

leaseSchedule is read-only. It is produced from leaseTerms by the same
server calculation that produces grossCommissionCents, so a consumer that
only needs to display, store, or reconcile the year-by-year schedule can read
it directly instead of reproducing sections 5.1 through 5.4. It is null
under exactly the same conditions as grossCommissionCents. It is never
accepted as write input, and it is not an independent check of the server
calculation; use leaseTerms and the formulas below for that.

FieldUnit / allowed valuesMeaning
freeRentModeby_year or amortizedThe free-rent model actually applied, after defaults and invalid-value fallback.
freeRentUnitmonths or weeksUnit of rows[].freeRentUnits and totals.freeRentUnits. The freeRentMonths fields are always month-equivalents.
commissionBasisnet_rent or base_rentThe basis actually applied; rows[].commissionableRentCents is C_i under that basis.
commissionCalcsliding or fixedThe gross-commission method actually applied.
fixedModemonths, amount, percent, or nullSet only when commissionCalc is fixed; null for sliding.
rows[]ordered rowsOne row per leaseTerms.years[] entry, Year 1 first; empty when the terms have no rows.
totalsobjectColumn totals across rows[], defined below.

Each rows[] entry carries the values of section 5 for that row i:

Row fieldUnitSection 5 value
yearwhole numberi, starting at 1.
monthsInYearwhole monthsm_i: 12, or the remaining months of a partial final row.
baseRentAnnualCentsstring centsB_i, the row's base rent after escalation and any partial-row proration.
baseRentMonthlyCentsstring centsDisplayed monthly base rent, round(F_i / 12); a rate, so it is not prorated.
escalationBpswhole bpsescalationBps_i as applied to the escalation chain (Year 1's value is ignored).
freeRentMonthsmonthsCapped by-year free rent for the row in month-equivalents. In amortized mode this is 0 on every row and the whole-term quantity is reported once in totals.
freeRentUnitsfreeRentUnit unitsThe same quantity in the entered unit.
freeRentAmountCentsstring centsR_i in by_year mode or R_slice in amortized mode.
excludedChargesAnnualCentsstring centsThe row's excludedChargesAnnualCents input as read by the calculator ("0" when absent).
excludedChargesCentsstring centsX_i, the prorated deduction actually applied.
netRentAnnualCentsstring centsNet_i.
commissionableRentCentsstring centsC_i: Net_i under net_rent, B_i under base_rent.
basePpsfCentsstring cents per SF or nullDisplayed base PPSF, round(F_i / sqft); null without a positive sqft.
commissionBpsbps, one decimal allowedThe row rate actually applied: commissionBps_i in sliding mode, fixedPercentBps in fixed-percent mode, 0 in fixed-months and fixed-amount modes.
commissionCentsstring centsQ_i in sliding and fixed-percent modes; "0" in fixed-months and fixed-amount modes.

totals reports the column sums of rows[]:

Total fieldUnitMeaning
baseRentCentsstring centssum(B_i).
freeRentCentsstring centssum(R_i) or sum(R_slice), the rounded row values, which in amortized mode can differ by a few cents from R_total.
excludedChargesCentsstring centssum(X_i).
netRentCentsstring centssum(Net_i).
commissionCentsstring centssum(Q_i). It equals grossCommissionCents in sliding and fixed-percent modes. In fixed-months and fixed-amount modes it is "0" because no per-row commission exists; grossCommissionCents alone carries the flat figure.
freeRentMonthsmonthsWhole-term free rent in month-equivalents: the sum of the capped row quantities in by_year mode, or the entered total in amortized mode.
freeRentUnitsfreeRentUnit unitsThe same whole-term quantity in the entered unit.

Referral, co-brokerage, GCI, and team payouts are not part of leaseSchedule;
read them from the financials summary and team[].

`leaseTerms`: inputs and defaults

leaseTerms is the authoritative public input record for the lease calculator.
All fields below are calculator inputs unless marked display-only.

FieldUnit / allowed valuesDefault and active condition
sqftwhole SF or nullTotal rentable SF. Values are limited to 100,000,000 SF; empty or zero becomes null. Used only for PPSF display, not for rent or commission math.
usableSqftwhole SF or nullOffice usable SF, display-only. It never participates in PPSF, rent, or commission math.
groundFloorSqft, basementSqftwhole SF or nullRetail breakdown, display-only. The total sqft, not the breakdown, drives PPSF.
startingRentAnnualCentsannual integer cents or nullYear-1 full-year base rent. Empty or zero becomes null. Required for a normal rent-based schedule.
termMonthswhole months from 1 through 720, or nullnull means every years[] row is a full 12 months. A value is a whole number of months, and ceil(termMonths / 12) must equal the years[] row count; it produces a partial final row when it is not divisible by 12. The API rejects any other value on write. A legacy stored value is rounded half up to whole months before the range and row-count checks in section 5.1.
leaseStart, leaseEndISO date (YYYY-MM-DD naming a real calendar day) or empty stringOptional display/term-entry dates. They can derive a displayed term but do not override a saved row schedule during arithmetic. The API rejects any other value on write, including a well-formed but impossible date such as 2026-02-30.
years[]ordered rows, at most 60 on writeOne row per calculated lease year. It sets row count, escalation, by-year free rent, excluded charges, and sliding rates. The calculation computes whatever row count a stored record carries; the API and the in-app editor accept at most 60 rows (the 720-month termMonths ceiling).
freeRentModeby_year or amortizedDefaults to by_year. Selects which free-rent inputs are active.
freeRentUnitmonths or weeksDefaults to months. Applies to both the per-row and total free-rent quantities.
freeRentMonthsTotalnon-negative number in the selected unitUsed only in amortized mode. Defaults to 0; limited to 600 entered units.
commissionBasisnet_rent or base_rentDefaults to net_rent. Used by sliding and fixed-percent calculations. base_rent charges commission on base rent, ignoring free rent and excluded charges.
commissionCalcsliding or fixedDefaults to sliding. Selects gross-commission method.
fixedModemonths, amount, or percentDefaults to months; used only when commissionCalc is fixed.
fixedMonthsnon-negative numberUsed only by fixed-months mode; capped at 600.
fixedAmountCentsnon-negative integer centsUsed only by fixed-amount mode.
fixedPercentBpsbpsUsed only by fixed-percent mode.
referralModepercent or dollarDefaults to percent; selects the active referral input.
referralFeeBps0–10,000 bpsUsed only in percent referral mode; defaults to 0.
referralAmountCentsnon-negative integer centsUsed only in dollar referral mode; defaults to 0.
coBrokerageModepercent or dollarDefaults to percent; selects the active co-brokerage input.
coBrokerageBps0–10,000 bpsUsed only in percent co-brokerage mode; defaults to 0.
coBrokerageAmountCentsnon-negative integer centsUsed only in dollar co-brokerage mode; defaults to 0.
commissionPaidBylandlord, tenant, both, or emptyDefaults to empty. It can assist billing-recipient entry but never changes commission math.
billTo, billToAddress, billToEmailtext, up to 2,000 characters eachDefault empty. Billing display fields only; never affect commission math.

Each years[] row is ordered by index: first row is Year 1.

All cents input fields are limited to 9,007,199,254,740,991 cents and
non-negative values. The API rejects a fractional, negative, or non-numeric
cents value on write; the legacy input coercion note below covers records
stored before that validation existed.

Row fieldUnitDefault / use
escalationBpswhole bps, 0–1,000,000Increase from the prior full-year base rent. Year 1's value is ignored.
freeRentMonthsnon-negative number in freeRentUnitUsed only in by_year mode. Fractions are allowed and are capped to the months covered by that row.
excludedChargesAnnualCentsnon-negative integer cents per yearDefaults to 0 when absent, including rows saved before the field existed. Annual taxes, CAM, BID, or other charges included in the stated base rent but excluded from net rent. The entered amount is an annual figure and is prorated by the row's months in a partial final row (section 5.2). It reduces net_rent commission and is ignored when commissionBasis is base_rent.
commissionBpsbps, up to 1,000,000Per-row rate for sliding calculation. Ignored by fixed-months and fixed-amount calculations; replaced by fixedPercentBps in fixed-percent calculation.

Legacy input coercion. The API validates leaseTerms on write: every
documented key it accepts already matches the types and ranges above, so the
calculation reads a record written since that validation existed exactly as
stored, and financials.leaseTerms and financials.leaseSchedule agree.
Records stored before then may still hold out-of-contract values, which the
calculation coerces as it reads them: a non-numeric value in a numeric field
becomes 0 (a numeric string is read as its number), a negative value becomes 0,
a fractional cents value is rounded half up to whole cents, a value above a
field's limit is reduced to that limit, a rate that allows one decimal place is
rounded to one decimal, an unknown enum value becomes the field's default, an
invalid termMonths becomes null, and a malformed or impossible date (such
as 2026-02-30) becomes an empty string. For such a record, leaseSchedule
reflects the coerced values while leaseTerms still echoes what was stored. An API edit that touches
termMonths or years[] re-checks the merged record's termMonths and row
count; an edit to other keys leaves a legacy record's untouched values as they
are.

4. Do not confuse the three financial schedules

The public financial object contains three distinct concepts:

FieldPurposeUnits and relationship to the calculator
financials.leaseTermsLease calculator input scheduleThe only schedule used to derive rent rows, gross commission, referral, co-brokerage, and GCI (GCI also reads the deal-level referralInvoiceMethod). Its money is cents and its rates are bps.
financials.commissionScheduleAgreement-style commission descriptionA separate tagged schedule: sliding year brackets, fixed agreement terms, or free-form custom text. Its percentage values are entered strings such as "5" for 5%, and its fixed dollar text is not a cents field. It does not replace, normalize, or drive leaseTerms.
financials.paymentScheduleWhen a commission is paidStructured milestone rows or free-form custom payment text. Structured percentages are entered strings such as "50" for 50%. It divides a team member's already-calculated GCI payout; it never changes gross commission or GCI.

For a structured paymentSchedule, the rows are ordered and contain a
milestone label, percent, and optional expected date. The expected date is a
billing helper only. The displayed expected date for “Lease Execution” follows
the deal's actualCloseDate; it does not affect an installment amount.

financials.leaseSchedule is not a fourth schedule to reconcile. It is the
computed row output of leaseTerms (section 3) and carries no inputs of its
own: changing a deal's terms changes leaseSchedule and grossCommissionCents
together, and nothing in commissionSchedule or paymentSchedule feeds it.

5. Calculation specification

5.1 Normalize the term and build rows

Use this sequence:

1. Let N be years[].length. It is the number of schedule rows.
2. Normalize termMonths to a whole number of months, then validate it. A
record written through the API already carries a whole number (the API
rejects anything else on write); a legacy stored value that is not whole is
rounded half up to whole months first. The result is valid only when it is
from 1 through 720 and ceil(termMonths / 12) = N. A non-numeric, absent,
or otherwise invalid value is treated as absent.
3. If termMonths is valid, rows 1 through N - 1 cover 12 months and row
N covers termMonths - 12 × (N - 1) months. If it is absent or invalid,
every row covers 12 months.
4. Lease start/end dates are optional. When both are present, an inclusive
lease duration can be derived by treating the day after the end date as the
boundary, taking calendar-month difference plus the nearest partial month
(day difference divided by 30.44), then limiting the result to 1–720
months. This is a term-entry aid; row count and valid termMonths control
the arithmetic.

For row i (Year 1 is i = 1), let A be
startingRentAnnualCents and m_i be that row's months:

- Full-year rate for Year 1: F_1 = A.
- For each later row:
F_i = round(F_(i-1) × (10,000 + escalationBps_i) / 10,000).
- The escalation chain always uses full-year rates, even if the last row is
partial.
- Row base rent:
B_i = F_i for a 12-month row; otherwise
B_i = round(F_i × m_i / 12).
- Displayed monthly base rent: round(F_i / 12). This remains the full-year
monthly rate even in a partial final row.
- Displayed base PPSF: round(F_i / sqft) cents per SF when total sqft is
positive; otherwise it is unavailable. PPSF is informational and never
changes the commission calculation.

For data entry, an annual dollar rent is converted to integer annual cents.
A monthly dollar rent is multiplied by 12 to become annual cents. An annual
PPSF entry is multiplied by total SF and then converted to annual cents.
Once read from the API, startingRentAnnualCents is the authoritative rent
input for the formulas above.

5.2 Free rent, excluded charges, and net rent

freeRentUnit = months uses the entered number directly. With
freeRentUnit = weeks, convert entered units to month-equivalents using:

free-rent months = entered weeks × 12 / 52

Equivalently, one week is 3/13 of a month. Do not use four weeks as one month.

#### Excluded charges

Each row can carry years[i].excludedChargesAnnualCents: taxes, CAM, BID, or
other charges that are included in the stated base rent but are not
commissionable. The value is entered as an annual amount, so prorate it by the
row's months before deducting it:

- X_i = excludedChargesAnnualCents_i for a 12-month row; otherwise
X_i = round(excludedChargesAnnualCents_i × m_i / 12).
- A missing field is 0, so X_i = 0 for rows saved before the field existed.

X_i is deducted in both free-rent modes below. It is not affected by free
rent, and it never changes B_i, F_i, or the displayed monthly base rent.

#### By year

This is the default mode. For each row:

1. Convert years[i].freeRentMonths from the selected unit to months.
2. Cap it at that row's m_i months, then retain the capped quantity for
display in the selected unit.
3. Calculate row free-rent value:
R_i = round(F_i / 12 × capped free-rent months).
4. Calculate row net rent:
Net_i = max(0, B_i - R_i - X_i).

The cap means free rent cannot exceed the months actually covered by the row.
For example, 60 entered weeks in a full-year row caps to 52 weeks, or 12
months.

#### Amortized over term

Only freeRentMonthsTotal is active in this mode. It is capped at 600 entered
units. Apply this sequence once:

1. Convert total entered units to month-equivalents.
2. Value total free rent at the Year-1 monthly base rate:
R_total = round(F_1 / 12 × total free-rent months).
3. Divide it over the number of rows, not the number of lease months:
R_slice = round(R_total / N).
4. Put the same R_slice on every row, including a partial final row.
5. For each row, calculate Net_i = max(0, B_i - R_slice - X_i).

The stored/free-rent total reports the entered total quantity, while the
schedule reports the rounded dollar slice. Therefore sum(R_i) can be a few
cents different from R_total. The schedule's total net rent uses the rounded
row slices.

In either mode, the zero floor is applied once, after both the free-rent value
and the prorated excluded charges have been subtracted from B_i.

5.3 Select commissionable rent

For every row, net rent is displayed regardless of the chosen basis:

- net_rent (default): C_i = Net_i.
- base_rent: C_i = B_i; free rent and excluded charges still appear in
net-rent display but are ignored for commission.

The basis applies to sliding and fixed-percent calculations. Fixed-months and
fixed-amount calculations do not use a row commission basis.

5.4 Calculate gross commission

Choose exactly one calculation branch.

ModeGross-commission rule
Sliding (default)For each row, calculate Q_i = round(C_i × commissionBps_i / 10,000). Gross is sum(Q_i). Round each row first.
Fixed: monthsGross = round((F_1 / 12) × fixedMonths). fixedMonths is non-negative and capped at 600. Per-row commission values are not used.
Fixed: amountGross = fixedAmountCents. Per-row commission values are not used.
Fixed: percentFor each row, set the row rate to fixedPercentBps and calculate Q_i = round(C_i × fixedPercentBps / 10,000). Gross is sum(Q_i). This deliberately follows the same per-row rounding as sliding.

In fixed-months and fixed-amount modes, the yearly commission cells have no
independent calculation and should be treated as unavailable rather than
summed. The public leaseSchedule returns them as 0 (commissionBps and
commissionCents on every row, and totals.commissionCents), and only
grossCommissionCents carries the flat figure. In fixed-percent mode, they are
calculated and sum to gross.

5.5 Apply referral, co-brokerage, and EXR GCI

All fee rates are limited to 0–10,000 bps. The order is mandatory:

1. Referral fee comes from gross. It is always calculated and capped this
way, whatever financials.referralInvoiceMethod says.
- Percent: Referral = round(Gross × referralFeeBps / 10,000).
- Dollar: Referral = min(referralAmountCents, Gross).
2. Set PostReferral = max(0, Gross - Referral).
3. Co-brokerage comes from the post-referral amount, never from gross.
This base is the same under every referral invoice method.
- Percent:
CoBrokerage = round(PostReferral × coBrokerageBps / 10,000).
- Dollar:
CoBrokerage = min(coBrokerageAmountCents, PostReferral).
4. Referral deduction depends on the deal-level
financials.referralInvoiceMethod, which is returned beside leaseTerms
rather than inside it:
- invoiced_separately or null: ReferralDeduction = Referral.
- included_on_exr_invoice: ReferralDeduction = 0. The referral stays
visible as a fee and already reduced the co-brokerage base in step 3,
but it is not removed from EXR GCI.
5. EXR GCI is the residual:
GCI = Gross - ReferralDeduction - CoBrokerage.

The dollar caps ensure GCI cannot become negative. If no downstream fees are
entered, both fees are zero and GCI equals gross. The deal-level
coBrokerageInvoiceMethod is informational only; co-brokerage is deducted
under every value.

5.6 Split GCI among the deal team and milestones

For each deal-team member independently:

MemberPayout = round(GCI × member.splitBps / 10,000)

The member payouts are derived views. Preserve EXR's returned payout values for
operational use; an independent replica should apply the same rounding to every
member rather than moving a rounding difference between members.

Then assess the payment schedule:

- Use installment breakdown only for a non-empty, structured milestone schedule
whose parsed percentages total within 1 bps of 10,000 bps (99.99%–100.01%).
- Custom free text, no rows, or a schedule outside that tolerance produces no
installments. The member payout is one lump sum.
- For a valid schedule, process milestones in listed order. For every member
except the final milestone, calculate
round(MemberPayout × milestonePercentBps / 10,000).
- The final milestone is
MemberPayout - sum(previous installments). It absorbs any rounding
remainder, so that member's installments always sum exactly to their payout.

6. Required worked parity example: 125-month scenario

This example uses the fields visible in the referenced commission scenario.
Any value not visible is assumed to remain at its documented default:

- 11,460 SF (PPSF is display-only).
- $350,000.00 annual starting rent = 35,000,000 cents.
- 125-month term, therefore 11 rows: ten 12-month rows and one 5-month row.
- Five months of free rent, amortized over the term, unit months.
- Fixed calculation, fixed-percent mode, 3.25% = 325 bps, on net_rent.
- No escalation, excluded charges, referral, co-brokerage, or other downstream
fee.

First calculate the free-rent allocation:

- Year-1 monthly base is 35,000,000 / 12 = 2,916,666.666... cents.
- One-time free-rent value is
round(2,916,666.666... × 5) = 14,583,333 cents = $145,833.33.
- Each row's amortized slice is
round(14,583,333 / 11) = 1,325,758 cents = $13,257.58.

RowsMonths eachBase rent / yrFree rent / yrNet rent / yrFixed 3.25% commission / row
Years 1–10 (each)12$350,000.00$13,257.58$336,742.42$10,944.13
Year 115$145,833.33$13,257.58$132,575.75$4,308.71

The ten full rows each use:

round(33,674,242 cents × 325 / 10,000) = 1,094,413 cents

The partial final row uses:

round(13,257,575 cents × 325 / 10,000) = 430,871 cents

Therefore:

- Total base rent = $3,645,833.33.
- The original one-time free-rent valuation is $145,833.33, but 11 rounded
schedule slices total $145,833.38.
- Total schedule net rent is $3,499,999.95.
- Gross commission is
10 × $10,944.13 + $4,308.71 = $113,750.01.
- With zero referral and co-brokerage, EXR GCI is also $113,750.01.

The five-cent free-rent allocation difference and one-cent gross outcome are
intentional consequences of EXR's row-by-row rounding rules. Do not replace
this with one calculation on aggregate net rent.

7. Compact parity examples

Sliding scale with escalation

Starting rent is $120,000.00/year (12,000,000 cents), no free rent, and both
Year 1 and Year 2 use 5.00% (500 bps). Year 2 escalates 10.00% (1,000 bps).

RowBase rentCommission
Year 1$120,000.00round(12,000,000 × 500 / 10,000) = $6,000.00
Year 2$132,000.00round(13,200,000 × 500 / 10,000) = $6,600.00

Gross is $12,600.00. The escalation is chained from the prior full-year
rate before commission is calculated.

By-year versus amortized free rent

Use a two-year $120,000.00/year lease, 10% Year-2 escalation, 5% net
commission each year, and one month of total free rent.

- By year: place the month in the escalated Year 2. Year 1 commission is
$6,000.00. Year 2 base is $132,000.00, free rent is $11,000.00, net is
$121,000.00, and commission is $6,050.00. Gross = $12,050.00.
- Amortized: value the month at Year-1 monthly rent ($10,000.00) and put
$5,000.00 on each row. Year 1 commission is $5,750.00 and Year 2 commission
is $6,350.00. Gross = $12,100.00.

The result differs because by-year free rent uses that year's rent while
amortized free rent always uses the Year-1 monthly rate and spreads its dollar
value by row.

Excluded charges with a partial final year

Use an 18-month lease (termMonths = 18, so Year 1 covers 12 months and Year 2
covers 6) at $120,000.00/year, no escalation, no free rent, 5% (500 bps) on
net_rent, and $12,000.00/year (1,200,000 cents) of excluded charges on each
row.

RowMonthsBase rentExcluded chargesNet rentCommission
Year 112$120,000.00$12,000.00$108,000.00round(10,800,000 × 500 / 10,000) = $5,400.00
Year 26$60,000.00round(1,200,000 × 6 / 12) = $6,000.00$54,000.00round(5,400,000 × 500 / 10,000) = $2,700.00

Gross is $8,100.00. Without the excluded charges the same lease produces
$9,000.00, and switching commissionBasis to base_rent also returns
$9,000.00 because that basis ignores the deduction. Net rent displays
$108,000.00 and $54,000.00 under either basis.

The public leaseSchedule for this deal returns these two rows directly:
monthsInYear 12 and 6, excludedChargesCents "1200000" and "600000",
netRentAnnualCents "10800000" and "5400000", and commissionCents
"540000" and "270000", with totals.commissionCents "810000" equal to
grossCommissionCents.

Referral then co-brokerage

For a $10,000.00 gross commission, referral is 10% and co-brokerage is 50%:

1. Referral = $1,000.00 (10% of gross).
2. Post-referral amount = $9,000.00.
3. Co-brokerage = $4,500.00 (50% of $9,000.00).
4. EXR GCI depends on referralInvoiceMethod:
- invoiced_separately or null:
GCI = $10,000.00 - $1,000.00 - $4,500.00 = $4,500.00.
- included_on_exr_invoice:
GCI = $10,000.00 - $4,500.00 = $5,500.00. The $1,000.00 referral is
still reported, and co-brokerage is still $4,500.00 rather than
$5,000.00 because its base excludes the referral under either method.

Taking co-brokerage from gross instead would be incorrect. A $12,000 dollar
referral would instead cap at the $10,000 gross, leaving $0 for co-brokerage
and, when the referral is invoiced separately, $0 for GCI. With an included
referral, the same capped case leaves GCI at the full $10,000.00 because
nothing is deducted.

Team and milestone rounding

Let GCI be 1,000,001 cents ($10,000.01), with a 60% lead and 40% collaborator.
Their independently rounded payouts are $6,000.01 and $4,000.00. Use valid,
ordered milestones of 33.34%, 33.33%, and 33.33%:

MemberPayoutMilestone 1Milestone 2Final milestone (remainder)
Lead, 60%$6,000.01$2,000.40$1,999.80$1,999.81
Collaborator, 40%$4,000.00$1,333.60$1,333.20$1,333.20

The final installment is not independently percentage-rounded. It is the
remainder after prior installments so each member's installment total exactly
matches that member's payout.

8. Vault handoff semantics

- Financial meaning is available only when the deal includes the scoped
financials object.
- Only lease and sublease records use this calculation.
- Public *Cents summary strings mean integer cents; leaseTerms retains the
input units documented above.
- EXR's computed gross, GCI, team payouts, and installments are the primary
operational handoff values. Sections 5.1–5.6 define the independent parity
interpretation and its required operation order.
- leaseSchedule supplies the per-year operational figures (rows and column
totals) for display, storage, or reconciliation without re-deriving the
calculator math. It is produced by the same server calculation as gross, so
it is not an independent parity source.
- leaseTerms, commissionSchedule, and paymentSchedule remain separate.
Agreement text does not supply a calculator rate, and payment milestones do
not create a second commission calculation.

These semantics give Vault exact EXR operational values and a clear audit basis
without prescribing a particular implementation.