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 forsale, 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 fromGET /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.
2. Use financials.leaseTerms as the calculator input record and the formulas
below for independent parity checks, audits, previews, or a calculation
before EXR has returned its computed values.
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
| Condition | Public financial interpretation |
|---|---|
financials absent | The caller lacks the financial-read scope. Stop rather than guessing. |
leaseTerms is null | The 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. |
Transaction is not lease or sublease | grossCommissionCents and gciCents are null by design; calculator terms are not applicable. |
| Lease/sublease has a readable but partial terms object | EXR 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 rate | It has no billable sliding commission. |
| Fixed calculation has a zero gross result | It 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 category | Representation and interpretation |
|---|---|
| Public summary money | Integer cents serialized as a string. For example, "12500000" is $125,000.00. Preserve it as an integer; divide by 100 only for display. |
leaseTerms money inputs | Non-negative integer cents represented as numeric fields: for example, startingRentAnnualCents and fixedAmountCents. |
| Rates | Basis 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 footage | Whole square feet. |
| Dates | ISO YYYY-MM-DD; an empty string inside lease terms means “not entered.” |
| Missing values | null 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
| Field | Meaning and use |
|---|---|
transactionType | lease or sublease activates this guide. Other transaction types do not use this calculator. |
representation | Deal-side context such as landlord_rep, tenant_rep, sublessor_rep, or sublessee_rep. It does not change the formulas below. |
status | Pipeline status. Commission invoice and payout status are operationally meaningful after deal_closed; status does not change the calculation. |
parties.tenant, parties.landlord | Party display context. |
property.address, property.unitNumber | Property display context. |
expectedCloseDate, actualCloseDate | Deal 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
| Field | Unit | Input or output | Meaning |
|---|---|---|---|
potentialCommissionCents | string cents or null | Stored headline | Manual estimate when no billable lease calculation replaces it; for a calculated lease it is normally the gross commission. |
grossCommissionCents | string cents or null | Server-computed output | Gross lease commission before referral and co-brokerage. |
gciCents | string cents or null | Server-computed output | EXR GCI: gross less referral and co-brokerage. It is a residual, not a separate calculator input. |
ownerSplitBps | bps | Team allocation input | Owner's deal-team split. |
team[] | array | Inputs plus computed outputs | Each member has identity/display fields and splitBps; EXR computes the member payout and, when valid, its milestone installments. |
leaseTerms | object or null | Calculator inputs | The per-year lease rent and commission terms defined in the next sections. |
commissionSchedule | object or null | Agreement-style data | Separate agreement/document schedule; not a source for lease-calculator math. |
paymentSchedule | object or null | Payout-timing input | Separate agreement-style milestone schedule used only to divide each team payout into installments. |
For every team[] member:
| Field | Unit | Meaning |
|---|---|---|
userId, name, email | text/null | Member identity and display information. |
splitBps | bps | Share used to compute that member's GCI payout. Deal-team splits are expected to total 10,000 bps across the team. |
payoutCents | string cents or null | Rounded member share of GCI. It is derived, not an additional amount to add to GCI. |
installments[] | ordered array | Optional derived {label, amountCents} breakdown of that member's payout. An empty array means show the member's payout as one lump sum. |
`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.
| Field | Unit / allowed values | Default and active condition |
|---|---|---|
sqft | whole SF or null | Total 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. |
groundFloorSqft, basementSqft | whole SF or null | Retail breakdown, display-only. The total sqft, not the breakdown, drives PPSF. |
startingRentAnnualCents | annual integer cents or null | Year-1 full-year base rent. Empty or zero becomes null. Required for a normal rent-based schedule. |
termMonths | whole months or null | null means every years[] row is a full 12 months. A valid value produces a partial final row when it is not divisible by 12. |
leaseStart, leaseEnd | ISO date or empty string | Optional display/term-entry dates. They can derive a displayed term but do not override a saved row schedule during arithmetic. |
years[] | ordered rows | One row per calculated lease year. It sets row count, escalation, by-year free rent, and sliding rates. |
freeRentMode | by_year or amortized | Defaults to by_year. Selects which free-rent inputs are active. |
freeRentUnit | months or weeks | Defaults to months. Applies to both the per-row and total free-rent quantities. |
freeRentMonthsTotal | non-negative number in the selected unit | Used only in amortized mode. Defaults to 0; limited to 600 entered units. |
commissionBasis | net_rent or base_rent | Defaults to net_rent. Used by sliding and fixed-percent calculations. |
commissionCalc | sliding or fixed | Defaults to sliding. Selects gross-commission method. |
fixedMode | months, amount, or percent | Defaults to months; used only when commissionCalc is fixed. |
fixedMonths | non-negative number | Used only by fixed-months mode; capped at 600. |
fixedAmountCents | non-negative integer cents | Used only by fixed-amount mode. |
fixedPercentBps | bps | Used only by fixed-percent mode. |
referralMode | percent or dollar | Defaults to percent; selects the active referral input. |
referralFeeBps | 0–10,000 bps | Used only in percent referral mode; defaults to 0. |
referralAmountCents | non-negative integer cents | Used only in dollar referral mode; defaults to 0. |
coBrokerageMode | percent or dollar | Defaults to percent; selects the active co-brokerage input. |
coBrokerageBps | 0–10,000 bps | Used only in percent co-brokerage mode; defaults to 0. |
coBrokerageAmountCents | non-negative integer cents | Used only in dollar co-brokerage mode; defaults to 0. |
commissionPaidBy | landlord, tenant, both, or empty | Defaults to empty. It can assist billing-recipient entry but never changes commission math. |
billTo, billToAddress, billToEmail | text, up to 2,000 characters each | Default 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. Whole-cent fields are rounded to whole cents during input
normalization.
| Row field | Unit | Default / use |
|---|---|---|
escalationBps | whole bps, 0–1,000,000 | Increase from the prior full-year base rent. Year 1's value is ignored. |
freeRentMonths | non-negative number in freeRentUnit | Used only in by_year mode. Fractions are allowed and are capped to the months covered by that row. |
commissionBps | bps, up to 1,000,000 | Per-row rate for sliding calculation. Ignored by fixed-months and fixed-amount calculations; replaced by fixedPercentBps in fixed-percent calculation. |
4. Do not confuse the three financial schedules
The public financial object contains three distinct concepts:
| Field | Purpose | Units and relationship to the calculator |
|---|---|---|
financials.leaseTerms | Lease calculator input schedule | The only schedule used to derive rent rows, gross commission, referral, co-brokerage, and GCI. Its money is cents and its rates are bps. |
financials.commissionSchedule | Agreement-style commission description | A 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.paymentSchedule | When a commission is paid | Structured 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.
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. It is valid only when it is from
1 through 720 and ceil(termMonths / 12) = N.
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 bestartingRentAnnualCents 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 and net rent
freeRentUnit = months uses the entered number directly. WithfreeRentUnit = 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.
#### 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).
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).
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.
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 still appears in net-rent display but is
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.
| Mode | Gross-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: months | Gross = round((F_1 / 12) × fixedMonths). fixedMonths is non-negative and capped at 600. Per-row commission values are not used. |
| Fixed: amount | Gross = fixedAmountCents. Per-row commission values are not used. |
| Fixed: percent | For 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. 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.
- 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.
- Percent:
CoBrokerage = round(PostReferral × coBrokerageBps / 10,000).
- Dollar:
CoBrokerage = min(coBrokerageAmountCents, PostReferral).
4. EXR GCI is the residual:
GCI = Gross - Referral - CoBrokerage.
The dollar caps ensure GCI cannot become negative. If no downstream fees are
entered, both fees are zero and GCI equals gross.
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,
amortizedover the term, unitmonths. - Fixed calculation, fixed-percent mode, 3.25% = 325 bps, on
net_rent. - No escalation, 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.
| Rows | Months each | Base rent / yr | Free rent / yr | Net rent / yr | Fixed 3.25% commission / row |
|---|---|---|---|---|---|
| Years 1–10 (each) | 12 | $350,000.00 | $13,257.58 | $336,742.42 | $10,944.13 |
| Year 11 | 5 | $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).
| Row | Base rent | Commission |
|---|---|---|
| Year 1 | $120,000.00 | round(12,000,000 × 500 / 10,000) = $6,000.00 |
| Year 2 | $132,000.00 | round(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.
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 = $4,500.00.
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 both
co-brokerage and GCI.
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%:
| Member | Payout | Milestone 1 | Milestone 2 | Final 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.
- 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.