> 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.

# Authentication

Every request carries an API key as a bearer token in the `Authorization`
header:

```bash
curl https://api.spreadspace.app/api/borrowers \
  -H "Authorization: Bearer ss_live_..."
```

Requests without a valid key return `401`.

## Key prefixes

One base URL serves both environments. The key prefix, not the URL, selects
where the request lands:

* **`ss_live_…`** operates on live workspace data.
* **`ss_test_…`** routes to the isolated developer sandbox (test mode), where
  uploads return premade sample extractions at no charge. Start here: sandbox
  calls never touch live borrower data.

Create, rotate, and revoke keys in the SpreadSpace dashboard: **Settings →
Live API** for live keys, **Settings → Sandbox API** for test keys.

## Scopes

Keys carry an explicit grant list checked on every request. There is no
implicit access: an API-key request to an endpoint is **denied by default**
unless the key holds the required scope. Missing scope → **403** with type
`insufficient_scope` (the message names the scope).

Format: `resource:action` (for example `documents:read`), `resource:*` for
all actions on a resource, or `*` for everything (avoid in production).

| Resource            | Actions                           | Notes                                                                                                                                                                                                                                                                            |
| ------------------- | --------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `documents`         | `read`, `write`, `delete`         | `write` = upload                                                                                                                                                                                                                                                                 |
| `loans`             | `read`, `write`, `delete`         |                                                                                                                                                                                                                                                                                  |
| `borrowers`         | `read`, `write`, `delete`         | `delete` cascades to the borrower's loans, documents and extractions                                                                                                                                                                                                             |
| `extractions`       | `read`, `write`, `edit`, `export` | `export` = single-document and bulk exports; `write` annotates an extraction (add-backs, tags, marks); `edit` corrects extracted figures (row edits). `write` and `edit` are granted to an [embed](/embed/overview) session only when the mint names them and the key holds them |
| `chart_of_accounts` | `read`, `write`                   | `read` = the workspace's [chart of accounts](/api/statement-mapping#the-chart-of-accounts) and its export map, which `extractions:read` also reads; `write` = save the export map                                                                                                |
| `spreads`           | `read`, `write`                   | `read` = a loan's [attribute snapshots](/api/spreads) and its persisted spread envelope; `write` is granted to an embed session when the mint names it, and the key must hold it to grant it                                                                                     |
| `memos`             | `read`, `render`                  | `read` = list a loan's [credit memos](/api/credit-memos) and fetch a rendered PDF link; `render` = request a render                                                                                                                                                              |
| `jobs`              | `read`                            | processing job status                                                                                                                                                                                                                                                            |
| `intake`            | `write`                           | server-mediated document intake; auto-provisions a borrower and loan per submission                                                                                                                                                                                              |
| `webhooks`          | `read`, `write`                   | `read` = list, get, deliveries; `write` = create, update, rotate, delete, replay                                                                                                                                                                                                 |
| `embed`             | `write`                           | mint embed-session tokens; **requires** the key to carry an allowed-origins list                                                                                                                                                                                                 |
| `sandbox`           | `reset`                           | wipe and reseed the test workspace; test-mode keys only                                                                                                                                                                                                                          |

Two identity reads need no scope: `GET /api/me` and `GET /api/organizations`
only describe the caller.

Each endpoint's reference page lists its required scope.

Scopes can be **added or removed on an existing key without rotating it**
(dashboard → key → scopes). The change takes effect on the next request.
Remove a scope to withdraw a specific permission while retaining the key's
other permissions.

## Key lifecycle

A key can carry an expiry (`expires_at`, set when the key is created or
changed later in the dashboard). Past it the key answers `401` exactly as a
revoked key does. Rotating a key issues a replacement and keeps the old key
working for a grace period, 24 hours unless the rotation names another value
between 0 and 720 hours, so a deploy can switch credentials without a gap.

A key can also carry an allowlist of CIDR ranges. A request from any other
address answers `403` with type `forbidden` and no further detail, and the
attempt is recorded in the workspace's audit log.

## Keeping keys secret

API keys are server-side credentials. Never ship one in browser code, a mobile
app, or a public repository: anyone holding the key can act as your
integration. If a key leaks, revoke it in the dashboard and issue a
replacement.

For rendering SpreadSpace inside your own app, use the
[Embed](/embed/overview) flow instead: the browser gets a short-lived
`ss_embed_…` session token minted by your server, and your API key stays
server-side.