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.
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

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.
Transaction is not lease or subleasegrossCommissionCents and gciCents 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. 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 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 referral and co-brokerage. It is a residual, not a separate calculator input.
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.
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.

`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.
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 or nullnull 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, leaseEndISO date or empty stringOptional display/term-entry dates. They can derive a displayed term but do not override a saved row schedule during arithmetic.
years[]ordered rowsOne row per calculated lease year. It sets row count, escalation, by-year free rent, and sliding rates.
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.
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. Whole-cent fields are rounded to whole cents during input
normalization.

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.
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.

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. 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.

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 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 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.

#### 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.

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. 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:

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.

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%:

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.
- 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.