Spreads
Finalized figures as data: the spread lifecycle and the attribute payload.
What a spread is
A spread organizes a borrower’s financial information for a loan. Analysts review it in the SpreadSpace workspace or in your application through the embed.
Finalizing a spread creates an attribute snapshot with the approved figures, periods, and source-document references. Your backend retrieves this versioned record through the API. Workspace layouts and formula definitions are not included in the snapshot.
The lifecycle
Saving changes creates a draft snapshot. Saves with unchanged values do
not create another snapshot.
Finalize is the key step. It creates the machine and final snapshots at
consecutive per-loan versions, locks the board on the final snapshot, and sends
the spread.finalized event. A locked board refuses replace, delete and a
second finalize alike with 423 spread_locked until it is reopened.
Finalize also locks the analyst inputs behind that board’s figures until the
board is reopened: a change from any spread on the loan answers the same
423 spread_locked. Company-reported add-backs, EBITDA configurations and DSCR
recipes are held per entity, for the entity the board was finalized under. The
loan’s add-back sets, and the company-reported add-backs kept for the whole
loan, are held while any spread on the loan is finalized. A board finalized
under no entity holds every scope on the loan.
The spread.finalized event is a pointer. It carries the loan, the board, both
snapshot ids and the version, but not the figures. Fetch those with the reads
below. See Webhooks for the envelope and delivery rules.
Reopen clears the lock so the board can be edited again, bumps its
version, and queues the spread.reopened webhook. That event points at the
final snapshot that was current, so a backend holding a copy can mark it
stale. The snapshots created by the finalize are kept as the loan’s history.
The next finalize creates a new version alongside them instead of replacing
them.
Statuses
Reading attributes
Three reads, all requiring the spreads:read scope, all in the Spreads
group of the API reference:
The versions list is capped at the 200 most recent snapshots and is not
paginated; fetch any one of them by id for its payload and manifest. Add
?status=final (or draft, machine) to filter it to one status. The first
row is then the current final, so backfilling a deal whose finalize predates
your integration is one call rather than listing and then filtering. The
200-row cap applies after the filter.
Each row also carries entity: the key and name the snapshot’s manifest
states, or null when it states none. On a loan that carries more than one
business or guarantor, that is how the rows are told apart without fetching
each one.
Every snapshot and summary carries snapshot_id, version (per-loan, counting
up across every status), status, created_at, and spread_board_id when one
is known. finalized_at is set on a final snapshot and is null on
machine and draft; finalized_by is set on final and machine, null
on a draft, and also null for a caller who may not see names, and a plain
API key never does. The join key a backend wants is
finalized_by_external_user_id: the external_user_id your own embed
session named for that analyst, returned to every caller because it is your
identifier, not a person’s name. It is null on drafts and when the finalize
happened in the SpreadSpace workspace or under a session that named no user.
A snapshot id belonging to another tenant or another loan answers 404, never
403. The read never confirms that a foreign id exists.
The payload
The payload states the figures. schema_version is attributes.v1.
unit is money, ratio, percent or count. A money attribute read from a
filed return carries a basis (tax or book) naming which side of the return
the figure came from; a ratio always carries one, saying where its operands came
from. Every value basis can take is listed under
Basis on the catalog page. An attribute keyed
by as-of date rather than fiscal year (an aging, a debt schedule) carries
period_kind: "as_of_date".
Values follow the value conventions: money is a
string with exactly two decimals ("754144.00", "-5644.00"), ratios and
percents are strings with at most four decimals, counts are integers, and
timestamps are RFC 3339 UTC. A period a figure has no value for reads null.
Keys are never dropped, so an absent year is visible as absence rather than as
a missing key.
The manifest
The manifest states what the payload was built from.
A payload matching the latest snapshot of the same status does not create
another version. Changes to manifest metadata alone do not create another
snapshot. builder_version is informational and may be null.
The catalog
The attribute catalog lists supported attribute and ratio names, labels, units, bases, and availability conditions.
Three groups use names based on labels an analyst typed or a return printed:
dscr_<recipe>identifies a debt-service coverage ratio saved for the business on the loan.inputs.dscr_configslists the configured recipes, including those without a result.custom_<slug>identifies an analyst-defined figure. Ratios appear inratios; aggregate money figures appear inattributes. Usecustom_visual_idas the stable identifier across label changes.personal_return_schedule_c_<business>_<line>identifies one Schedule C business on a guarantor’s return, named after the business as printed. The fixedpersonal_return_schedule_c_<line>names carry the sum across the return’s businesses only when the return prints two or more.
These names are normalized from their labels, with numeric suffixes where needed to distinguish duplicates. Read the returned keys instead of constructing them. The attribute catalog documents the naming rules.
Both groups appear in final and draft snapshots. They are not included in
the documents-only machine snapshot. Their formula definitions remain in the
workspace.
A statement whose revenue is rent alone reads as a rental property statement, and its snapshot then
carries company_reported_noi. Presence of that name is the designation: a statement with other
revenue beside its rent states company_reported_rental_income and no NOI. A snapshot finalized
under a guarantor rather than a business carries the personal_return family: the Schedule E rental
figures and, when the return files Schedule C, each business’s income block, total expenses and net
profit under its own name, with the sum across businesses when the return prints two or more.
Company-reported figures from statements attached to that person sit beside them; manifest.entity
names the scope.
Provenance
Provenance in an attribute snapshot is document-level: for each attribute, each
period’s documents entry lists the document_id and extraction_version its
figure was read from, and [] when the figure is null. That is enough to
tell a reader which filing a number came from, and to notice when a document
has been re-extracted since.
Use the workspace or embedded review panel to view a figure’s location in the source PDF.