> ## Documentation Index
> Fetch the complete documentation index at: https://www.finta.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Sheets

> Find spreadsheet documents, read live formulas and selected cells, and delete a document

Read the same spreadsheet documents you use in the Finta editor. Start with document and worksheet metadata, then request only the cells you need. For AI tool calls, see [Sheets MCP tools](/docs/mcp/sheets).

All HTTP paths below are relative to `/api/v1`. A **sheet** is a document with an `sht_` ID; a **worksheet** is a tab inside that document, with its own stable ID and user-facing name. The document URL opens the Finta editor. Worksheet IDs are not zero-based tab positions. The `revision` belongs to the entire document.

| HTTP operation | Reference | MCP tool | Permission |
| - | - | - | - |
| `GET /sheets` | [List sheets](/docs/api-reference/sheets/list-sheets) | `list_sheets` | Forecast: View |
| `GET /sheets/{id}` | [Retrieve sheet](/docs/api-reference/sheets/retrieve-sheet) | `get_sheet` | Forecast: View |
| `GET /sheets/{id}/cells` | [List cells](/docs/api-reference/sheets/list-cells) | `search_sheet_cells` | Forecast: View |
| `DELETE /sheets/{id}` | [Delete sheet](/docs/api-reference/sheets/delete-sheet) | `delete_sheet` | Forecast: Manage |

Existing API authentication, live company permissions, subscription/entitlement checks and rate limits still apply. API key use requires API access Manage in addition to the endpoint's Forecast permission. Use credentials for the intended company; no company ID is supplied to these operations. A sheet from another company is not exposed by supplying its ID.

## List documents and page through results

`GET /sheets` returns document summaries without any cell data. Optional `query` performs a case-insensitive document-name substring search (1–256 characters). `limit` defaults to 100 and accepts 1–500. Order is creation time descending, then internal ID descending. Pass the returned `next_cursor` unchanged and URL-encoded as `starting_after`, keeping the query unchanged. Do not derive or decode cursors, even when their current representation resembles a sheet ID. A cursor unavailable under the current company/filter returns 404. This list is not a revision-pinned workbook snapshot.

```http theme={null}
GET /api/v1/sheets?query=forecast&limit=20 HTTP/1.1
Authorization: Bearer YOUR_API_KEY

HTTP/1.1 200 OK
Content-Type: application/json

{"object":"list","url":"/api/v1/sheets","data":[{"id":"sht_example","name":"Cash forecast","url":"https://app.finta.com/sheets/sht_example","revision":3}],"has_more":false,"next_cursor":null}
```

`url` on the list envelope is the relative API collection path; `url` on each document is the absolute editor link on the configured Finta app host. Empty/final pages have `has_more: false` and `next_cursor: null`. Document summaries do not currently contain an `object` discriminator.

## Inspect a document before selecting cells

`GET /sheets/{id}` without ranges returns `id`, `name`, `url`, `revision` and `worksheets`. Each worksheet has `id`, `name`, `used_range`, `row_count` and `column_count`. `used_range` is the unqualified bounding A1 rectangle of nonempty authored cells (including formulas), or null when no such cells exist; formatting alone does not make a used range. Grid dimensions describe existing bounds, not used-data dimensions.

Read cells by repeating the literal query key `ranges[]`: `ranges[]=Plan!A1:B3&ranges[]=Plan!D1:D3`. A single `ranges` string is also accepted. For example, curl can URL-encode the query safely:

```sh theme={null}
curl --get 'https://app.finta.com/api/v1/sheets/sht_example' \
  -H 'Authorization: Bearer YOUR_API_KEY' \
  --data-urlencode "ranges[]='Plan'!A1:B2" \
  --data-urlencode 'view=both' \
  --data-urlencode 'include=charts,formats'
```

Qualified A1 selections specify the worksheet name: `'Plan'!A1:B2`. Double an apostrophe inside a quoted worksheet name: `'Bob''s Plan'!A1`. Alternatively pass a stable `worksheet_id` and an unqualified range such as `A1:B2`. An unqualified range without a worksheet ID is only unambiguous when the document has one worksheet. If both the range name and worksheet ID are supplied, they must identify the same tab. Worksheet names are labels, not positional indices.

Ranges must be bounded cells or rectangles, in ascending order and inside the current grid. Whole-column/whole-row selections such as `A:A` and `1:10` are not read-range syntax. Up to 100 selections and 10,000 selected cells total are accepted per read. Overlapping ranges each contribute their cell count. Discover the grid from metadata before requesting large selections.

The `view` enum controls the returned matrices:

* `values` (default): return calculated values for selected cells, without a formula matrix.
* `formulas`: return saved formula strings beginning with `=` and null for non-formula cells. No financial evaluation runs and no `calculation` object is returned.
* `both`: return the formula matrix alongside calculated values, allowing callers to inspect assumptions and results together.

Matrices are rectangular and row-major. A selected `A1:B2` has two rows and two entries per row. Blank cells are null in the value matrix; formula-error cells can also be null, so inspect `calculation.errors` to distinguish them. The `include` HTTP parameter is a comma-separated selection: `charts` includes embedded chart definitions on worksheets, and `formats` includes explicit formatting entries for selected cells. Both are opt-in. A chart definition is not a rendered image. Requesting formats without ranges does not retrieve all cell formats.

```json theme={null}
{
  "id": "sht_example",
  "name": "Cash forecast",
  "url": "https://app.finta.com/sheets/sht_example",
  "revision": 3,
  "worksheets": [{"id":"sheet-01","name":"Plan","used_range":"A1:B2","row_count":100,"column_count":26}],
  "ranges": [{
    "worksheet_id": "sheet-01",
    "range": "'Plan'!A1:B2",
    "values": [["Opening cash",20000],["Cash after hiring",5000]],
    "formulas": [[null,null],[null,"=B1-15000"]]
  }],
  "calculation": {"status":"complete","errors":[],"warnings":[]}
}
```

Dimensions in this example illustrate existing metadata; they are not a creation-default contract.

## Cell units and live calculation

Spreadsheet `values` are generic cell values and preserve worksheet units. A sheet amount of \$20,000 is `20000`, not `2000000`. Do not divide cell values by 100 merely because other Finta endpoints use integer `_cents` monetary fields. Formatting does not convert the underlying number. Authored whitespace-only strings remain text in calculated output rather than becoming numeric zero. This exception is limited to generic spreadsheet arrays; transactions, reports and other financial resource fields retain their cents contracts.

Selected values use the existing spreadsheet evaluator, including supported FINTA financial functions and existing authorization. Saved formulas are distinct from their results. Supported FINTA functions follow the existing sheet evaluator; a saved number stays a snapshot rather than becoming a live financial formula.

Calculation is synchronous and bounded; it does not create a pending job or a polling endpoint. Clients must inspect `calculation.status` even after HTTP 200:

* `complete`: evaluation completed without formula errors. Warnings can still be present.
* `error`: one or more formulas failed. Corresponding cells have null values and errors identify the cell and/or formula where available. Other results can still be returned.
* `unavailable`: evaluation could not complete. Value matrices are omitted, not fabricated. Readable formulas remain available with `view=both`; retry the selected GET ranges when appropriate.

Each error has `code` and `message`, with optional `worksheet_id`, `cell` and `formula`. Warnings include code/message and may include the formula and a count. In particular, `uncategorized_transactions` means uncategorized transactions may affect that financial result. Treat new error/warning codes defensively rather than failing to display the whole response. These diagnostic codes are open strings.

```http theme={null}
GET /api/v1/sheets/sht_example?ranges%5B%5D=Plan%21B2&view=both HTTP/1.1
Authorization: Bearer YOUR_API_KEY

HTTP/1.1 200 OK
Content-Type: application/json

{"id":"sht_example","name":"Cash forecast","url":"https://app.finta.com/sheets/sht_example","revision":3,"worksheets":[{"id":"sheet-01","name":"Plan","used_range":"A1:B2","row_count":100,"column_count":26}],"ranges":[{"worksheet_id":"sheet-01","range":"'Plan'!B2","formulas":[["=B1-15000"]]}],"calculation":{"status":"unavailable","errors":[{"code":"calculation_unavailable","message":"Calculation is unavailable. Retry reading the requested ranges."}],"warnings":[]}}
```

## Find authored cells

`GET /sheets/{id}/cells` requires a nonempty `query` (maximum 1,000 characters). It searches saved authored input and formula text, not evaluated financial results or displayed formatting. A request for a number will therefore not find every formula whose current result equals that number. Matching is case-insensitive:

* `contains` (default): the authored text contains the query.
* `exact`: the full authored text equals the query, ignoring case.

Omit `worksheet_id` to search every tab, or supply a stable worksheet ID to restrict the search. Results are traversed in worksheet order, then row/column order. Each match includes `worksheet_id`, `worksheet_name`, unqualified `cell` and authored string `input`. It does not include calculated values. Blank authored cells are skipped.

```http theme={null}
GET /api/v1/sheets/sht_example/cells?query=hiring&match=contains&limit=100 HTTP/1.1
Authorization: Bearer YOUR_API_KEY

HTTP/1.1 200 OK
Content-Type: application/json

{"object":"list","url":"/api/v1/sheets/sht_example/cells","data":[{"worksheet_id":"sheet-01","worksheet_name":"Plan","cell":"A2","input":"Cash after hiring"}],"has_more":false,"next_cursor":null,"revision":3}
```

Pagination accepts the same 1–500 limit, default 100. Search cursors bind the document, query, match mode, worksheet filter and document revision. Keep those filters unchanged between pages. A cursor from a different search returns 400; a document changed during pagination returns 409 `revision_conflict`. Restart from the first page without `starting_after` after inspecting the changed document; do not keep retrying a stale cursor.

## Delete the whole document safely

`DELETE /sheets/{id}?base_revision=3` requires the revision from a current read. It accepts **no request body**, including an empty JSON object. The revision is compared under a lock before deletion. A stale revision returns 409 and does not delete the document. Reread and decide whether the changed document should still be deleted; do not automatically substitute the new revision and retry a destructive action.

This permanently deletes the document and all its worksheets. It is not a way to clear a range or remove one tab. Success returns HTTP 204 with no JSON body:

```http theme={null}
DELETE /api/v1/sheets/sht_example?base_revision=3 HTTP/1.1
Authorization: Bearer YOUR_API_KEY

HTTP/1.1 204 No Content
```

The corresponding MCP tool returns a small confirmation `{"id":"sht_example","deleted":true}` after the HTTP 204. A second HTTP deletion of the missing ID returns 404; do not assume an additional 204 confirmation.

## Errors, headers and recovery

Sheets use the existing error envelope: `error.type`, `error.code`, `error.message`, `error.doc_url`, optional `error.param`, and optional `error.current_revision`. There is no revision HTTP header; use the JSON `revision` and `error.current_revision` fields. Error messages are human-readable guidance, not stable machine identifiers.

| Header | Type | Meaning |
| - | - | - |
| `Authorization` | Request string | Bearer credential on authenticated requests; existing API authentication applies. |
| `Content-Type` | Response string | `application/json` for JSON successes/errors; 204 has no response body. |
| `Retry-After` | Response integer seconds | Existing per-key burst-rate 429 response only; absent for monthly-quota 429. There is no Sheets-specific retry header. |

400 is a caller input failure, including unknown parameters, invalid range syntax/selection, unsupported `view`/`match`, too many cells/ranges, invalid limits or wrong-search cursors. Correct the request before retrying.

```http theme={null}
GET /api/v1/sheets/sht_example?view=raw HTTP/1.1
Authorization: Bearer YOUR_API_KEY

HTTP/1.1 400 Bad Request
Content-Type: application/json

{"error":{"type":"invalid_request_error","code":"invalid_request","message":"view must be values, formulas, or both.","doc_url":"https://www.finta.com/docs/api-reference/errors#invalid_request","param":"view"}}
```

404 `resource_missing` covers an absent or inaccessible document, and unavailable list cursors. Verify company context and rediscover accessible resources rather than assuming a guessed ID exists.

```http theme={null}
GET /api/v1/sheets/sht_missing HTTP/1.1
Authorization: Bearer YOUR_API_KEY

HTTP/1.1 404 Not Found
Content-Type: application/json

{"error":{"type":"invalid_request_error","code":"resource_missing","message":"Sheet not found.","doc_url":"https://www.finta.com/docs/api-reference/errors#resource_missing","param":"id"}}
```

Deletion conflicts include the current revision:

```http theme={null}
DELETE /api/v1/sheets/sht_example?base_revision=2 HTTP/1.1
Authorization: Bearer YOUR_API_KEY

HTTP/1.1 409 Conflict
Content-Type: application/json

{"error":{"type":"invalid_request_error","code":"revision_conflict","message":"The sheet has changed since it was read.","doc_url":"https://www.finta.com/docs/api-reference/errors#revision_conflict","param":"base_revision","current_revision":3}}
```

Search pagination has a separate recovery action even though it uses the same conflict code:

```http theme={null}
GET /api/v1/sheets/sht_example/cells?query=hiring&starting_after=OLD_CURSOR HTTP/1.1
Authorization: Bearer YOUR_API_KEY

HTTP/1.1 409 Conflict
Content-Type: application/json

{"error":{"type":"invalid_request_error","code":"revision_conflict","message":"The sheet changed during pagination. Start the search again.","doc_url":"https://www.finta.com/docs/api-reference/errors#revision_conflict","current_revision":3}}
```

401 and 403 preserve existing distinctions: obtain a valid credential for authentication failures, restore required company/product access for permission failures. Existing 429 `rate_limit_exceeded` uses `Retry-After`; monthly `monthly_limit_exceeded` is not retryable in the short term and deliberately omits that header. See [Usage Limits](/docs/api-reference/usage-limits) for the shared headers and retry rules.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.