Credit memos
The underwriting write-up beside the numbers, rendered to a PDF your system can file.
A credit memo is the document: the underwriting write-up an analyst authors and saves in SpreadSpace, in the workspace or inside your product through the embed. The attribute snapshot is the data from the same spread. One loan produces both: the figures your system keys on and the narrative a credit file needs.
This surface hands out metadata and finished artifacts only. A memo’s contents are never returned through the API; what you can fetch is the list, the render state, and a link to the rendered PDF.
The loop
Five operations, in the Loan Credit Memos group of the
API reference: list the memos, request a render, poll a render,
cancel a render, and fetch the PDF link. The list, the render read and the
PDF link need the memos:read scope; requesting or cancelling a render needs
memos:render.
List returns each memo’s id, name, updated_at, finalized_at,
render_state, and, for a finalized memo, the figures it was approved on
(spread_snapshots and figures_status, below):
Render answers 202 with the render. Poll it on
GET /api/loans/{loan_id}/memos/{memo_id}/renders/{render_id} until it reaches a
terminal status; when it succeeds, the PDF is available at step 3, and the
render’s links.pdf points there. Every request renders: the PDF carries the
loan’s figures as they stand when it is printed, so an unchanged memo is still
rendered fresh. A render can be cancelled while it is queued
(POST .../renders/{render_id}/cancel); once it is running it finishes in
seconds, and a cancel then answers 409.
PDF returns a short-lived download link: url, expires_in_seconds,
rendered_at, stale, and final. expires_in_seconds is a guaranteed-valid floor
of 300 seconds; the link itself lives five to ten minutes. Request again for a
fresh one. Until a render has finished, this operation answers
404. That is the normal state of a memo nobody has rendered, not an error to
retry against.
stale on that response means the same thing as in the list: the memo was
edited after this PDF was rendered. The link still resolves to the older PDF,
so decide whether to pull it or request a fresh render first.
Render after finalize
Render once the spread is finalized. Finalizing freezes the loan’s figures as
the final attribute snapshot and locks the board, so a memo rendered after
that point is a PDF of numbers that can no longer move underneath it. Render
against an open board and the analyst may change a figure a minute later, with
nothing in the PDF to say so.
A render is not pinned to a snapshot version: the PDF records what the memo
said when it was rendered, and rendered_at is what dates it. If you need the
figures themselves tied to a version, that is what the attribute snapshot’s
version and finalized_at are for.
Finalized memos
A memo finalized in SpreadSpace is locked, and its final PDF is the document of
record. The list carries finalized_at on that memo; it is null while the memo
is still open. GET /api/loans/{loan_id}/memos/{memo_id}/pdf then returns that
final PDF with final: true and stale: false, and keeps returning it however
much the loan changes afterwards. While the final PDF is still being made, or if
it could not be made, the same call answers 404.
render_state on a finalized memo describes the final PDF: rendering while it
is being made, ready once it is made, and none if it could not be made. It is
never stale.
Requesting a render of a finalized memo answers 423 with memo_locked and the
memo’s finalize time in details.locked_at. Reopen the memo in SpreadSpace to
render it again.
Two webhook events follow the same pair. memo.finalized is sent when the final
PDF is ready to pull, and memo.reopened is sent when the memo is reopened for
editing. Both carry ids and the spread_snapshots below, never the memo or a
figure, so pull the PDF from the endpoint above; see
Webhooks for the envelope and delivery rules.
The figures a memo was approved on
A finalized memo names the spread figures it was approved on. spread_snapshots
carries one entry per entity the memo’s figure exhibits cite: the final
attribute snapshot (snapshot_id), its version, and the entity (key and
name). Read the figures themselves by id with
GET /api/loans/{loan_id}/attributes/{snapshot_id}. An open memo carries no
entries, and a finalized memo with no figure exhibits carries an empty list.
Finalizing a memo freezes those figures. An entity whose spread is already
finalized is cited on that spread’s final snapshot. An entity whose spread is
still open is finalized together with the memo: its final and machine
snapshots are created at the loan’s next versions, and the analyst inputs
behind its figures (company-reported add-backs, EBITDA configurations and DSCR
recipes) refuse changes with 423 spread_locked until the memo is reopened.
The loan’s add-back sets, and the company-reported add-backs kept for the whole
loan, are held for as long as the memo is finalized, the same as while any
spread on the loan is finalized. Reopening the memo releases what the memo
finalized; an entity it only cited stays held by the spread that finalized it.
figures_status says whether those figures still stand: unchanged, or
moved once a spread the memo cites is reopened, a document its figures were
read from is re-extracted, a document is added to the loan after the memo was
finalized, or the workspace’s chart of accounts changes. It is null while the
memo is open. The final PDF stays the document
of record either way; moved says the numbers behind it are no longer the ones
on the loan.
One render at a time
Renders for a workspace run one at a time. While one is in progress a second
request is refused with 429 and Retry-After: 10, and the refusal names the
in-flight render in render_id. Wait and retry, or poll that render.
A typical render takes seconds.
Webhooks
Three events report the end of a render: memo_render.succeeded,
memo_render.failed and memo_render.cancelled. Each carries the render,
memo and loan ids plus a timestamp saying when it reached that state, and
memo_render.failed adds a reason. None of them carries the PDF: on a
success, fetch the link from the PDF endpoint above. See
Webhooks for the envelope and delivery rules.
reason, and error_code on a failed render, is one of memo_unreadable
(the memo could not be loaded: save it again and retry), render_timeout
(the render took too long), navigation_failed or render_unavailable (the
render could not start), stale_running_exceeded (the render stopped making
progress and was abandoned), or internal_error. Request the render again
after any of them.