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

# Introduction

> Get started with the Finta API

The Finta API gives you programmatic access to your company's financial data: transactions and the source accounts and cards behind them, journal entries, categories, departments, automation rules, integration status, financial reports, and your team directory. Most endpoints are read-only. There are eleven narrow writes: editing one transaction, editing up to 5,000 in one bulk update, creating a manual bank or credit account, the four operations on a team invitation (create, change its access, resend it, revoke it), the three on an automation rule (create, update, delete), and starting an integration connection.

<Tip>
  To work with Finta from Claude or another AI tool, connect the [MCP server](/docs/mcp/introduction). It signs in with your Finta account instead of an API key.
</Tip>

## Get your API key

<Steps>
  <Step title="Go to API Keys">
    Sign in to [Finta](https://finta.lol) and go to **Settings > API Keys**.
  </Step>

  <Step title="Create a key">
    Click **Create API key**.
  </Step>

  <Step title="Copy the key">
    Copy the key immediately. It starts with `finta_` and is only shown once. You cannot retrieve it later.
  </Step>
</Steps>

Each API key is tied to the user who created it and scoped to a single company. There is no company ID parameter; the key already knows which company it belongs to. If you manage multiple companies, create a separate key for each.

If you are removed from a company, your key automatically loses access.

## Permissions

A key acts as its owner rather than carrying scopes of its own. Every request requires the owner to currently hold **API access: Manage**, plus the permission the endpoint requires (for example **Reports: View** for reports and journal entries, **Transactions: Manage** to edit transactions, create a manual account, or read a bulk update job, **Accounting setup: View** to read automation rules, **Team & access: Manage** for any of the invitation operations, or **Integrations: Manage** and **Transactions: Manage** to connect an integration).

Because permissions are read live on every request, granting or revoking one takes effect on the very next call. There is nothing to reissue. See [Permissions](/docs/api-reference/errors#permissions) for the full endpoint-to-permission table and the `403` you get when something is missing.

## Base URL

All requests go to:

```
https://finta.lol/api/v1
```

## Environments

There is no sandbox or test environment. Every request runs against your real company data, and every response reflects live production data. Write requests, such as categorizing a transaction, modify your live books.

## Authentication

Include your API key in the `Authorization` header as a Bearer token:

```bash theme={null}
curl https://finta.lol/api/v1/company \
  -H "Authorization: Bearer finta_your_key_here"
```

### Key prefix convention

Every Finta credential is prefixed so it can be recognized at a glance in logs, error messages, and secret scanners. Today there is one credential type and its prefix is `finta_`. As additional credential or token types are introduced (for example restricted keys or webhook signing secrets), each will have its own distinct prefix that stacks on the brand prefix (e.g. `finta_<type>_...`). Treat the prefix as load-bearing: do not strip it before sending, and do not assume a missing or unknown prefix is still a Finta credential.

## Content type

All responses are returned as JSON. List and report filters are passed as query strings. Write endpoints accept JSON request bodies.

## Pagination

List endpoints (`/accounts`, `/cards`, `/transactions`, `/journal_entries`, `/parties/merchants`, and `/rules`) use cursor-based pagination. Responses are wrapped in a list envelope:

```json theme={null}
{
  "object": "list",
  "url": "/api/v1/transactions",
  "has_more": true,
  "next_cursor": "txn_h8i9j0k1l2m3n4",
  "data": [...]
}
```

Pass `limit` (default 100, max 500) to control page size, and `starting_after` with the `next_cursor` value to fetch the next page. Treat `next_cursor` as opaque and pass it back unchanged. There is no offset or page-number parameter. The `url` field carries the canonical path of the collection and is useful for logging and generic pagination helpers.

`/categories`, `/departments`, and `/integrations` are list endpoints too, but their result sets are small and bounded, so they always return everything in one response and omit `has_more` and `next_cursor` entirely.

`/team` is not a list endpoint at all. It returns a single team document with its own `members` and `invitations` arrays and no list envelope, so there is no `object: "list"`, `url`, or `data` to read.

If you keep a local copy of transactions, `GET /transactions` also has an incremental sync mode: pass `updated_after` and it returns only what changed since your last run, including deletions, plus a `watermark` to sync from next time. See [Incremental Sync](/docs/api-reference/incremental-sync).

See [Pagination](/docs/api-reference/pagination) for full parameters and an example fetch-all loop.

## Monetary amounts

Every monetary field in the API follows two non-negotiable rules:

1. **Integer cents.** Monetary values are integers, never floats and never formatted strings. `\$499.00` is `49900`. `\$1,500.00` is `150000`. Divide by 100 to get dollars.
2. **`_cents` suffix.** The field name always ends in `_cents` (e.g. `amount_cents`, `balance_cents`, `total_cents`). If a field name does not end in `_cents`, it is not a monetary value.

There are no exceptions and no "summary" or "display" sibling field that returns the same amount in dollars or as a string. If you encounter a field that appears to hold a monetary value but does not end in `_cents`, or whose value is not an integer, treat it as a bug and report it.

**Sign conventions:**

* **Income statement**: revenue/income amounts are positive, expense amounts are negative. Summing every section's `total_cents` yields net income without sign-flipping.
* **Balance sheet**: `balance_cents` carries the natural-sign cumulative balance for that account at the report date.
* **Cash flow**: `amount_cents` is positive for cash inflows and negative for cash outflows.

## Errors

The Finta API uses conventional HTTP status codes and returns every error in a consistent JSON envelope. Branch on `error.type` and `error.code` to handle errors programmatically; treat `error.message` as human-readable only and do not parse it.

```json theme={null}
{
  "error": {
    "type": "invalid_request_error",
    "code": "parameter_missing",
    "message": "Missing required parameter: start_date.",
    "param": "start_date",
    "doc_url": "https://finta.lol/docs/api-reference/errors#parameter_missing"
  }
}
```

| Status | Description |
| - | - |
| `200` | Success. |
| `201` | Created. A new record was saved. Returned by `POST /team/invitations` (note that its `changed` flag is `false`; the status code is what tells you the record is new), by `POST /rules` (where it confirms the rule is saved, not that historical application has finished), by `POST /integrations/{key}/connect` (a new connect request; calling again while one is open returns it with `200`), and by `POST /accounts` (a new manual account; a matching manual account that already exists is returned with `200`). |
| `202` | Accepted. Returned only by `POST /transactions/bulk/update`: the bulk update was accepted as a job, not yet carried out. Read the job at the `Location` header for its outcome. |
| `204` | No content. The request succeeded and there is no response body. Returned only by `DELETE /team/invitations/{id}` and `DELETE /rules/{id}`, including when the record was already gone. |
| `400` | Bad request. A required parameter is missing or invalid. |
| `401` | Unauthorized. The bearer credential is missing, malformed, or unrecognized. The fix is to obtain a valid API key. |
| `403` | Forbidden. The API key is valid, but the caller does not have permission to access the resource (deactivated user, removed from company, closed company, expired subscription, or a missing product-area permission). The fix is to regain access, not to get a new key. |
| `404` | Not found. The endpoint path does not exist, or a requested resource is missing, hidden, or unsupported for that operation. |
| `409` | Conflict. Returned by `POST /rules` and `PATCH /rules/{id}` when the definition exactly matches an existing rule; the error message names that rule's ID. Also returned by `POST /integrations/{key}/connect` when the integration is already connected or another user holds its open connection link, and by `POST /transactions/bulk/update` when its `Idempotency-Key` was already used with a different body. |
| `422` | Unprocessable entity. The request was syntactically valid, but a business validation rejected the change. |
| `429` | Rate limited. Either the per-minute burst limit (retryable, with `Retry-After`) or the monthly per-company call limit (not retryable in the short term, no `Retry-After`). Branch on `error.code` to distinguish the two. |
| `5xx` | Server error. Something went wrong on our end. Nine cases carry a stable code to branch on. On the invitation endpoints: `invitation_create_failed`, `permissions_update_failed`, `invitation_resend_failed`, and `invitation_revoke_failed`, all safe to retry except the resend, which sends another email each time. On the rules endpoints: `rules_not_ready` and `rule_busy` (both `503`) and `rule_deletion_failed` (`500`), all retryable with backoff. On `POST /integrations/{key}/connect`: `connect_link_failed` (`500`), retryable with backoff. On `POST /accounts`: `account_create_failed` (`500`), retryable with the same body. |

See [Errors](/docs/api-reference/errors) for the full list of error codes with resolution steps.

## Making your first request

Verify your API key by pulling your company's metadata:

```bash theme={null}
curl https://finta.lol/api/v1/company \
  -H "Authorization: Bearer finta_your_key_here"
```

```json theme={null}
{
  "id": "comp_a1b2c3d4e5f6g7",
  "object": "company",
  "name": "Acme Corp",
  "legal_name": "Acme Corp Inc.",
  "entity_type": "c_corp",
  "federal_ein_last4": "6789",
  "incorporation": {
    "date": "2022-10-21",
    "state": "DE"
  },
  "legal_address": {
    "line_1": "548 Market Street",
    "line_2": "PMB 39381",
    "city": "San Francisco",
    "state": "CA",
    "postal_code": "94104",
    "country": "US"
  },
  "created": 1688053841
}
```

The full schema, including all field types and enum values (e.g. the closed set of `entity_type` values), is in the [Retrieve Company reference](/docs/api-reference/company/retrieve-company).

The `id` is included so you can cross-reference the company from other API responses, and as the disambiguator for the planned multi-company-keys feature; the endpoint is a singleton, so there is no `GET /v1/company/{id}`.

From here, try pulling one [category total](/docs/api-reference/aggregations/retrieve-total), your [income statement](/docs/api-reference/reports/retrieve-income-statement), or the [journal entries](/docs/api-reference/journal-entries/list-journal-entries) behind a report. [`GET /integrations`](/docs/api-reference/integrations/list-integrations) is another good first call: it takes no parameters and tells you whether the data behind everything else is still flowing. For integrations it marks `api_connectable: true`, [`POST /integrations/{key}/connect`](/docs/api-reference/integrations/connect-integration) returns a link a person opens to connect or reconnect it. [`GET /team`](/docs/api-reference/team/retrieve-team) also takes no parameters and returns the company's members and pending invitations, and [`POST /team/invitations`](/docs/api-reference/team/create-invitation) adds a new one. A pending invitation can then be changed with [`PATCH /team/invitations/{id}`](/docs/api-reference/team/update-invitation), sent again with [`POST /team/invitations/{id}/resend`](/docs/api-reference/team/resend-invitation), or withdrawn with [`DELETE /team/invitations/{id}`](/docs/api-reference/team/revoke-invitation). The company's categorization automations are readable and writable too: [`GET /rules`](/docs/api-reference/rules/list-rules) lists them, and [`POST /rules`](/docs/api-reference/rules/create-rule) saves a new one, optionally applying it to existing transactions. To understand how journal entries, transactions, aggregations, and reports fit together, see [Data Model](/docs/api-reference/data-model).


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