> This page is for API.

> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://docs.spreadspace.app/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs.spreadspace.app/_mcp/server.

# spread.finalized

POST 

Fires once per finalize: an analyst finalized a spread, the `final` and `machine` attribute snapshots were created, and the board was locked. The payload carries ids, not figures. Fetch the figures from `GET /api/loans/{loan_id}/attributes/{snapshot_id}`.

Reference: https://docs.spreadspace.app/api/api-reference/webhook-events/webhook-spread-finalized

## Request

### Headers

- `SpreadSpace-Signature` (string, required) — Signature over the exact request body: `t=<seconds since the Unix epoch>,v1=<lowercase hex HMAC-SHA256 of "{t}.{body}" keyed with your endpoint's signing secret>`. Verify it before trusting the body, and reject a `t` more than five minutes from your own clock. During a secret rotation both the new and the previous secret verify for 24 hours; each delivery is signed with exactly one.
- `SpreadSpace-Event-Id` (string, required) — The event id, identical to the body's `id`. Stable across retries and replays, and shared by every endpoint one event fans out to. Delivery is at-least-once, so dedupe on it.

### Payload

- `id` (string, required) — Event id: `evt_` plus 24 lowercase hex characters. Also sent as the `SpreadSpace-Event-Id` header. Stable across retries and replays, so dedupe on it.
- `type` (enum, required) — Always this event type on this body.
  - Allowed values: `spread.finalized`
- `created` (long, required) — Seconds since the Unix epoch at which the event was created server-side. Seconds, not milliseconds. Deliveries are not ordered; reconcile on this.
- `tenant_id` (string, required) — The workspace the event belongs to. Reject a delivery whose tenant does not match the endpoint you registered.
- `livemode` (boolean, required) — `true` for live activity, `false` for test mode (an `ss_test_` key or the sandbox simulator). Branch on it to route test deliveries to a staging handler.
- `data` (SpreadFinalizedPayload, required) — The `data` object on a `spread.finalized` delivery, sent once per finalize: an analyst pressed Finalize on a saved spread board, the server minted the loan's `machine` snapshot (documents only) and then its `final` snapshot (the frozen working values), and locked the board. A pointer, not a payload: ids and the version only, no figures and no names. The frozen values are served by the authenticated `GET /api/loans/{loan_id}/attributes` (latest final) or `GET /api/loans/{loan_id}/attributes/{snapshot_id}`, where the caller's own scope and plan apply.

## Types

### SpreadFinalizedPayload

The `data` object on a `spread.finalized` delivery, sent once per finalize: an analyst pressed Finalize on a saved spread board, the server minted the loan's `machine` snapshot (documents only) and then its `final` snapshot (the frozen working values), and locked the board. A pointer, not a payload: ids and the version only, no figures and no names. The frozen values are served by the authenticated `GET /api/loans/{loan_id}/attributes` (latest final) or `GET /api/loans/{loan_id}/attributes/{snapshot_id}`, where the caller's own scope and plan apply.

- `loan_id` (string, required) — The loan whose spread was finalized.
- `borrower_id` (string, required) — The borrower that owns the loan.
- `spread_board_id` (string, required) — The saved spread board that was finalized.
- `snapshot_id` (string, required) — The `final` snapshot this finalize created.
- `machine_snapshot_id` (string, required) — The `machine` snapshot created with it: the same loan built from the documents alone, with no analyst input.
- `version` (integer, required) — The final snapshot's per-loan version number.
- `finalized_at` (datetime, required) — Server-side wall-clock time of the finalize.