Skip to navigation

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.

StepOperation
1. List what existsGET /api/loans/{loan_id}/memos
2. Ask for a PDFPOST /api/loans/{loan_id}/memos/{memo_id}/renders
2a. Poll the renderGET /api/loans/{loan_id}/memos/{memo_id}/renders/{render_id}
2b. Cancel a queued renderPOST /api/loans/{loan_id}/memos/{memo_id}/renders/{render_id}/cancel
3. Fetch the linkGET /api/loans/{loan_id}/memos/{memo_id}/pdf

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_stateMeaning
noneNever rendered.
renderingA render is in flight.
readyThe latest PDF matches the memo as saved.
staleThe memo was edited after its latest PDF was rendered.

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.