---
title: "Get transfer limit"
method: GET
path: "/v1/banking/bank_transactions/transfer_limit"
tags: ["Bank transaction"]
---

# Get transfer limit

`GET /v1/banking/bank_transactions/transfer_limit`

## Request

- Base URL: `https://api.cardda.com`
- URL: `https://api.cardda.com/v1/banking/bank_transactions/transfer_limit`
- Auth: HTTP bearer
- TypeScript: <https://skmtc.dev/cardda/apis/banking-api/docs/v1/banking/bank_transactions/transfer_limit/get.ts> (a function with typed inputs; its response is checked against the schema)

Answers the **per-transfer cap** that applies to a transfer you are about to create,
so you can size the amount (or ask the API to split it, see `split` on
`createBankTransaction`) before you send anything.

The cap is not a property of a bank alone: it depends on the **sending bank**, the
**destination bank** (same-bank transfers are never capped), whether the transfer
belongs to an **online or a deferred payroll**, and the **LBTR** flag. Rather than
reimplementing those four rules — and drifting from them — ask here.

The answer does not depend on the amount, so it is cacheable — but **the caller is
part of the key**: `(caller, sender_id, recipient_id, bank_payroll_id, lbtr)`. Both
`recipient_id` and `bank_payroll_id` are resolved through the calling user's own
visibility, so the same tuple is a `404` for a caller who cannot see them and a cap
for one who can. Cache it **private / per-session only** — never in a shared or proxy
cache, which would hand the second answer to the first.

## It resolves a cap, it does not validate the transfer

This endpoint answers **only** "how large may one transfer be". It does not run the
validations of `createBankTransaction`, so a `200` here is not a promise that the
transfer is creatable — in particular for `lbtr`:

- **`lbtr: true` between two accounts of the same bank** answers `max_amount: null`
  (same-bank is uncapped), but creating it is a `422
  "Lbtr cannot create lbtr transaction if the sender and recipient belong to the same
  bank"`.
- **`lbtr: true` out of a bank other than Banco de Chile or Santander** answers that
  bank's ordinary cap (LBTR does not lift it there), and creating it is a `422 "Lbtr is
  not yet implemented at bank {bank_id}"`.

The rest of the create-time rules (recipient approved, description format, budget,
payroll state) are likewise out of scope here; they are listed on the `422` of
`createBankTransaction`.

## Query parameters

- `sender_id` string, uuid, required
- `recipient_id` string, uuid, required
- `bank_payroll_id` string, uuid
- `lbtr` boolean

## Parameters

- `#/paths/~1v1~1banking~1bank_keys/get/parameters/0` (unresolved $ref)

## Response `200`

The cap in force for that transfer

- object
  - `max_amount` integer, nullable, required: Maximum amount of a single transfer, in the **minor unit of the sending account's currency** (CLP has no subunit — `7000000` is $7.000.000). **`null` means the transfer has no cap**: same-bank, LBTR, or a deferred payroll at a bank that lifts it. It does **not** mean the transfer is creatable — see "It resolves a cap, it does not validate the transfer".
  - `max_transactions` integer, required: How many rows one `split: true` request may create. An amount that would need more is rejected with `422` and nothing is created. **Always present and never `null`.** It is a server-side constant, not a per-transfer computation: every `200` carries it, including the uncapped `max_amount: null` case. Unlike `max_amount`, it does not depend on the sender, the recipient, the payroll or `lbtr`. Model it as a required non-nullable integer — a client that treats it as optional and falls back to a hardcoded default is carrying a second, silently diverging copy of this limit. The value may change between releases, so read it from here instead of hardcoding `120`.

## Other responses

- `401`: Unauthorized. **Two shapes, and only one of them has a body** — the `application/json` schema below describes that one, not the status as a whole: - **empty body** — the shared auth / `company-id` guard (missing or invalid `Authorization`, missing `company-id`), and the permission gate: reading the cap is gated exactly like creating the transfer it previews, so a caller who may not create one may not price one either. - **`{"message": "Unauthorized (401)"}`** — `sender_id` names an account you are not a user of. Not "no such account": that is the `404`. Branch on the status code and parse defensively (skip `JSON.parse` on an empty body). See [Errors](https://docs.cardda.com/docs/errors).
- `404`: Not found — one of the three records the cap is resolved from does not resolve **for you and for `sender_id`**: - `sender_id` matches no `bank_account`; - `recipient_id` matches no recipient **enrolled in that account**. A recipient of another of your accounts is a different record with a different id; look it up with `?owner_id={sender_id}`; - `bank_payroll_id` matches no payroll **of that account**, including one of another of your own accounts. The payroll is deliberately not degraded to the no-payroll cap: it is what decides whether a Banco de Chile or BICE transfer is capped at all, so answering without it would be a wrong preview rather than a missing one. To ask for the no-payroll cap, omit `bank_payroll_id`.

## Changes

- **2026-11-03** `785332193a09`: 1 info
  - endpoint added

[Operation history](https://skmtc.dev/cardda/apis/banking-api/changes/v1/banking/bank_transactions/transfer_limit/get.md)

---

[API](https://skmtc.dev/cardda/apis/banking-api.md) - [All operations](https://skmtc.dev/cardda/apis/banking-api/llms.txt) - [OpenAPI document](https://skmtc.dev/cardda/apis/banking-api/revisions/785332193a09?raw)
