> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://docs.finput.com.au/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs.finput.com.au/_mcp/server.

# Calculate repayments

POST https://api.finput.com.au/api/v1/calculator
Content-Type: application/json

The core calculator endpoint. Takes loan parameters and returns matching
financier/product/rate bracket combinations with calculated repayment amounts.

Performs:
1. Filters products by eligibility criteria (term, amount, ABN age, asset age, etc.)
2. Matches rate brackets within eligible products
3. Applies uplift rate adjustments
4. Calculates min/max repayments for each match


Reference: https://docs.finput.com.au/api/endpoints/calculator/calculate

## Authentication

- `Authorization` header (bearer token, required) — JWT access token obtained from `POST /api/v1/auth/login`, or a `finput_sk_...` API token

## Request

### Headers

- `X-Finput-Client` (enum, optional) — Which client is asking, so every `message` in the response is worded for it. `ios` and `android` get sentences that state a fact and nothing more: no plan, no price, no link. Absent means `web`, which keeps its existing wording. An unrecognised value is treated like `ios` and `android`.
  - Allowed values: `web`, `ios`, `android`

### Body (application/json)

This endpoint expects a RepaymentInputData.

- `cost` (integer, required) — Total asset cost ($)
- `term` (integer, required) — Loan term (months)
- `deposit` (float, required) — Deposit amount ($ or %)
- `brokerage` (float, required) — Brokerage amount ($ or %)
- `origination_fee` (float, required) — Origination fee ($)
- `advance_arrears` (enum, required)
  - Allowed values: `none`, `advance`, `arrears`
- `repayment_frequency` (enum, required) — `none` prices monthly.
  - Allowed values: `yearly`, `quarterly`, `monthly`, `weekly`, `daily`, `none`
- `cost_gst` (boolean, optional, default: false) — Whether cost includes GST
- `deposit_gst` (boolean, optional, default: false)
- `deposit_percentage` (boolean, optional, default: false) — If true, deposit is a percentage of cost
- `brokerage_gst` (boolean, optional, default: false)
- `brokerage_percentage` (boolean, optional, default: false) — If true, brokerage is a percentage
- `origination_fee_gst` (boolean, optional, default: false)
- `balloon` (float, optional, default: 0) — Balloon/residual payment ($ or %)
- `balloon_gst` (boolean, optional, default: false)
- `balloon_percentage` (boolean, optional, default: false) — If true, balloon is a percentage
- `private_sale` (YesNoFlagInput, optional) — A yes/no calculator input. `true`, `1`, `"1"`, `"true"` and `"yes"` mean yes; `false`, `0`, `"0"`, `"false"` and `"no"` mean no; `null`, `""` and `"not_sure"` mean unanswered, which filters nothing. Strings are case-insensitive. Any other value is rejected with a 400 naming the field.
- `sale_hire_back` (YesNoFlagInput, optional) — A yes/no calculator input. `true`, `1`, `"1"`, `"true"` and `"yes"` mean yes; `false`, `0`, `"0"`, `"false"` and `"no"` mean no; `null`, `""` and `"not_sure"` mean unanswered, which filters nothing. Strings are case-insensitive. Any other value is rejected with a 400 naming the field.
- `doc_fee_financed` (RepaymentInputDataDocFeeFinanced, optional) — Whether the documentation fee is financed. Takes every `YesNoFlagInput` spelling, plus the rate-card value `"both"`, which narrows to cards set to `both` rather than meaning unanswered.
- `asset_owner` (YesNoFlagInput, optional) — Whether the borrower is a home owner
- `asset_state` (enum, optional)
  - Allowed values: `none`, `new`, `used`, `demo`
- `asset_age` (integer, optional, nullable) — Asset age (months)
- `asset_age_plus_term` (integer, optional, nullable)
- `asset_value` (integer, optional, nullable)
- `abn_age` (integer, optional, nullable) — ABN age (months)
- `abn_years_age` (integer, optional, nullable) — Whole years the ABN has been registered, with `abn_months_age`. Not priced (`abn_age` is); kept with the recent scenario, which reopens from it.
- `abn_months_age` (integer, optional, nullable)
- `gst_age` (integer, optional, nullable) — GST registration age (months)
- `gst_years_age` (integer, optional, nullable) — Whole years registered for GST, with `gst_months_age`. Not priced (`gst_age` is); kept with the recent scenario, which reopens from it.
- `gst_months_age` (integer, optional, nullable)
- `credit_score` (integer, optional, nullable)
- `preferred_financier` (list of integer, optional) — List of preferred organisation (financier) IDs
- `type` (enum, optional, default: commercial) — Which calculator to run. Absent means `commercial`, so payloads written before the consumer calculator keep their behaviour.
  - Allowed values: `commercial`, `consumer`
- `employment_status` (enum, optional) — Consumer borrower's employment status. Null means not stated.
  - Allowed values: `full_time`, `part_time`, `casual`, `self_employed`, `unemployed`, `pensioner`
- `citizenship_status` (enum, optional) — Consumer borrower's residency status. Null means not stated.
  - Allowed values: `citizen`, `permanent_resident`, `visa_holder`
- `lvr` (float, optional, nullable) — Loan-to-value ratio being asked for, as a percentage of the asset's value. A rate card whose `max_lvr` sits below this drops out. Omit it to filter on LVR at all — the consumer form pre-fills 100, so a broker who ignores the field still sends 100 explicitly. Deliberately not capped at 100: a consumer deal routinely finances more than the asset is worth once fees are capitalised, and lenders publish cards for exactly that.
- `bid_override` (boolean, optional, nullable) — Overrides the broker organisation's BID (broker-introduced deal) status for this run. Tri-state — omit to use the organisation's own setting.

## Response

### 200

Calculator results

- `list of RepaymentResult`

## Errors

### 400 Bad Request Error

Invalid input (e.g., asset_state conflicts with asset_age)

- `message` (string, required)
- `detail` (any, required) — Why; a sentence, or an object of the flag field to its messages.

### 403 Forbidden Error

Consumer pricing is off (`feature_disabled`) or not on this account (`entitlement_required`).

- `error` (enum, required)
  - Allowed values: `feature_disabled`, `entitlement_required`
- `detail` (string, required) — The sentence this endpoint sent before `message` existed. The same as `message` for `ios` and `android`; kept for the web.
- `message` (string, optional) — Sent with `entitlement_required`: why, worded for the client named in `X-Finput-Client`.
- `entitlement` (string, optional) — Sent with `entitlement_required`.

### 429 Too Many Requests Error

The daily calculator allowance is spent.

- `error` (enum, required)
  - Allowed values: `cap_hit`
- `detail` (string, required) — The sentence this endpoint sent before `message` existed. The same as `message` for `ios` and `android`; kept for the web.
- `message` (string, required) — What happened, worded for the client named in `X-Finput-Client`. Show this rather than composing a sentence from the other fields.
- `limit` (integer, required)
- `used` (integer, required)
- `metric` (enum, optional) — Which allowance ran out. Sent by `/matrix-calculator/`, which spends both.
  - Allowed values: `calculator`, `matrix`

### 500 Internal Server Error

Server error

- `error` (string, optional)
- `errors` (map from string to list of string, optional)

## Types

### YesNoFlagInput

A yes/no calculator input. `true`, `1`, `"1"`, `"true"` and `"yes"` mean yes; `false`, `0`, `"0"`, `"false"` and `"no"` mean no; `null`, `""` and `"not_sure"` mean unanswered, which filters nothing. Strings are case-insensitive. Any other value is rejected with a 400 naming the field.

### RepaymentInputDataDocFeeFinanced

Whether the documentation fee is financed. Takes every `YesNoFlagInput` spelling, plus the rate-card value `"both"`, which narrows to cards set to `both` rather than meaning unanswered.

### RepaymentResult

One priced option: a rate bracket of one financier's product. When the plan sees only the cheapest rows in full, every row carries `masked`, and a masked row's figures are null. Those runs list the visible rows first, cheapest first, and then the masked rows by financier name, product name and rate bracket id — not by price. Which rows are visible is decided over the whole market, so naming preferred financiers can only leave rows out, never show a row that is masked without them.

- `rate_bracket_id` (integer, optional)
- `rate_bracket_name` (string, optional, nullable)
- `product_id` (integer, optional)
- `product_name` (string, optional, nullable)
- `organisation_id` (integer, optional)
- `organisation_name` (string, optional)
- `masked` (boolean, optional) — Present only when the plan sees the cheapest rows in full: false on those, true on the rest.
- `repayment_min` (string, optional, nullable) — Dollars per repayment, 2 decimal places, e.g. "830.33". Null on a masked row, never 0.
- `repayment_max` (string, optional, nullable) — Dollars per repayment, 2 decimal places. Null on a masked row, never 0.
- `base_min` (string, optional, nullable) — Annual rate as a percentage, 2 decimal places, e.g. "7.95". Null on a masked row, never 0.
- `base_max` (string, optional, nullable) — Annual rate as a percentage, 2 decimal places. Null on a masked row, never 0.
- `base` (double, optional, nullable) — Annual rate as a fraction, e.g. 0.0795. Null on a masked row, never 0.
- `e_min` (string, optional, nullable) — Effective annual rate as a percentage, 2 decimal places. Null on a masked row, never 0.
- `e_max` (string, optional, nullable) — Effective annual rate as a percentage, 2 decimal places. Null on a masked row, never 0.
- `r_min` (double, optional, nullable) — Rate per compounding period, as a fraction. Null on a masked row, never 0.
- `r_max` (double, optional, nullable) — Rate per compounding period, as a fraction. Null on a masked row, never 0.
- `balloon` (double, optional, nullable) — Dollars; 0 for no balloon. Null on a masked row, never 0.
- `commission` (double, optional, nullable) — Dollars. Null on a masked row, never 0.
- `pv` (double, optional, nullable) — Amount financed, dollars. Null on a masked row.
- `cost` (double, optional) — Cost including GST, dollars
- `deposit` (double, optional)
- `brokerage` (double, optional) — As entered, normalised; a fraction when a percentage, else dollars excluding GST
- `loaded_brokerage` (double, optional, nullable) — Brokerage as the product loads it. Null on a masked row.
- `origination_fee` (double, optional)
- `loaded_origination_fee` (double, optional, nullable) — Origination fee as the product loads it. Null on a masked row.
- `upfront_fees` (double, optional, nullable) — Dollars. Null on a masked row.
- `max_upfront_fees` (double, optional, nullable) — Set only when whether fees are financed was not answered. Null on a masked row.
- `monthly_fee` (double, optional, nullable) — Dollars. Null on a masked row.
- `documentation_fee` (double, optional, nullable) — Dollars. Null on a masked row.
- `balloon_basis` (string, optional, nullable) — Null on a masked row.
- `brokerage_basis` (string, optional, nullable) — Null on a masked row.
- `uplift_min_term` (integer, optional, nullable) — Months. Null on a masked row.
- `uplift_max_term` (integer, optional, nullable) — Months. Null on a masked row.
- `product_min_range` (integer, optional)
- `product_max_range` (integer, optional)
- `compounding_freq` (string, optional, nullable) — Null on a masked row.
- `compounding_freq_value` (integer, optional, nullable) — Compounding periods a year. Null on a masked row.
- `unresolved_rate_fields` (list of string, optional) — Request fields a rate depends on that were not answered. Empty on a masked row, which shows no rate.
- `noi_min` (double, optional, nullable) — Number of repayments. Null on a masked row.
- `noi_max` (double, optional, nullable) — Number of repayments. Null on a masked row.
- `billing_type` (string, optional, nullable) — advance_arrears, as sent
- `repayment_frequency` (string, optional)
- `consumer_commission` (double, optional, nullable) — Consumer only. Dollars. Null on a masked row, never 0.
- `flex_steps` (list of RepaymentResultFlexStepsItems, optional, nullable) — Consumer only: the rate, repayment and commission at each notch below the quoted rate. Null on a masked row, never 0.

### RepaymentResultFlexStepsItems

- `rate_reduction` (double, optional)
- `rate` (double, optional)
- `commission` (double, optional)
- `repayment` (double, optional)
- `effective_rate` (double, optional)

## Examples

**Request**

```json
{
  "cost": 50000,
  "term": 60,
  "deposit": 5000,
  "brokerage": 2.5,
  "origination_fee": 990,
  "advance_arrears": "arrears",
  "repayment_frequency": "monthly",
  "cost_gst": false,
  "deposit_gst": false,
  "deposit_percentage": false,
  "brokerage_gst": false,
  "brokerage_percentage": true,
  "origination_fee_gst": false,
  "balloon": 0,
  "asset_state": "used",
  "asset_age": 24,
  "abn_age": 36,
  "gst_age": 36,
  "credit_score": 650,
  "preferred_financier": []
}
```

**Response**

```json
[
  {
    "rate_bracket_id": 1,
    "rate_bracket_name": "string",
    "product_id": 1,
    "product_name": "string",
    "organisation_id": 1,
    "organisation_name": "string",
    "masked": true,
    "repayment_min": "string",
    "repayment_max": "string",
    "base_min": "string",
    "base_max": "string",
    "base": 1.1,
    "e_min": "string",
    "e_max": "string",
    "r_min": 1.1,
    "r_max": 1.1,
    "balloon": 1.1,
    "commission": 1.1,
    "pv": 1.1,
    "cost": 1.1,
    "deposit": 1.1,
    "brokerage": 1.1,
    "loaded_brokerage": 1.1,
    "origination_fee": 1.1,
    "loaded_origination_fee": 1.1,
    "upfront_fees": 1.1,
    "max_upfront_fees": 1.1,
    "monthly_fee": 1.1,
    "documentation_fee": 1.1,
    "balloon_basis": "string",
    "brokerage_basis": "string",
    "uplift_min_term": 1,
    "uplift_max_term": 1,
    "product_min_range": 1,
    "product_max_range": 1,
    "compounding_freq": "m",
    "compounding_freq_value": 1,
    "unresolved_rate_fields": [
      "string"
    ],
    "noi_min": 1.1,
    "noi_max": 1.1,
    "billing_type": "string",
    "repayment_frequency": "string",
    "consumer_commission": 1.1,
    "flex_steps": [
      {
        "rate_reduction": 1.1,
        "rate": 1.1,
        "commission": 1.1,
        "repayment": 1.1,
        "effective_rate": 1.1
      }
    ]
  }
]
```

**SDK Code**

```python Calculator_calculate_example
import requests

url = "https://api.finput.com.au/api/v1/calculator"

payload = {
    "cost": 50000,
    "term": 60,
    "deposit": 5000,
    "brokerage": 2.5,
    "origination_fee": 990,
    "advance_arrears": "arrears",
    "repayment_frequency": "monthly",
    "cost_gst": False,
    "deposit_gst": False,
    "deposit_percentage": False,
    "brokerage_gst": False,
    "brokerage_percentage": True,
    "origination_fee_gst": False,
    "balloon": 0,
    "asset_state": "used",
    "asset_age": 24,
    "abn_age": 36,
    "gst_age": 36,
    "credit_score": 650,
    "preferred_financier": []
}
headers = {
    "Authorization": "Bearer <token>",
    "Content-Type": "application/json"
}

response = requests.post(url, json=payload, headers=headers)

print(response.json())
```

```javascript Calculator_calculate_example
const url = 'https://api.finput.com.au/api/v1/calculator';
const options = {
  method: 'POST',
  headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
  body: '{"cost":50000,"term":60,"deposit":5000,"brokerage":2.5,"origination_fee":990,"advance_arrears":"arrears","repayment_frequency":"monthly","cost_gst":false,"deposit_gst":false,"deposit_percentage":false,"brokerage_gst":false,"brokerage_percentage":true,"origination_fee_gst":false,"balloon":0,"asset_state":"used","asset_age":24,"abn_age":36,"gst_age":36,"credit_score":650,"preferred_financier":[]}'
};

try {
  const response = await fetch(url, options);
  const data = await response.json();
  console.log(data);
} catch (error) {
  console.error(error);
}
```

```go Calculator_calculate_example
package main

import (
	"fmt"
	"strings"
	"net/http"
	"io"
)

func main() {

	url := "https://api.finput.com.au/api/v1/calculator"

	payload := strings.NewReader("{\n  \"cost\": 50000,\n  \"term\": 60,\n  \"deposit\": 5000,\n  \"brokerage\": 2.5,\n  \"origination_fee\": 990,\n  \"advance_arrears\": \"arrears\",\n  \"repayment_frequency\": \"monthly\",\n  \"cost_gst\": false,\n  \"deposit_gst\": false,\n  \"deposit_percentage\": false,\n  \"brokerage_gst\": false,\n  \"brokerage_percentage\": true,\n  \"origination_fee_gst\": false,\n  \"balloon\": 0,\n  \"asset_state\": \"used\",\n  \"asset_age\": 24,\n  \"abn_age\": 36,\n  \"gst_age\": 36,\n  \"credit_score\": 650,\n  \"preferred_financier\": []\n}")

	req, _ := http.NewRequest("POST", url, payload)

	req.Header.Add("Authorization", "Bearer <token>")
	req.Header.Add("Content-Type", "application/json")

	res, _ := http.DefaultClient.Do(req)

	defer res.Body.Close()
	body, _ := io.ReadAll(res.Body)

	fmt.Println(res)
	fmt.Println(string(body))

}
```

```ruby Calculator_calculate_example
require 'uri'
require 'net/http'

url = URI("https://api.finput.com.au/api/v1/calculator")

http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true

request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n  \"cost\": 50000,\n  \"term\": 60,\n  \"deposit\": 5000,\n  \"brokerage\": 2.5,\n  \"origination_fee\": 990,\n  \"advance_arrears\": \"arrears\",\n  \"repayment_frequency\": \"monthly\",\n  \"cost_gst\": false,\n  \"deposit_gst\": false,\n  \"deposit_percentage\": false,\n  \"brokerage_gst\": false,\n  \"brokerage_percentage\": true,\n  \"origination_fee_gst\": false,\n  \"balloon\": 0,\n  \"asset_state\": \"used\",\n  \"asset_age\": 24,\n  \"abn_age\": 36,\n  \"gst_age\": 36,\n  \"credit_score\": 650,\n  \"preferred_financier\": []\n}"

response = http.request(request)
puts response.read_body
```

```java Calculator_calculate_example
import com.mashape.unirest.http.HttpResponse;
import com.mashape.unirest.http.Unirest;

HttpResponse<String> response = Unirest.post("https://api.finput.com.au/api/v1/calculator")
  .header("Authorization", "Bearer <token>")
  .header("Content-Type", "application/json")
  .body("{\n  \"cost\": 50000,\n  \"term\": 60,\n  \"deposit\": 5000,\n  \"brokerage\": 2.5,\n  \"origination_fee\": 990,\n  \"advance_arrears\": \"arrears\",\n  \"repayment_frequency\": \"monthly\",\n  \"cost_gst\": false,\n  \"deposit_gst\": false,\n  \"deposit_percentage\": false,\n  \"brokerage_gst\": false,\n  \"brokerage_percentage\": true,\n  \"origination_fee_gst\": false,\n  \"balloon\": 0,\n  \"asset_state\": \"used\",\n  \"asset_age\": 24,\n  \"abn_age\": 36,\n  \"gst_age\": 36,\n  \"credit_score\": 650,\n  \"preferred_financier\": []\n}")
  .asString();
```

```php Calculator_calculate_example
<?php
require_once('vendor/autoload.php');

$client = new \GuzzleHttp\Client();

$response = $client->request('POST', 'https://api.finput.com.au/api/v1/calculator', [
  'body' => '{
  "cost": 50000,
  "term": 60,
  "deposit": 5000,
  "brokerage": 2.5,
  "origination_fee": 990,
  "advance_arrears": "arrears",
  "repayment_frequency": "monthly",
  "cost_gst": false,
  "deposit_gst": false,
  "deposit_percentage": false,
  "brokerage_gst": false,
  "brokerage_percentage": true,
  "origination_fee_gst": false,
  "balloon": 0,
  "asset_state": "used",
  "asset_age": 24,
  "abn_age": 36,
  "gst_age": 36,
  "credit_score": 650,
  "preferred_financier": []
}',
  'headers' => [
    'Authorization' => 'Bearer <token>',
    'Content-Type' => 'application/json',
  ],
]);

echo $response->getBody();
```

```csharp Calculator_calculate_example
using RestSharp;

var client = new RestClient("https://api.finput.com.au/api/v1/calculator");
var request = new RestRequest(Method.POST);
request.AddHeader("Authorization", "Bearer <token>");
request.AddHeader("Content-Type", "application/json");
request.AddParameter("application/json", "{\n  \"cost\": 50000,\n  \"term\": 60,\n  \"deposit\": 5000,\n  \"brokerage\": 2.5,\n  \"origination_fee\": 990,\n  \"advance_arrears\": \"arrears\",\n  \"repayment_frequency\": \"monthly\",\n  \"cost_gst\": false,\n  \"deposit_gst\": false,\n  \"deposit_percentage\": false,\n  \"brokerage_gst\": false,\n  \"brokerage_percentage\": true,\n  \"origination_fee_gst\": false,\n  \"balloon\": 0,\n  \"asset_state\": \"used\",\n  \"asset_age\": 24,\n  \"abn_age\": 36,\n  \"gst_age\": 36,\n  \"credit_score\": 650,\n  \"preferred_financier\": []\n}", ParameterType.RequestBody);
IRestResponse response = client.Execute(request);
```

```swift Calculator_calculate_example
import Foundation

let headers = [
  "Authorization": "Bearer <token>",
  "Content-Type": "application/json"
]
let parameters = [
  "cost": 50000,
  "term": 60,
  "deposit": 5000,
  "brokerage": 2.5,
  "origination_fee": 990,
  "advance_arrears": "arrears",
  "repayment_frequency": "monthly",
  "cost_gst": false,
  "deposit_gst": false,
  "deposit_percentage": false,
  "brokerage_gst": false,
  "brokerage_percentage": true,
  "origination_fee_gst": false,
  "balloon": 0,
  "asset_state": "used",
  "asset_age": 24,
  "abn_age": 36,
  "gst_age": 36,
  "credit_score": 650,
  "preferred_financier": []
] as [String : Any]

let postData = JSONSerialization.data(withJSONObject: parameters, options: [])

let request = NSMutableURLRequest(url: NSURL(string: "https://api.finput.com.au/api/v1/calculator")! as URL,
                                        cachePolicy: .useProtocolCachePolicy,
                                    timeoutInterval: 10.0)
request.httpMethod = "POST"
request.allHTTPHeaderFields = headers
request.httpBody = postData as Data

let session = URLSession.shared
let dataTask = session.dataTask(with: request as URLRequest, completionHandler: { (data, response, error) -> Void in
  if (error != nil) {
    print(error as Any)
  } else {
    let httpResponse = response as? HTTPURLResponse
    print(httpResponse)
  }
})

dataTask.resume()
```