Agent-assisted integration

Give this page to your coding agent. It builds both legs: the SpreadSpace workspace on your own loan page, and the receiving side, where an analyst’s Finalize lands the approved figures in your database.

Hand it to your agent

In SpreadSpace, Finalize is the analyst’s last click on a spread. It locks the spread and saves its figures as a snapshot that never changes. SpreadSpace then sends your backend a spread.finalized webhook naming that snapshot, and your backend reads the snapshot by id and stores the figures.

Your agent builds both legs of that. On the embed leg, your server mints a single-use handle for one loan and the signed-in analyst, and your loan page renders the SpreadSpace workspace from it, so the analyst works and finalizes inside your product. On the backend leg, that Finalize reaches your receiver as spread.finalized, and the snapshot’s figures are read by id into your own database and onto your loan page. When the analyst reopens the spread, spread.reopened marks your copy as under revision.

1

Save the skill

Copy the SKILL.md block below to .claude/skills/spreadspace-integration/SKILL.md (Claude Code), or paste it into AGENTS.md or your rules file (Cursor, Codex, and similar tools). It carries both legs.

2

Add the standing rules

Append the CLAUDE.md block to your own CLAUDE.md / AGENTS.md, so the rules hold on every session rather than only the one that writes the code.

3

Put the API keys in your environment

Two key shapes, both from Settings → Live API. For the receiver, a key from the Backend preset, which holds webhooks:read, webhooks:write and spreads:read, as SPREADSPACE_API_KEY. For the mint, a key from the Embed preset, which holds embed:write and the writes a session may carry, with the origin of your loan page under Allowed origins, as SPREADSPACE_EMBED_API_KEY. One key can hold both: start from the Embed preset, add webhooks:read, webhooks:write and spreads:read, and set both variables to it. A test-mode key (ss_test_…) reaches the sandbox, where the frame reaches only seeded loans and extractions are canned. That is fine for the plumbing, but a finalize there freezes sample figures, not yours.

4

Give it the prompt

Integrate SpreadSpace, both legs. Embed: add a server endpoint that mints a
SpreadSpace handle for the loan on the page and the signed-in user, and
render the SpreadSpace workspace on our loan page from it. Receive: handle
spread.finalized, read the snapshot it names by id, persist its figures
against our loan record, show them on our loan page, and handle
spread.reopened. The keys are SPREADSPACE_API_KEY and
SPREADSPACE_EMBED_API_KEY. Follow the
spreadspace-integration skill.

Your agent can also read this page directly at https://docs.spreadspace.app/get-started/agent-assisted-integration.md. Every page here has a .md twin, and the index is at /llms.txt.

SKILL.md

Save this as .claude/skills/spreadspace-integration/SKILL.md, or paste it into your agent’s rules file.

SKILL.md

The standing rules

Add this block to your own CLAUDE.md / AGENTS.md, so the rules hold on every session, not just the one that writes the code.

CLAUDE.md
1# SpreadSpace integration
2
3Follow the `spreadspace-integration` skill for anything touching SpreadSpace:
4embedding the workspace on our loan page, receiving `spread.finalized`,
5persisting the frozen figures, rendering them.
6
7Standing rules:
8
91. Never log the API key or a `whsec_…` signing secret, not in errors and not in traces.
102. The webhook receiver reads the **raw** request body bytes. Re-serialized JSON
11 never verifies.
123. Dedupe on the event id (`SpreadSpace-Event-Id`, equal to the body's `id`).
134. Persist snapshots **whole**, upserted on `snapshot_id`, which is unique.
145. The by-id snapshot read is the source of truth. Never rebuild figures from the
15 event. The event is a pointer, not the numbers.
166. The API key and the `embed_token` never reach the browser. The page gets a
17 `signed_url` and nothing else; `@spreadspace/embed` and the key stay on the
18 server.
197. Mint a handle per page load and per refresh, at the moment the page asks.
20 Never cache, reuse or pre-mint a handle or a `signed_url`; a handle is
21 exchanged once.
228. `external_user_id` comes from our own server session, never from the request
23 body or anything else the browser sends.
249. Return the `signed_url` unchanged. The component loads it verbatim.
2510. Name `scopes` explicitly on every mint: `documents:read`, `extractions:read`
26 and `spreads:read`, plus `spreads:write` only where the analyst may
27 finalize and `documents:write` only where they may upload.
2811. Register the origin of every page that holds the frame in the Embed key's
29 allowed origins before that page ships.
30
31Docs: <https://docs.spreadspace.app/llms.txt> is the index, and every page has a
32`.md` version (append `.md` to any docs URL) built for agents to read directly.

What you’ll have

  • The workspace on your loan page: your server mints a handle per load, your page renders it with <SpreadSpaceEmbed>, and refresh is handled. The API key and the token never reach the browser.
  • The loop: an analyst presses Finalize inside that frame, spread.finalized reaches your receiver, and the frozen figures are stored in your own table keyed by snapshot_id.
  • Reopen handled: spread.reopened marks that copy under revision until the next finalize arrives with a higher version.
  • “Finalized by” from your own users table, joined on finalized_by_external_user_id, the id your server named when it minted the handle. No vendor releases a person’s name to a service account.
  • Replay and rotation handled: a redelivery is a no-op, and a rotated secret verifies through its 24-hour grace window.
  • No vendor call at render time. Your loan page reads your database.

Not covered here: hosting the frame without the React component (the React embed SDK page describes the protocol module for a hand-rolled frame), and production hardening on your side (secret storage, alerting, your own retries).

Up next