Proposal Data Keys

A proposal template does not run queries. It declares the sources it needs and names a key wherever a value should appear on the page, and the server assembles those values once, scoped to your org and checked against what your plan includes.

This page lists every key that exists, and what each one is actually for.


How a key is written

A key is a source, a dot, and a field:

solarDesign.systemKw
customer.name
customer.quote.totalAmount
financing.apr
products.0.name

Lists are reachable by number — products.0 is the first product, ordered by name so it means the same thing on every proposal from that template.

Three rules are worth knowing before you author against them.

A key names one printable value, never a record. solarDesign.pricePerWatt is a key; solarDesign.pricing is not, and a template pointing at a whole record is refused at authoring time rather than printing [object Object] to a customer.

A missing value is never a blank. If a key has no value on this job, the field arrives on the fill form marked blocked, with the reason, and somebody answers it. It does not quietly print an empty box.

A source your plan does not include is withheld, not broken. The proposal says which feature it needed instead of rendering a hole — so a template degrades rather than failing at somebody's kitchen table.


solarDesign — the roof, the system and the price

Requires the Solar Designer feature. Reads the design attached to this quote, at its current revision — a proposal quotes a version of a design, and the version is the point.

If the quote has no solar design at all, the whole source is absent. A solar template used on a non-solar quote says so instead of printing zeros.

What the design is

KeyWhat it is for
solarDesign.idThe design's identifier. For a reference line or a QR link back to it.
solarDesign.nameWhat the design is called — "Roof design", "South array", whatever the rep named it.

The system

These come from the engine, recomputed and copied on every save, so they are never a stale figure typed by hand.

KeyWhat it is for
solarDesign.panelCountNumber of modules, after any hand adjustment on the pricing step. The number a customer counts on the picture.
solarDesign.systemKwSystem size in kWp, to three decimals. The headline "an 8.4 kW system".
solarDesign.systemWattsThe same size in watts, rounded. Use it where a per-watt calculation is being shown.
solarDesign.annualKwhFirst-year production. Absent until a simulation has been run — a drawn-but-unsimulated design has no annual figure, and inventing one is worse than asking.
solarDesign.specificYieldkWh per kW installed. What lets one design be compared against another regardless of size.
solarDesign.solarAccessPercentHow much of the available sun this roof actually receives, 0–100. The honest way to show a shaded roof.
solarDesign.tsrfPercentTotal solar resource fraction, 0–100 — orientation and shade together.
solarDesign.simulatedTrue once the annual simulation has been run. Use it to hide a production block on a design that has not been simulated.
solarDesign.computedOnThe date those figures were computed. A production number without its date cannot be checked later.

The module

KeyWhat it is for
solarDesign.moduleManufacturerThe module's maker, from the equipment library.
solarDesign.moduleModelThe model designation. Together with the maker, the line a customer checks against a datasheet.
solarDesign.moduleWattsNameplate watts per module. panelCount × moduleWatts is the system, which is the arithmetic a customer does in their head.
solarDesign.moduleDatasheetUrlA link to the manufacturer's specification PDF. Absent when the library entry has none.

What they use, and what this covers

KeyWhat it is for
solarDesign.annualUsageKwhThe customer's annual consumption, from the quick bid.
solarDesign.monthlyBillThe bill the system was sized against.
solarDesign.offsetPercentThe offset the design achieves — production over usage — not the offset that was aimed at. A proposal printing the target rather than the result promises a number the array does not make.

The price

Every figure here is the pricing form applied to that system, computed by the same function the pricing screen uses. The rep and the customer read the same net price because there is only one place that works one out.

KeyWhat it is for
solarDesign.pricePerWattThe rate this job is sold at.
solarDesign.systemPriceThe system alone — price per watt × watts, before adders.
solarDesign.addersEverything added to the base system: a main panel upgrade, a tree removal, trenching.
solarDesign.salePriceWhat the job sells for — system plus adders, before any credit or deposit. This is the contract number.
solarDesign.downPaymentWhat is paid up front.
solarDesign.federalCreditPercentThe credit rate applied, e.g. 30. A number rather than a constant because it is legislated and has already changed twice.
solarDesign.federalCreditThe credit the system earns — the rate applied to the sale price.
solarDesign.federalCreditReceivedThe part the customer will actually receive, given their stated liability and carry-forward window. This is the number a net price may honestly subtract.
solarDesign.federalCreditForfeitedThe part that runs out of years and is never received. Printing this is what stops a proposal quietly over-promising.
solarDesign.federalCreditYearsThe carry-forward window used, in years. Print it beside the credit so the assumption travels with the number.
solarDesign.netPriceSale price, less the credit they will actually get, less the deposit.

The federal credit is not a rebate. federalCredit is what the system earns; federalCreditReceived is what lands. On a customer whose tax liability is smaller than the credit those are different numbers, and a proposal that advertises the first as though it were the second is the one they come back about in April.

The long-term case

Present only when a bill and a rate were captured on the quick bid — there is nothing to project against otherwise, so these keys are absent rather than zero.

KeyWhat it is for
solarDesign.firstYearSavingsWhat the system saves in year one, capped at the bill it offsets.
solarDesign.lifetimeSavingsTotal savings over the projection, with module degradation and utility escalation both applied.
solarDesign.lifetimeYearsThe term that projection covers, normally 25. Print it — a savings figure without its term means nothing.
solarDesign.paybackYearsThe year cumulative savings first cover the net price. Absent when it never pays back inside the term — that is a fact to state plainly, not a large number to imply.

The picture

KeyWhat it is for
solarDesign.imageCapturedOnThe date the design image was frozen. A proposal prints this beside the image.
solarDesign.imageView2d or 3d — which view was captured.
solarDesign.imageMatchesDesignFalse when the design has gained or lost panels since the picture was taken. An image showing 32 panels beside a price for 28 is the failure this exists to catch.

The image itself is not a key — it is placed with a solar view field bound to the design, so the platform renders it rather than the template.


customer / lead — the person, and their quote

The same contact under both names, because a residential template author writes "lead" and a commercial one writes "customer", and it is the same row either way. Pick one and use it consistently.

KeyWhat it is for
customer.nameThe person or business the proposal is addressed to.
customer.companyTheir company, where the contact has one.
customer.email · customer.phone · customer.mobilePhoneContact details for the header or the signature block.
customer.street · customer.city · customer.state · customer.postalCode · customer.countryThe primary address, flattened one level so a template writes customer.city rather than digging through an address list.
customer.statusWhere they sit in the pipeline.

The quote it hangs on

KeyWhat it is for
customer.quote.numberThe quote number. The reference everything else in the job is filed under.
customer.quote.subtotalAmountBefore discount and tax.
customer.quote.discountAmountWhat was taken off.
customer.quote.taxRate · customer.quote.taxAmountThe rate applied and what it came to.
customer.quote.totalAmountThe quote total — the value templates reach for most.
customer.quote.validUntilThe expiry date. A proposal with no expiry is a price you are still honouring next year.

products — what you sell

Live products only, ordered by name, up to 25. A proposal naming products.40.name is not a proposal.

KeyWhat it is for
products.0.nameThe product's name.
products.0.descriptionIts description, for a line item or a spec block.
products.0.costCost in dollars — money reaches a template in the units the rest of a quote uses, so a currency field never has to know which table a number came from.
products.0.idIts identifier.

financing — how it gets paid for

Only products your org can actually offer today: inactive ones, and ones a lender has withdrawn, never reach a proposal a customer could try to accept.

The cheapest option by APR is surfaced flat as well as listed, because that is the one a template reaches for and making an author write financing.options.0.apr for the common case is how a template ends up hard-coding a rate instead.

KeyWhat it is for
financing.nameThe best (lowest-APR) option's name.
financing.aprIts APR.
financing.termMonthsIts term.
financing.options.0.name · .apr · .termMonths · .minCreditScore · .idAny option by position, cheapest first. Use these to print a comparison table.

schema — questions this template asks

Anything a template needs that no source can answer is defined on the template itself and reached as schema.<key> — schema.roof_pitch, schema.hoa_name. Those become questions on the fill form.

Two halves worth keeping straight: a template may also read custom fields your org already has, and ticking one of those means the proposal reads it, not that it asks for it again. A proposal that asks for something the org already knows is a worse proposal.

Keys are lowercase with underscores, and a handful are reserved because they would be ambiguous with a real source: schema, customer, lead, quote, products, financing, solar, solardesign, org.


Sources that are declared but not yet assembled

utilityRatePlans, inventory, collections, orgFunctions and platformFunctions are part of the design and have no assembler yet. A template asking for one is told, rather than left to wonder why a field is empty.

Business functions are worth a note for when they land: a platform function exposes its signature — name, inputs, outputs — and never its expression. The proposal calls it on the server and receives only the result, which is what lets a proprietary calculation be used without being read.