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

# Update onboarding

> Saves answers to the onboarding questions, asks Finta to decide, and sets whether Finta
emails the user when their books are ready. Returns the same object as
`GET /onboarding`.

- Only the answers you send change. Use what you can already reach (chat, local files,
  connected tools), within the permissions they've given you, to prefill sourced answers;
  name each source and confirm them together. Ask only
  what's missing, two or three related questions at a time; save quietly. Never guess
  without a source; flag conflicts and ask.
- One invalid answer, or an unknown field, rejects the whole request and saves nothing
  (`400` `invalid_request`, with `param` naming it).
- `submit: true` asks Finta to decide, which it does only once no required question is
  unanswered. If any is, the valid answers sent with the request are still saved and the
  response is `400` `answers_incomplete`, with the missing answer keys in `missing`.
- Finta's decision is final. Afterwards the eligibility answers can't change
  (`409` `onboarding_locked`); while Finta needs a call, the call follow-ups
  (`incorporation_year`, `accounting_software`, `files_taxes_with`, `goals` and
  `subsidiary_countries`) still can. Sending an answer that matches what's saved isn't a
  change, so repeating a request that already went through, submit included, returns
  `200` with the current state and changes nothing.
- `notify_when_synced: true` is the web app's "Email me when it's ready": Finta emails the
  user who sent it when the first sync finishes, or right away if it already has.
  `false` withdraws it. It can change until onboarding is complete, once at least one
  question is answered. Offer it at the import wait step once banks are connected, not
  during the questionnaire; honor a preference the user brings up at any time.
- Once the company is onboarded, every request returns `409` `onboarding_complete`.

Needs Company: Manage and Integrations: Manage. This endpoint is free: it doesn't count
toward the monthly API limit and keeps answering after that limit is reached.




## OpenAPI

````yaml /openapi.yaml patch /onboarding
openapi: 3.0.3
info:
  title: Finta API
  version: '1.0'
  description: >
    The Finta API provides programmatic access to your company's financial data,

    including transactions, journal entries, categories, financial reports,
    sheets, and the team directory.


    ## Authentication


    Each API key is scoped to a single company. There is no company ID
    parameter.

    The key already knows which company it belongs to. If you have access to
    multiple

    companies, create a separate key for each.


    A key acts as its owner; it does not have a separate permission snapshot.
    The owner

    must currently have **API access: Manage**, plus the permission required by
    the endpoint:


    | Endpoint | Required permission |

    |----------|---------------------|

    | `GET /sheets`, `GET /sheets/{id}`, `GET /sheets/{id}/cells` | Forecast:
    View |

    | `POST /sheets`, `PATCH /sheets/{id}`, `DELETE /sheets/{id}` | Forecast:
    Manage; existing sheet entitlements apply |

    | `GET /company` | Company: View |

    | `GET /onboarding`, `PATCH /onboarding` | Company: Manage and Integrations:
    Manage, as onboarding needs in the web app |

    | `GET /taxes`, `GET /taxes/{id}` | Taxes: View |

    | `POST /files`, `POST /file_uploads`, `POST /taxes/income_uploads`, `POST
    /taxes/franchise_uploads` | Taxes: Manage |

    | `GET /team` | Team & access: View |

    | `DELETE /team/invitations/{id}` | Team & access: Manage; target-management
    limits apply. No additional Growth/RBAC gate. |

    | `POST /team/invitations/{id}/resend` | Admin role required. No additional
    Growth/RBAC gate. |

    | `PATCH /team/invitations/{id}` | Team & access: Manage; RBAC and
    active/trialing Growth required, with grant and target limits. |

    | `POST /team/invitations` | Admin role required; requested access must also
    be allowed by the plan. |

    | `GET /categories`, `GET /departments`, `GET /rules`, `GET /rules/{id}` |
    Accounting setup: View |

    | `GET /tags` | Accounting setup: View; early access |

    | `POST /tags`, `PATCH /tags/{id}`, `DELETE /tags/{id}` | Accounting setup:
    Manage; early access |

    | `POST /categories` | Accounting setup: Manage; some templates also need
    the Startup plan, and some only Finta adds |

    | `POST /rules` | Accounting setup: Manage; applying to existing
    transactions (`apply_to_existing_transactions`, default true) also requires
    Transactions: Manage |

    | `PATCH /rules/{id}` | Accounting setup: Manage; Transactions: Manage is
    not required |

    | `DELETE /rules/{id}` | Accounting setup: Manage and Transactions: Manage,
    including absent retries |

    | `GET /integrations` | Integrations: View |

    | `GET /tax_credits`, `GET /tax_credits/{id}` | Taxes: View |

    | `GET /reports/*`, `POST /reports/exports` | Reports: View |

    | `GET /accounts`, `GET /cards`, `GET /transactions`, `GET
    /transactions/{id}`, `GET /transactions/splits`, `GET /spreads` |
    Transactions: View |

    | `GET /forms/1099`, `GET /forms/1099/{id}` | Taxes: View |

    | `POST /transactions/bulk/update`, `GET /jobs/{id}` | Transactions: Manage
    |

    | `PATCH /transactions/{id}`, `POST /transactions/{id}/split`, `PATCH
    /transactions/{id}/split`, `DELETE /transactions/{id}/split`, `POST
    /accounts`, `POST /transaction_uploads`, `POST /transfers`, `DELETE
    /transfers/{id}` | Transactions: Manage |

    | `GET /journal_entries`, `GET /journal_entries/{id}`, `GET
    /aggregations/total`, `GET /aggregations/totals`, `GET /parties/merchants` |
    Reports: View |

    | `GET /invoices`, `GET /invoices/{id}` | Invoices: View |

    | `POST /invoices`, `POST /invoices/{id}/void` | Invoices: Manage |

    | `POST /invoices/{id}/match`, `POST /invoices/{id}/unmatch`, `POST
    /transactions/{id}/match_invoices` | Invoices: Manage and Transactions:
    Manage |


    Permission changes apply to the next request. Removing API access
    permanently revokes

    the owner's active keys for that company; restoring access requires creating
    a new key.


    Authenticate by including your API key in the `Authorization` header:


    ```

    Authorization: Bearer finta_...

    ```


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


    ## Onboarding


    A company starts using Finta by onboarding: it answers a short
    questionnaire, Finta decides

    whether it can take the company on, the company connects the banks and cards
    it selected, and

    Finta syncs them for the first time. Until the company is onboarded, every
    endpoint returns

    `403 Forbidden` with `type: permission_error` and `code:
    onboarding_incomplete`, except these:


    | Endpoint | Why |

    |----------|-----|

    | `GET /onboarding`, `PATCH /onboarding` | Onboarding itself |

    | `GET /integrations` | To see the banks and cards to connect |

    | `POST /integrations/{key}/connect`, `GET /integrations/{key}/connect` | To
    connect them, only once Finta has approved the company (`onboarding_status`
    `connect_banks` or `syncing`) |

    | `POST /team/invitations` | To invite the teammate who can approve a
    connection, such as a Brex account admin |

    | `POST /feedback` | To write to Finta support |


    The error's `onboarding_status` says where the company is (the `status` of
    `GET /onboarding`):


    ```json

    {
      "error": {
        "type": "permission_error",
        "code": "onboarding_incomplete",
        "message": "This company hasn’t finished onboarding with Finta, so this endpoint isn’t available yet. Call GET /api/v1/onboarding and follow its next_step.",
        "doc_url": "https://www.finta.com/docs/api-reference/errors#onboarding_incomplete",
        "onboarding_status": "connect_banks"
      }
    }

    ```


    Call `GET /onboarding` and follow its `next_step` until its `status` is
    `complete`. A company

    Finta needs a call with (`call_required`) or can't onboard (`not_eligible`)
    stays here, as it

    does in the web app. Nothing counts toward the monthly limit until the
    company is onboarded.


    Connecting banks is part of onboarding, but only after Finta approves the
    company, as in the

    web app: a bank connected earlier would sync outside onboarding, and
    onboarding's first sync

    would never start. Before approval, both connect endpoints return
    `onboarding_incomplete`

    with a message to finish the questionnaire first. `GET /integrations`
    answers throughout.


    ## Rate Limits


    The API enforces two independent limits. Both surface as `429 Too Many
    Requests`, but they are distinct error codes with different retry guidance.


    ### Per-minute burst limit


    Authenticated requests are limited to **6,000 requests per 60 seconds** (100
    per second) per API key. Unauthenticated requests (missing or invalid key)
    are limited to **120 requests per 60 seconds** per IP address.


    The window is **fixed**, not rolling. Each 60-second wall-clock interval is
    its own counter; all requests within that interval share it, and the counter
    resets to 0 in a single step at the next boundary. Available budget jumps
    from `0` back to the full bucket size (`6000` for authenticated API keys,
    `120` for unauthenticated IP buckets) instantaneously at the boundary,
    rather than aging out one slot at a time. Trust `X-RateLimit-Reset` for the
    exact reset timestamp.


    Successful responses and burst-limit rejections include the following
    headers.

    Do not assume they are present on other errors: early authentication,
    authorization,

    and monthly-limit rejections can omit them. This describes existing header
    behavior,

    not a new quota policy.


    | Header | Description |

    |--------|-------------|

    | `X-RateLimit-Limit` | Maximum requests per window (`6000` for
    authenticated requests, `120` for unauthenticated). |

    | `X-RateLimit-Remaining` | Requests remaining in the current window. |

    | `X-RateLimit-Reset` | Unix timestamp when the window resets. |


    On a 429 for this case, an additional header is included:


    | Header | Description |

    |--------|-------------|

    | `Retry-After` | Number of seconds until the next request is safe. |


    The error body is `type: rate_limit_error` / `code: rate_limit_exceeded`.


    **Retry guidance:** This case is retryable. Honor `Retry-After` as the
    minimum wait, then apply exponential backoff with jitter for any retries
    beyond the first (cap at a few minutes; abandon after a small number of
    attempts to avoid retry storms). Do not retry tighter than `Retry-After`.


    ### Monthly per-company limit


    Each company has a monthly cap on total API calls, independent of the
    per-minute burst:


    | Plan | Monthly cap |

    |------|-------------|

    | Formation | 10 |

    | Startup | 300 |

    | Growth | 30,000 |

    | Enterprise | Unlimited |


    Enterprise is enabled internally by Finta for contract-managed companies. It
    bypasses

    commercial monthly API/MCP quotas and ordinary subscription lockouts, even
    when the

    Stripe subscription is absent or canceled. Requests and MCP tool calls are
    still counted.

    Enterprise does not bypass valid credentials, company/user permissions,
    company closure,

    request validation, payload bounds, or per-minute abuse limits. Disabling
    Enterprise restores

    ordinary plan gates using the current billing state; it does not change
    Stripe billing.


    Nothing counts until the company finishes onboarding, and `GET /onboarding`
    and `PATCH /onboarding`

    never count.


    Counts reset at **midnight Pacific Time (US & Canada)** on the 1st of each
    month. This is the Finta application's configured time zone; the cap is
    computed in that zone, not in UTC. Consumers in other time zones should
    convert the local-midnight Pacific boundary to their own clock; note that
    the absolute UTC offset shifts by one hour twice a year for daylight saving
    (PST is UTC-8, PDT is UTC-7). Blocked requests are not counted toward the
    limit. The error body is `type: limit_error` / `code:
    monthly_limit_exceeded`, and the `message` field includes the reset date in
    human-readable form.


    **Retry guidance:** This case is **not retryable in the short term.** No
    `Retry-After` header is sent, deliberately, because the only meaningful
    remediation is to upgrade the plan (Settings -> Plans at app.finta.com) or
    wait until the 1st of the next month. Naive retry loops should branch on
    `error.code` and stop retrying when they see `monthly_limit_exceeded`. SDKs
    that auto-retry on 429 should look at `error.code` (or the absence of
    `Retry-After`) before re-issuing.


    A temporary company limit override, set by Finta support for the current
    month, may change

    the allowance and the wording of the monthly-limit message. It applies to
    every user and

    API key in the company. The error code and no-short-term-retry rule remain
    unchanged.


    ## Pagination


    List endpoints use cursor-based pagination. Pass `limit` to control page
    size

    (default 100, max 500). To fetch the next page, pass `starting_after` with
    the

    `next_cursor` value from the previous response. Responses include `object:
    "list"`,

    `url` (the canonical path of the collection, relative to the API host),
    `has_more`

    (whether more results exist), `next_cursor` (an opaque value to pass
    unchanged as `starting_after`),

    and `data` (the page of items).


    ## Reporting dates and freshness


    Reports and category totals use calendar dates in **America/Los_Angeles
    (Pacific Time)**,

    including defaults such as today and the current quarter. Periodic requests
    include both

    `start_date` and `end_date` exactly. Point-in-time requests include activity
    through the

    exact `date`. Response dates identify the boundaries actually used, not
    rounded months.


    Whole months read whole-month rollups. The current month's first day through
    today in

    Pacific Time reads month-to-date (MTD) rollups when fresh. Other
    partial-month boundaries,

    including a midmonth start, read raw journal entries for just those partial
    months and are

    slower; any whole months in the same request still use rollups. Stale or
    unfilled MTD

    rollups safely fall back to raw entries. Whole-month requests and
    month-aligned

    month-start-to-today or year-to-date requests stay on the fast rollup path
    when MTD is fresh.


    Fresh MTD must end at exactly the requested cutoff. If a refresh advances
    the rollup

    across Pacific midnight during a request, exact live entries preserve the
    original

    cutoff; later-day MTD is never included in that answer.


    `refreshed_at` is a Unix timestamp covering the entire report, total, or
    grouped page,

    including partial months. For rollup-only reads it is the maximum
    contributing rollup

    timestamp, including MTD. Any live raw-entry portion is current as of the
    call, even when

    no raw entries match. A fresh MTD row contributes its timestamp even when it
    contains zero

    activity through today; future-only merchants do not appear as empty
    merchant groups.

    A grouped page covers its returned groups; a later month's refresh does not
    advance an

    earlier monthly page's timestamp.

    It is null only when no contributing timestamp or live raw read is

    available. Rollup-backed activity may lag newly imported or edited entries.


    ## Amounts


    Financial resource fields follow these two rules. Generic spreadsheet cell
    arrays are

    a scoped exception, described below:


    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. This avoids floating-point precision errors in financial
    calculations.

    2. **`_cents` suffix.** The field name always ends in `_cents` (e.g.
    `amount_cents`, `balance_cents`, `total_cents`, `net_income_cents`,
    `change_in_cash_cents`, `cash_cents`). If a field name does not end in
    `_cents`, it is not a monetary value.


    These rules apply to monetary resource fields (transactions, journal
    entries, income statement,

    balance sheet, cash flow). There is no "summary" or "display" sibling field
    that returns

    the same financial-resource amount in dollars or as a string.


    **Spreadsheet exception:** `/sheets` range `values` are generic spreadsheet
    cells, not

    financial-resource amount fields. They preserve the existing sheet engine's
    units: for

    example, a sheet amount of $20,000 is entered as `20000`, not `2000000`.
    Formatting does

    not trigger a cents conversion. Formula results use the existing spreadsheet
    evaluator

    and FINTA behavior. Do not apply the financial-resource cents convention to
    cell arrays.


    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


    Errors return a consistent JSON structure:


    ```json

    {
      "error": {
        "type": "invalid_request_error",
        "code": "resource_missing",
        "message": "The requested resource was not found.",
        "doc_url": "https://www.finta.com/docs/api-reference/errors#resource_missing"
      }
    }

    ```


    ### Status codes


    | Status | Meaning |

    |--------|---------|

    | `200 OK` | Request succeeded. |

    | `201 Created` | A new resource was created, such as an invitation, an
    account, or a transaction upload draft. |

    | `400 Bad Request` | Request was malformed or had invalid parameters. |

    | `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. The fix is to regain the required company
    or product-area access. See the `Forbidden` response component for the
    specific codes. |

    | `404 Not Found` | The requested resource, or the endpoint itself, does not
    exist. Unknown or renamed paths (for example an old hyphenated report path
    like `/reports/income-statement` instead of `/reports/income_statement`)
    return this same envelope with `type: invalid_request_error` and `code:
    resource_missing`, as JSON, regardless of the `Accept` header. |

    | `409 Conflict` | The request conflicts with the resource's current state,
    for example changing an onboarding answer after Finta decided. |

    | `422 Unprocessable Entity` | Invitation data failed validation, for
    example an invalid email or a conflicting invitation or existing teammate. |

    | `429 Too Many Requests` | Either the per-minute burst rate limit
    (retryable, with `Retry-After`) or the monthly per-company API call limit
    (not retryable in the short term, no `Retry-After`). Branch on `error.code`
    to distinguish the two and avoid retry storms on monthly exhaustion. See the
    Rate Limits section for the full retry guidance. |

    | `5xx` | An unexpected error on Finta's side. Retry with exponential
    backoff. |


    The `error.type` and `error.code` fields are stable identifiers safe to
    switch on programmatically. The `error.message` is human-readable and may
    change without notice.


    ### Overdue billing invoices


    A company with an unpaid billing invoice explicitly linked by Finta loses
    access when

    that invoice's due date ends in America/Los_Angeles, independently of its
    subscription

    or plan. Every API endpoint then returns `403 permission_error` with code

    `invoice_overdue`, before running the endpoint or changing data. Pay all
    overdue linked

    invoices at app.finta.com or contact support@finta.com; replacing the API
    key or buying

    another plan does not resolve this refusal. There is no payment-processing
    grace period:

    payment must have settled and Stripe must mark each overdue invoice paid. A
    linked invoice only

    counts while its corresponding Enterprise product is enabled.


    Unpaid status can be cached for up to 60 seconds. Access returns
    automatically within

    a minute after every overdue linked invoice is paid. Paid status is final.
    Companies with no

    linked invoices do not perform this payment-status check.

    Amounts in the human-readable message reflect the unsettled balance after
    partial

    payments. Whole-dollar amounts omit decimal places; non-zero cents remain
    exact.

    Only invoice status paid clears an overdue invoice.

    The lock is not latched: when an overdue invoice is paid and the only
    remaining

    unpaid invoice is not due yet, access resumes until that later invoice
    misses its cutoff.


    If payment status cannot be verified after the due-date cutoff, every
    endpoint can

    instead return `503 api_error` with code `invoice_status_unavailable` and

    `Retry-After: 60`. Retry after that interval, then use bounded exponential
    backoff if

    the service remains unavailable. This response never treats an unknown
    payment as paid.

    A Stripe outage before the cutoff does not refuse access for this reason.


    MCP connections remain connected, but every tool call is refused for these
    same

    reasons, including tools that normally do not consume the monthly allowance.
    A refused

    tool result has `isError: true`, uses the API's message, and is not counted
    against the

    monthly allowance. Its transport remains HTTP 200; a temporary
    payment-status failure

    includes `Retry-After: 60` on that response.


    ### Early access endpoints


    Tags (`GET /tags`, `POST /tags`, `PATCH /tags/{id}`, `DELETE /tags/{id}`)
    and transaction `tag_id` writes and filters are in early access. Transaction
    `tag_id` and `tag_name` are null without access.


    Some endpoints are in early access: documented here, but turned on per
    company while they roll

    out. For a company that doesn't have one yet, every request to it returns
    `403 Forbidden` with

    `type: permission_error` and `code: feature_disabled`, ahead of the
    endpoint's own permission

    check, and changes nothing:


    ```json

    {
      "error": {
        "type": "permission_error",
        "code": "feature_disabled",
        "message": "This feature isn’t turned on for this company yet. Contact Finta to request access.",
        "doc_url": "https://www.finta.com/docs/api-reference/errors#feature_disabled"
      }
    }

    ```


    It is not retryable: contact Finta to request access for the company, then
    retry. Once

    the feature is on for the company the endpoint works normally, with no
    change to requests.
servers:
  - url: https://app.finta.com/api/v1
    description: Production
security:
  - bearerAuth: []
tags:
  - name: Onboarding
    description: Create a Finta account through an agent and verify the user's email
  - name: Sheets
    description: >
      Create, read, edit and delete spreadsheet documents, worksheets, cell
      ranges and embedded charts.

      Existing Sheets access includes tag-filtered financial formulas, including
      Other, without

      separate Dashboard, Transactions or Accounting settings access. API calls
      still require

      API access: Manage; reads require Forecast: View and mutations require
      Forecast: Manage,

      with existing company, subscription, financial authorization and
      tag-feature checks.

      Existing web link sharing requires Forecast: Manage and the existing
      sharing entitlement;

      the sharing owner's current access and revocation checks remain
      authoritative. Guests

      can evaluate authorized saved formulas, not arbitrary financial queries or
      the full tag

      catalog. This adds no public sharing or tag-management endpoint.
  - name: Onboarding
    description: >-
      Answer the onboarding questionnaire, follow Finta's decision, and connect
      the company's banks until it's onboarded
  - name: Company
    description: Retrieve company metadata
  - name: Plans & billing
    description: >-
      The plans Finta offers, what the company pays, and how much of each plan
      limit it has used.
  - name: Team
    description: Retrieve company members and manage invitations
  - name: Categories
    description: List your chart of accounts categories and add Finta's standard ones
  - name: Rules
    description: Company automation rule definitions.
  - name: Departments
    description: List the departments available to the authenticated company
  - name: Tags
    description: >-
      Company-defined transaction labels managed in Settings that break
      categories down further, such as Vercel and Webshare under Infrastructure.
      Each transaction has at most one tag; untagged amounts appear as Other.
      Tags do not change the books, taxes or reports. Early access.
  - name: Integrations
    description: List the authenticated company's integrations and their connection status
  - name: Inbox
    description: >-
      What Finta needs from the company, from its Finta inbox, and how each item
      gets done
  - name: Aggregations
    description: >-
      Compute totals for one category and its descendants, as a single figure or
      grouped by merchant or month
  - name: Transactions
    description: >
      Transactions are what your bank shows you: a single line like "AWS charged
      you $499."

      Most API consumers want transactions. For accounting-level detail, see
      Journal Entries.


      Amounts are in cents (e.g. `amount_cents: 49900` = $499.00).
  - name: Journal Entries
    description: >
      Journal entries are the accounting records that transactions create. A
      single $499 AWS

      charge becomes two journal entries: debit Software $499, credit Cash $499
      (double-entry

      bookkeeping). Use journal entries when you need accounting-level detail.


      Amounts are in cents (e.g. `amount_cents: 49900` = $499.00).
  - name: Invoices
    description: >
      Invoices the company sent, and the bank deposits that paid them. Recording
      an invoice books

      its revenue; Finta doesn't send invoices to customers.


      Amounts are in cents (e.g. `amount_cents: 49900` = $499.00).
  - name: Parties
    description: Discover observed counterparties for category-scoped financial queries.
  - name: Forms
    description: Discover vendor compliance filing records and yearly progress.
  - name: Reports
    description: >
      Financial statements: income statement, balance sheet, and cash flow. Each
      report

      returns the complete statement for a single period. You cannot filter to
      one category

      or request multiple periods in one call.
  - name: Feedback
    description: Send questions, feedback and bug reports to Finta support
  - name: Tax Credits
    description: Credit amounts and claim progress by type, jurisdiction, and tax year
  - name: Taxes
    description: >-
      Discover income-tax and Delaware franchise-tax filing records and
      available PDFs.
  - name: Files
    description: Upload the PDFs that tax uploads attach to the company's tax records.
paths:
  /onboarding:
    patch:
      tags:
        - Onboarding
      summary: Update onboarding
      description: >
        Saves answers to the onboarding questions, asks Finta to decide, and
        sets whether Finta

        emails the user when their books are ready. Returns the same object as

        `GET /onboarding`.


        - Only the answers you send change. Use what you can already reach
        (chat, local files,
          connected tools), within the permissions they've given you, to prefill sourced answers;
          name each source and confirm them together. Ask only
          what's missing, two or three related questions at a time; save quietly. Never guess
          without a source; flag conflicts and ask.
        - One invalid answer, or an unknown field, rejects the whole request and
        saves nothing
          (`400` `invalid_request`, with `param` naming it).
        - `submit: true` asks Finta to decide, which it does only once no
        required question is
          unanswered. If any is, the valid answers sent with the request are still saved and the
          response is `400` `answers_incomplete`, with the missing answer keys in `missing`.
        - Finta's decision is final. Afterwards the eligibility answers can't
        change
          (`409` `onboarding_locked`); while Finta needs a call, the call follow-ups
          (`incorporation_year`, `accounting_software`, `files_taxes_with`, `goals` and
          `subsidiary_countries`) still can. Sending an answer that matches what's saved isn't a
          change, so repeating a request that already went through, submit included, returns
          `200` with the current state and changes nothing.
        - `notify_when_synced: true` is the web app's "Email me when it's
        ready": Finta emails the
          user who sent it when the first sync finishes, or right away if it already has.
          `false` withdraws it. It can change until onboarding is complete, once at least one
          question is answered. Offer it at the import wait step once banks are connected, not
          during the questionnaire; honor a preference the user brings up at any time.
        - Once the company is onboarded, every request returns `409`
        `onboarding_complete`.


        Needs Company: Manage and Integrations: Manage. This endpoint is free:
        it doesn't count

        toward the monthly API limit and keeps answering after that limit is
        reached.
      operationId: updateOnboarding
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/OnboardingUpdate'
            example:
              answers:
                incorporation_year: 2024
                legal_entity_type: c_corp
                legal_entity_state: DE
                industry: software
                international_subsidiaries: false
                banks:
                  - mercury
                  - chase
                credit_cards:
                  - ramp
              submit: true
              notify_when_synced: true
      responses:
        '200':
          description: The company's onboarding after the change
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Onboarding'
        '400':
          description: >-
            An answer or field was invalid and nothing was saved
            (`invalid_request`), or `submit` was sent while required questions
            are unanswered (`answers_incomplete`), in which case the valid
            answers sent were saved.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              examples:
                invalid_request:
                  summary: An invalid answer
                  value:
                    error:
                      type: invalid_request_error
                      code: invalid_request
                      message: >-
                        legal_entity_type must be one of: c_corp, pbc, llc,
                        s_corp, other.
                      doc_url: >-
                        https://www.finta.com/docs/api-reference/errors#invalid_request
                      param: legal_entity_type
                answers_incomplete:
                  summary: Submitted with unanswered questions
                  value:
                    error:
                      type: invalid_request_error
                      code: answers_incomplete
                      message: >-
                        Answer industry, international_subsidiaries, and banks
                        before submitting. Any answers sent with this request
                        were saved.
                      doc_url: >-
                        https://www.finta.com/docs/api-reference/errors#answers_incomplete
                      missing:
                        - industry
                        - international_subsidiaries
                        - banks
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '409':
          description: >-
            An answer can't change after Finta's decision (`onboarding_locked`,
            with `param`), or the company is already onboarded
            (`onboarding_complete`).
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              examples:
                onboarding_locked:
                  summary: Changing an answer after Finta decided
                  value:
                    error:
                      type: invalid_request_error
                      code: onboarding_locked
                      message: >-
                        legal_entity_type can’t change after Finta’s eligibility
                        decision.
                      doc_url: >-
                        https://www.finta.com/docs/api-reference/errors#onboarding_locked
                      param: legal_entity_type
                onboarding_complete:
                  summary: The company is already onboarded
                  value:
                    error:
                      type: invalid_request_error
                      code: onboarding_complete
                      message: >-
                        Onboarding is already complete, so its answers can’t
                        change.
                      doc_url: >-
                        https://www.finta.com/docs/api-reference/errors#onboarding_complete
        '429':
          $ref: '#/components/responses/RateLimited'
components:
  schemas:
    OnboardingUpdate:
      type: object
      additionalProperties: false
      properties:
        answers:
          type: object
          additionalProperties: false
          description: >-
            Only the answers to save, keyed as in `questions`. Answers left out
            keep their saved values. The enums below include accepted values
            hidden from the question's suggested choices. `null` clears an
            optional answer; a required one can't be cleared.
          properties:
            incorporation_year:
              type: integer
              nullable: true
              description: >-
                The year the company incorporated, such as 2024: any year from
                1900 to the current year. A company incorporated 3 or more years
                ago needs a call with Finta before it can onboard.
            legal_entity_type:
              type: string
              nullable: true
              enum:
                - c_corp
                - pbc
                - llc
                - s_corp
                - other
                - null
            legal_entity_state:
              type: string
              nullable: true
              description: >-
                The USPS 2-letter code of one of the 50 US states, such as DE.
                An unchanged code or null returned for a saved legacy state is
                accepted, including DC; DC cannot be newly selected.
              example: DE
            industry:
              type: string
              nullable: true
              enum:
                - software
                - services
                - marketplace
                - biotech
                - payments_and_financial_products
                - crypto
                - hardware
                - null
            international_subsidiaries:
              type: boolean
              nullable: true
            banks:
              type: array
              nullable: true
              description: >-
                Every bank it uses. Recognized provider keys such as `boa` are
                accepted directly, or as `other` with `other_bank` and saved as
                the same key. `no_bank_yet` is accepted only when the
                bank/other-bank pair matches the saved answer; a new or changed
                selection containing it returns 400 invalid_request.
              items:
                type: string
                enum:
                  - mercury
                  - brex
                  - rho
                  - svb
                  - chase
                  - no_bank_yet
                  - other
                  - ramp
                  - american_express
                  - boa
                  - citi
                  - arc
                  - slash
            other_bank:
              type: string
              nullable: true
              maxLength: 500
            credit_cards:
              type: array
              nullable: true
              description: >-
                Every credit card it uses; empty for none. Recognized provider
                keys such as `american_express` are accepted directly, or as
                `other` with `other_credit_card` and saved as the same key.
                `no_credit_cards_yet` is accepted only when the card/other-card
                pair matches the saved answer; a new or changed selection
                containing it returns 400 invalid_request.
              items:
                type: string
                enum:
                  - mercury
                  - brex
                  - ramp
                  - no_credit_cards_yet
                  - other
                  - rho
                  - chase
                  - american_express
                  - boa
                  - citi
                  - arc
                  - slash
            other_credit_card:
              type: string
              nullable: true
              maxLength: 500
            accounting_software:
              type: string
              nullable: true
              maxLength: 500
            files_taxes_with:
              type: string
              nullable: true
              maxLength: 500
            goals:
              type: string
              nullable: true
              maxLength: 500
            subsidiary_countries:
              type: array
              nullable: true
              items:
                type: string
        submit:
          type: boolean
          description: >-
            `true` asks Finta to decide once no required question is unanswered.
            Send it only after the user explicitly says yes to a recap of every
            answer in a later turn; stop and wait after the recap. A yes picked
            in the app's multiple-choice question tool after the recap counts.
            Earlier confirmations do not count; never recap and submit in the
            same turn. Repeating it after Finta decided changes nothing.
        notify_when_synced:
          type: boolean
          description: >-
            `true` to email the user who sends it when the first sync finishes;
            `false` to stop that email.
    Onboarding:
      type: object
      required:
        - object
        - status
        - answers
        - questions
        - decision
        - integrations
        - sync
        - notify_when_synced
        - next_step
      properties:
        object:
          type: string
          enum:
            - onboarding
        status:
          type: string
          enum:
            - questionnaire
            - ready_to_submit
            - call_required
            - not_eligible
            - connect_banks
            - syncing
            - complete
          description: >-
            Where the company is in onboarding. `questionnaire`: required
            questions are unanswered. `ready_to_submit`: every required question
            is answered and Finta hasn't decided yet. `call_required`: Finta
            needs a call with the company before it can onboard it.
            `not_eligible`: Finta can't onboard the company. `connect_banks`:
            approved, and the selected banks and cards are being connected.
            `syncing`: Finta is importing transactions and setting up the books,
            or a completed web-started import awaits `finish_in_web`.
            `complete`: the company is onboarded and every endpoint is
            available.
        answers:
          $ref: '#/components/schemas/OnboardingAnswers'
        questions:
          type: array
          description: >-
            The questions still to ask at this stage, in order: the required
            ones unanswered, and `credit_cards`, which is optional, until a card
            is chosen. Empty once there is nothing to ask. Once an answer means
            Finta can't onboard the company, later questions aren't asked.
            Entity and industry questions show short choice lists. Bank and card
            questions have empty `options`; gather answers from context or plain
            text. Accepted values are in `OnboardingUpdate.answers` and the MCP
            `update_onboarding` input enums.
          items:
            $ref: '#/components/schemas/OnboardingQuestion'
        decision:
          type: object
          nullable: true
          description: Finta's eligibility decision. `null` until Finta has decided.
          required:
            - outcome
            - reason
            - decided
          properties:
            outcome:
              type: string
              enum:
                - approved
                - call_required
                - not_eligible
              description: >-
                `approved`: Finta can onboard the company. `call_required`:
                after a call. `not_eligible`: Finta can't onboard it.
            reason:
              type: string
              nullable: true
              description: >-
                Why the company isn't eligible, as the web app tells the user.
                `null` for any other outcome.
              example: Unfortunately, Finta cannot support crypto startups.
            decided:
              type: integer
              nullable: true
              description: >-
                Unix timestamp of the decision. `null` for companies decided
                before Finta recorded the time.
              example: 1792540579
        integrations:
          type: array
          description: >-
            The banks and cards the company selected that onboarding waits on,
            in this order: Mercury, Brex, Ramp, Rho, SVB, Chase. A bank or card
            typed in as "other" isn't listed. Follow `next_step.message` for
            connecting them: OAuth and Plaid banks, including Chase and SVB,
            through the API. Plaid reconnects still require the web app.
          items:
            type: object
            required:
              - key
              - name
              - status
            properties:
              key:
                type: string
                enum:
                  - mercury
                  - brex
                  - ramp
                  - rho
                  - svb
                  - chase
                description: The integration's `key`, as in `GET /integrations`.
              name:
                type: string
                example: Mercury
              status:
                type: string
                enum:
                  - not_connected
                  - connected
                  - synced
                  - failed
                description: >-
                  `not_connected`: connect it. `connected`: connected, and its
                  first sync hasn't finished. `synced`: its first sync finished.
                  `failed`: its first sync failed or the connection needs
                  reauthenticating. Follow `next_step`: reconnect only when
                  reauthentication is required; failed imports with active
                  connections need Finta support.
        sync:
          type: object
          nullable: true
          description: >-
            The first sync's progress while `status` is `syncing`; `null`
            otherwise.
          required:
            - stage
            - check_again_in_seconds
          properties:
            stage:
              type: string
              enum:
                - downloading
                - categorizing
                - matching_transfers
                - failed
              description: >-
                `downloading`: Finta is downloading the transactions.
                `categorizing`: it's categorizing them. `matching_transfers`:
                it's matching transfers and preparing the dashboard, the last
                step. `failed`: a bank's sync failed; follow `next_step` to
                reconnect an expired connection or contact Finta support when
                the connection is still active.
            check_again_in_seconds:
              type: integer
              description: How long to wait before calling `GET /onboarding` again.
              example: 30
        notify_when_synced:
          type: boolean
          description: >-
            Whether Finta emails the user when the first sync finishes, as the
            web app's "Email me when it's ready" sets.
        next_step:
          type: object
          description: What to do now. See `GET /onboarding` for what each action means.
          required:
            - action
            - message
          properties:
            action:
              type: string
              enum:
                - answer_questions
                - confirm_and_submit
                - book_call
                - contact_support
                - connect_banks
                - start_import
                - wait_for_sync
                - finish_in_web
                - none
            message:
              type: string
              description: >-
                Instructions for the agent, naming the banks to connect or the
                reason Finta gave.
            url:
              type: string
              format: uri
              description: >-
                Only with `book_call` (book a call with Finta) or
                `finish_in_web` (switch to the API company in Finta first, then
                open the completed web import and choose See dashboard).
              example: https://cal.com/finta/intro
            email:
              type: string
              format: email
              description: Only with `contact_support`. Finta support's email address.
              example: support@finta.com
    Error:
      type: object
      required:
        - error
      properties:
        error:
          type: object
          required:
            - type
            - code
            - message
            - doc_url
          properties:
            type:
              type: string
              enum:
                - authentication_error
                - permission_error
                - invalid_request_error
                - rate_limit_error
                - limit_error
                - api_error
              description: >-
                The error category. `authentication_error` (401) means the
                bearer credential was missing, malformed, or unrecognized.
                `permission_error` (403) means the credential was valid but the
                caller is not allowed to access the resource.
                `invalid_request_error` covers invalid parameters, unavailable
                resources, invitation validation failures, and requests that
                conflict with current state (409). `rate_limit_error` is for
                per-minute burst limits or signup email limits (wait for
                Retry-After). `limit_error` is for monthly API call limits per
                company (upgrade or wait for reset). `api_error` denotes an
                operation failure on the server (500), or temporarily
                unavailable rule definitions (503 rules_not_ready), or paused
                agent signup (503 signups_paused). Retry with exponential
                backoff; persistent 503 errors require operator attention.
            code:
              type: string
              enum:
                - invalid_api_key
                - user_inactive
                - user_removed_from_company
                - company_closed
                - subscription_required
                - invoice_overdue
                - invoice_status_unavailable
                - staging_access_denied
                - insufficient_permission
                - resource_missing
                - parameter_missing
                - invalid_email
                - signups_paused
                - category_update_failed
                - transaction_update_failed
                - rate_limit_exceeded
                - monthly_limit_exceeded
                - invalid_date_range
                - invalid_date
                - invalid_request
                - idempotency_key_conflict
                - plan_upgrade_required
                - request_required
                - feature_disabled
                - invitation_invalid
                - invitation_create_failed
                - permissions_update_failed
                - invitation_resend_failed
                - invitation_revoke_failed
                - integration_not_connectable
                - integration_already_connected
                - connect_link_in_progress
                - connect_link_failed
                - rules_not_ready
                - forms_not_ready
                - taxes_not_ready
                - rule_already_exists
                - rule_busy
                - tag_already_exists
                - tag_busy
                - tag_deletion_failed
                - revision_conflict
                - revision_history_mismatch
                - rule_deletion_failed
                - account_create_failed
                - category_create_failed
                - upload_committed
                - upload_commit_failed
                - feedback_unavailable
                - billing_unavailable
                - closed_books
                - invoice_already_exists
                - invoice_not_open
                - invoice_not_matched
                - payment_already_matched
                - transaction_not_matchable
                - invoice_operation_failed
                - transaction_already_matched
                - transfer_not_eligible
                - transfer_operation_failed
                - transaction_already_split
                - transaction_not_splittable
                - transaction_not_split
                - split_operation_failed
                - report_export_failed
                - report_export_limit_exceeded
                - invalid_file
                - wrong_document_type
                - file_already_attached
                - tax_upload_not_allowed
                - tax_upload_failed
                - inbox_item_not_completable
                - inbox_item_complete_failed
                - onboarding_incomplete
                - answers_incomplete
                - onboarding_locked
                - onboarding_complete
              description: A specific error code.
            message:
              type: string
              description: A human-readable description of the error.
            doc_url:
              type: string
              format: uri
              description: A link to documentation about this error.
              example: https://www.finta.com/docs/api-reference/errors#invalid_api_key
            current_revision:
              type: integer
              minimum: 0
              description: >-
                Current sheet revision, returned on a revision conflict when
                available.
            param:
              type: string
              nullable: true
              description: The parameter that caused the error, if applicable.
            missing:
              type: array
              items:
                type: string
              description: >-
                With `answers_incomplete`, the onboarding answer keys still
                required before submitting.
            onboarding_status:
              type: string
              enum:
                - questionnaire
                - ready_to_submit
                - call_required
                - not_eligible
                - connect_banks
                - syncing
                - complete
              description: >-
                With `onboarding_incomplete`, where the company is in
                onboarding, as `GET /onboarding` returns it in `status`.
    OnboardingAnswers:
      type: object
      description: >-
        The answers saved so far; `null` (or an empty list) when unanswered.
        `accounting_software`, `files_taxes_with`, `goals` and
        `subsidiary_countries` are asked only when Finta needs a call.
      required:
        - incorporation_year
        - legal_entity_type
        - legal_entity_state
        - industry
        - international_subsidiaries
        - banks
        - other_bank
        - credit_cards
        - other_credit_card
        - accounting_software
        - files_taxes_with
        - goals
        - subsidiary_countries
      properties:
        incorporation_year:
          type: integer
          nullable: true
          description: >-
            The year the company incorporated. `null` when the user gave only a
            range in the web app.
          example: 2024
        legal_entity_type:
          type: string
          nullable: true
          enum:
            - c_corp
            - pbc
            - llc
            - s_corp
            - other
            - null
          description: >-
            `c_corp` (C corporation), `pbc` (public benefit corporation), `llc`
            (limited liability company), `s_corp` (S corporation) or `other`.
        legal_entity_state:
          type: string
          nullable: true
          description: >-
            The US state it incorporated in (USPS 2-letter code, uppercase).
            `null` until answered: the web app preselects Delaware, the API
            asks. Saved legacy state aliases return their mapped code, including
            DC; unmappable values return null. Echoing either preserves the
            saved value.
          example: DE
        industry:
          type: string
          nullable: true
          description: >-
            What it sells to make revenue: `software`, `services`,
            `marketplace`, `biotech`, `payments_and_financial_products`,
            `crypto` or `hardware`.
          example: software
        international_subsidiaries:
          type: boolean
          nullable: true
          description: Whether it has, or will soon have, foreign subsidiaries.
        banks:
          type: array
          description: >-
            The banks it uses: `mercury`, `brex`, `rho`, `svb`, `chase`, or
            `other` with `other_bank`. Recognized "other" providers are saved as
            their canonical key, such as `boa` for Bank of America. Canonical
            provider keys are also accepted directly for new answers. Saved
            `no_bank_yet` can be echoed unchanged but cannot be newly selected.
          items:
            type: string
          example:
            - mercury
        other_bank:
          type: string
          nullable: true
          description: The bank typed in under `other`.
        credit_cards:
          type: array
          description: >-
            The credit cards it uses: `mercury`, `brex`, `ramp`, or `other` with
            `other_credit_card`. Empty for none. An "other" card Finta can
            connect is saved as its own key instead, such as `american_express`.
            Canonical provider keys are also accepted directly for new answers.
            Saved `no_credit_cards_yet` can be echoed unchanged but cannot be
            newly selected.
          items:
            type: string
          example:
            - ramp
        other_credit_card:
          type: string
          nullable: true
          description: The card typed in under `other`.
        accounting_software:
          type: string
          nullable: true
          description: What it uses for accounting now. A call follow-up.
        files_taxes_with:
          type: string
          nullable: true
          description: What it uses to file taxes now. A call follow-up.
        goals:
          type: string
          nullable: true
          description: What it wants to accomplish with Finta. A call follow-up.
        subsidiary_countries:
          type: array
          description: >-
            The countries it has subsidiaries in, as the question's option
            values, such as `canada`. A call follow-up.
          items:
            type: string
    OnboardingQuestion:
      type: object
      example:
        key: legal_entity_type
        label: What is your legal entity type?
        type: single_select
        required: true
        options:
          - value: c_corp
            label: C Corporation
          - value: llc
            label: LLC
          - value: pbc
            label: Public benefit corporation
          - value: s_corp
            label: S Corporation
      required:
        - key
        - label
        - type
        - required
        - options
      properties:
        key:
          type: string
          description: The answer key to send in `PATCH /onboarding`'s `answers`.
          example: legal_entity_type
        label:
          type: string
          description: >-
            The question to cover conversationally, following
            `next_step.message`.
          example: What is your legal entity type?
        description:
          type: string
          description: >-
            Hints and private examples for accounting_software, files_taxes_with
            and goals, not to read aloud. Omitted for entity, industry, bank and
            card questions.
        type:
          type: string
          enum:
            - single_select
            - multi_select
            - boolean
            - year
            - text
          description: >-
            `single_select`: one accepted value. `multi_select`: a list of
            accepted values. `boolean`: true or false. `year`: a 4-digit year
            from 1900 to the current year. `text`: free text, up to 500
            characters.
        required:
          type: boolean
          description: >-
            Whether Finta needs the answer to decide, or, after a call is
            required, before the call.
        options:
          type: array
          description: >-
            Suggested choices to show, in order; not the full set of accepted
            values (see `OnboardingUpdate.answers`). Entity: C Corporation
            (`c_corp`), LLC (`llc`), Public benefit corporation (`pbc`), S
            Corporation (`s_corp`). Industry: Software (`software`), Hardware
            (`hardware`), Marketplace (`marketplace`), Payments or fintech
            (`payments_and_financial_products`). Empty for banks and credit
            cards: gather answers from context or plain text and map to accepted
            input values. Their type remains `multi_select`. State choices are
            unchanged; also empty for `boolean`, `text` and `year`.
          items:
            type: object
            required:
              - value
              - label
            properties:
              value:
                oneOf:
                  - type: string
                  - type: integer
                description: What to send.
              label:
                type: string
  responses:
    Unauthorized:
      description: >-
        Authentication failed. Returned when the bearer credential itself is
        missing, malformed, or unrecognized. The consumer should obtain a valid
        API key and retry. This is distinct from `403 Forbidden`, which is
        returned when the credential is valid but the caller is not allowed to
        access the resource.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          example:
            error:
              type: authentication_error
              code: invalid_api_key
              message: >-
                Invalid API key provided. Check that your API key is correct and
                active.
              doc_url: https://www.finta.com/docs/api-reference/errors#invalid_api_key
    Forbidden:
      description: >-
        The API key was successfully authenticated, but the caller is not
        allowed to access this resource. The fix is not "get a new key" (that
        returns 401) but "regain access" (reactivate the user, restore company
        access, restore an active subscription, or ask an administrator for the
        required product permission). These codes can be returned, distinguished
        by `error.code`:
          - `user_inactive` - the user that owns the API key has been deactivated.
          - `user_removed_from_company` - the user no longer has access to the company the key was created for.
          - `company_closed` - the company is closed, closing, or deleted.
          - `subscription_required` - the company does not have an active subscription.
          - `invoice_overdue` - a linked billing invoice remains unpaid after its Pacific due date; pay every overdue linked invoice in the web app to restore access, independently of the subscription or plan.
          - `staging_access_denied` - the staging environment is restricted to Finta users.
          - `insufficient_permission` - the key owner lacks API access or the endpoint's required area permission.
          - `feature_disabled` - the endpoint is in early access and not yet turned on for this company; contact Finta to request access. See "Early access endpoints" under Errors.
          - `onboarding_incomplete` - the company hasn't finished onboarding, so only the onboarding endpoints and the few it needs are available; the connect endpoints only once Finta has approved the company. `onboarding_status` says where it is; call `GET /onboarding` and follow its `next_step`. See "Onboarding".
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          examples:
            user_inactive:
              summary: User has been deactivated
              value:
                error:
                  type: permission_error
                  code: user_inactive
                  message: >-
                    The user associated with this API key is no longer active.
                    Reactivate the user or create a new API key under an active
                    user.
                  doc_url: >-
                    https://www.finta.com/docs/api-reference/errors#user_inactive
            user_removed_from_company:
              summary: User no longer has access to this company
              value:
                error:
                  type: permission_error
                  code: user_removed_from_company
                  message: >-
                    The user associated with this API key no longer has access
                    to this company. Ask a company admin to re-grant access,
                    then create a new API key.
                  doc_url: >-
                    https://www.finta.com/docs/api-reference/errors#user_removed_from_company
            company_closed:
              summary: Company is closed
              value:
                error:
                  type: permission_error
                  code: company_closed
                  message: >-
                    This company is closed. The API is not available for closed
                    companies.
                  doc_url: >-
                    https://www.finta.com/docs/api-reference/errors#company_closed
            subscription_required:
              summary: Company subscription is not active
              value:
                error:
                  type: permission_error
                  code: subscription_required
                  message: >-
                    This company does not have an active subscription. Visit
                    Settings -> Plans at app.finta.com to resolve, then retry.
                  doc_url: >-
                    https://www.finta.com/docs/api-reference/errors#subscription_required
            staging_access_denied:
              summary: Staging access is restricted
              value:
                error:
                  type: permission_error
                  code: staging_access_denied
                  message: This staging environment is restricted to Finta users.
                  doc_url: >-
                    https://www.finta.com/docs/api-reference/errors#staging_access_denied
            insufficient_permission:
              summary: Key owner lacks the required product permission
              value:
                error:
                  type: permission_error
                  code: insufficient_permission
                  message: >-
                    The API key owner needs the Transactions: View permission to
                    use this endpoint.
                  doc_url: >-
                    https://www.finta.com/docs/api-reference/errors#insufficient_permission
            feature_disabled:
              summary: Endpoint is in early access and not yet on for this company
              value:
                error:
                  type: permission_error
                  code: feature_disabled
                  message: >-
                    This feature isn’t turned on for this company yet. Contact
                    Finta to request access.
                  doc_url: >-
                    https://www.finta.com/docs/api-reference/errors#feature_disabled
            onboarding_incomplete:
              summary: The company hasn't finished onboarding
              value:
                error:
                  type: permission_error
                  code: onboarding_incomplete
                  message: >-
                    This company hasn’t finished onboarding with Finta, so this
                    endpoint isn’t available yet. Call GET /api/v1/onboarding
                    and follow its next_step.
                  doc_url: >-
                    https://www.finta.com/docs/api-reference/errors#onboarding_incomplete
                  onboarding_status: connect_banks
    RateLimited:
      description: >-
        Too many requests. Two distinct limits can trigger a 429: (1) Per-minute
        burst limit (6,000 requests per 60 seconds per API key) returns
        `rate_limit_error` / `rate_limit_exceeded` with `Retry-After` header.
        (2) Monthly API call limit per company returns `limit_error` /
        `monthly_limit_exceeded` with the reset date in the message. Monthly
        limits vary by plan: Formation (10/month), Startup (300/month), Growth
        (30,000/month). Enterprise bypasses commercial monthly quotas, but still
        counts requests and enforces per-minute abuse limits. Blocked requests
        do not count toward the limit.
      headers:
        Retry-After:
          schema:
            type: integer
          description: >-
            Seconds until the burst rate limit resets. Only present for
            rate_limit_error responses.
        X-RateLimit-Limit:
          schema:
            type: integer
          description: >-
            Maximum requests per burst window. Only present for rate_limit_error
            responses.
        X-RateLimit-Remaining:
          schema:
            type: integer
          description: >-
            Requests remaining in burst window (0 when rate limited). Only
            present for rate_limit_error responses.
        X-RateLimit-Reset:
          schema:
            type: integer
          description: >-
            Unix timestamp when the burst window resets. Only present for
            rate_limit_error responses.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          examples:
            burst_rate_limit:
              summary: Per-minute burst rate limit exceeded
              value:
                error:
                  type: rate_limit_error
                  code: rate_limit_exceeded
                  message: >-
                    Too many requests. Please retry after the Retry-After
                    period.
                  doc_url: >-
                    https://www.finta.com/docs/api-reference/errors#rate_limit_exceeded
            monthly_limit:
              summary: Monthly API call limit exceeded
              value:
                error:
                  type: limit_error
                  code: monthly_limit_exceeded
                  message: >-
                    Monthly API limit reached. Your plan allows 300 calls per
                    company per month. Resets on April 1, 2026. Upgrade in
                    Settings -> Plans at app.finta.com.
                  doc_url: >-
                    https://www.finta.com/docs/api-reference/errors#monthly_limit_exceeded
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      description: API key prefixed with `finta_`

````

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