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

# Price a deal and find where it can be approved

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

Runs the calculator and the Approval Matrix over one payload and
returns the join: each financier that can **both** price the deal
and approve it, with the rate and repayment from the cheapest rate
card that financier accepts.

The request is the union of the two tools' fields, so anything
either accepts is accepted here. Two differences from the
standalone surfaces:

- **`term` is required.** Matrix treats it as optional because a
  broker without a term in mind can still ask who would approve a
  deal. There is no repayment without a term, so the combined tool
  demands it.
- **Commercial only.** `type` accepts `commercial`; consumer
  pricing carries its own entitlement and commission columns and
  is not folded in yet.

`home_owner` and `asset_owner` are the same question under the two
tools' names. Send either; sending both with different values is
rejected rather than silently resolved.

The rate bracket is the join key, so a financier appears only when
it can do both. An approval whose brackets were all filtered out by
pricing has no rate to show and is omitted — it still appears in
the standalone Matrix, which is the tool for that question. This is
why `destination_count` can exceed the length of `results`.

Requires the `matrix.enabled` entitlement, and
`surfaces.matrix_calculator` on `GET /api/v1/feature-flags` to
be `available`. A run decrements **both** the
calculator and Matrix daily allowances, because it consumes both
engines.

If one engine fails and the other succeeds, the response is a 200
with `degraded` naming the missing half and the surviving half
returned unjoined. An empty `results` with `degraded: null` means
no financier matched; `degraded` set means the check could not be
completed. The two are deliberately distinguishable.


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

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

- `cost` (string, required) — Asset cost. Compared GST-inclusive against an approval's `min_asset_cost` / `max_asset_cost`. A negative cost is rejected.
- `asset_value` (integer, required) — Asset ID from `GET /api/v1/assets/search`.
- `term` (integer, required) — Months. Required here even though Matrix treats it as optional — there is no repayment without a term.
- `advance_arrears` (enum, required) — Whether payments are made at the start or end of each period. `none` prices in arrears.
  - 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` already includes GST.
- `abn_age` (integer, optional, nullable) — ABN age (months).
- `gst_age` (integer, optional, nullable) — GST registration age (months).
- `asset_age` (integer, optional, nullable) — Asset age (months). Derived from `year_model` when that is sent instead.
- `year_model` (integer, optional, nullable) — Build year, used to derive `asset_age`.
- `borrower_age_youngest` (integer, optional, nullable) — Youngest borrower's age (years). Tested against the approval's minimum — every borrower has to sit inside the band.
- `borrower_age_oldest` (integer, optional, nullable) — Oldest borrower's age (years), tested against the maximum. A single-borrower deal can send `borrower_age` instead and the API mirrors it into both ends.
- `borrower_age` (integer, optional, nullable) — Shorthand for a single-borrower deal.
- `file_age` (integer, optional, nullable) — Age of the borrower's **credit file**, in months — not the deal file. Months to match every other age criterion on the form (ABN age, GST age, asset age); it was days until the unit was unified.
- `credit_score` (integer, optional, nullable) — The borrower's credit score. A different criterion from `file_age`: this is the score, that is how long the file has existed, and an approval can gate on either or both.
- `industry` (string, optional, nullable) — ANZSIC division. See `GET /api/v1/approvals/options`.
- `asset_state` (enum, optional)
  - Allowed values: `none`, `new`, `used`, `demo`
- `transaction_type` (enum, optional)
  - Allowed values: `purchase`, `refinance`, `sale_hire_back`, `capital_raise`
- `home_owner` (boolean, optional, nullable)
- `private_sale` (boolean, optional, nullable)
- `sale_hire_back` (boolean, optional, nullable)
- `preferred_financier` (list of integer, optional) — Restrict results to these organisation (financier) IDs.
- `type` (enum, optional, default: commercial) — Commercial only for now. A consumer value is rejected rather than silently priced as commercial.
  - Allowed values: `commercial`
- `deposit` (float, optional, default: 0)
- `deposit_gst` (boolean, optional, default: false)
- `deposit_percentage` (boolean, optional, default: false) — Treat `deposit` as a percentage of cost rather than dollars.
- `brokerage` (float, optional, default: 0)
- `brokerage_gst` (boolean, optional, default: false)
- `brokerage_percentage` (boolean, optional, default: false)
- `origination_fee` (float, optional, default: 0)
- `origination_fee_gst` (boolean, optional, default: false)
- `balloon` (float, optional, default: 0)
- `balloon_gst` (boolean, optional, default: false)
- `balloon_percentage` (boolean, optional, default: false) — Treat `balloon` as a percentage. A percentage above 100 is rejected; a dollar balloon above 100 is ordinary.
- `doc_fee_financed` (string, optional, nullable)
- `asset_owner` (boolean, optional, nullable) — The calculator's name for `home_owner`. Send either; both with different values is rejected.
- `asset_age_plus_term` (integer, optional, nullable)
- `employment_status` (string, optional, nullable)
- `citizenship_status` (string, optional, nullable)
- `lvr` (float, optional, nullable) — Loan-to-value ratio as a percentage of asset value. Cards whose `max_lvr` is below this drop out.

## Response

### 200

Priced approval destinations

- `results` (list of MatrixCalculatorRow, optional)
- `priced_count` (integer, optional) — Rate cards that survived pricing for this deal.
- `destination_count` (integer, optional) — Approvals that were not ruled out. Can exceed the length of `results`, because an approval with no priced rate bracket has no rate to show and is omitted from the join.
- `degraded` (enum, optional) — Null on a healthy run. Set when one engine failed and the other succeeded, naming the missing half (`rates` for the rate engine, `approvals` for the approval checks) — so an empty `results` can be told apart from "we could not check".
  - Allowed values: `rates`, `approvals`
- `priced` (list of MatrixCalculatorResponsePricedItems, optional) — Present only on a degraded run where the rate engine survived: the unjoined rate cards, so the broker still sees something useful.
- `financiers` (list of MatrixFinancierGroup, optional) — Present only on a degraded run where the approvals lookup survived: the unjoined Matrix groups.

## Errors

### 400 Bad Request Error

Invalid input — a missing `term`, a consumer `type`, a balloon over 100%, or contradictory `home_owner` / `asset_owner`.

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

### 403 Forbidden Error

Matrix is not on this account (`entitlement_required`) or the feature is off (`feature_disabled`).

- `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

Either daily allowance is spent. `metric` names which one, so the caller knows which limit to act on.

- `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`

## Types

### MatrixCalculatorRow

One financier that can both price and approve the deal, carrying the approval verdict beside the figures from the cheapest rate card that approval accepts.

- `organisation_id` (integer, optional)
- `organisation_name` (string, optional)
- `approval_id` (integer, optional)
- `approval_name` (string, optional)
- `doc_level` (enum, optional) — Documentation burden. Results sort least-onerous first.
  - Allowed values: `low_doc`, `lite_doc`, `full_doc`
- `status` (enum, optional)
  - Allowed values: `confirmed`, `possible`
- `missing_fields` (list of string, optional)
- `deposit_percentage` (float, optional, nullable)
- `deposit_amount` (float, optional, nullable)
- `deposit_required` (float, optional, nullable)
- `max_term` (integer, optional, nullable)
- `product_id` (integer, optional)
- `product_name` (string, optional)
- `rate_bracket_id` (integer, optional) — The cheapest bracket this approval accepts for this deal.
- `rate_bracket_name` (string, optional)
- `base_min` (string, optional) — Rates and repayments are strings — the pricing engine serialises them that way. Parse before comparing numerically.
- `base_max` (string, optional)
- `e_min` (string, optional) — Minimum effective rate. Results sort on this within a status.
- `e_max` (string, optional)
- `repayment_min` (string, optional)
- `repayment_max` (string, optional)
- `balloon` (float, optional)
- `commission` (float, optional)
- `masked` (boolean, optional) — True when the Free-tier paywall has nulled this row's figures. The cheapest three rows stay visible.
- `priced_bracket_count` (integer, optional) — How many of this approval's brackets survived pricing — not how many it has configured. Distinguishes a financier that barely fits from one that is narrow.

### MatrixCalculatorResponsePricedItems

### MatrixFinancierGroup

- `organisation_id` (integer, optional)
- `organisation_name` (string, optional)
- `approvals` (list of MatrixApprovalResult, optional)

### MatrixApprovalResult

One approval that was not ruled out. Approvals whose criteria the deal violates are omitted entirely rather than returned as a rejection.

- `approval_id` (integer, optional)
- `approval_name` (string, optional)
- `doc_level` (enum, optional) — Documentation burden. Results sort least-onerous first.
  - Allowed values: `low_doc`, `lite_doc`, `full_doc`
- `status` (enum, optional) — `confirmed` — every criterion the approval checks was supplied and satisfied. `possible` — a checked criterion had no input, so it could still qualify once that answer is known. A blank input is never treated as a violation.
  - Allowed values: `confirmed`, `possible`
- `missing_fields` (list of string, optional) — Request fields that would need answering to move this row from `possible` to `confirmed`.
- `deposit_percentage` (float, optional, nullable)
- `deposit_amount` (float, optional, nullable)
- `deposit_required` (float, optional, nullable) — Deposit this deal needs, resolved from the two fields above.
- `max_term` (integer, optional, nullable) — Longest term (months) this approval will write. Also bounds a supplied `term`, so an approval capped below the requested term is dropped rather than returned.
- `rate_bracket_ids` (list of integer, optional) — Rate brackets linked to this approval.

## Examples

**Request**

```json
{
  "cost": "100000",
  "asset_value": 42,
  "term": 60,
  "advance_arrears": "arrears",
  "repayment_frequency": "monthly",
  "cost_gst": false,
  "abn_age": 36,
  "gst_age": 24,
  "credit_score": 720,
  "asset_state": "used",
  "home_owner": true,
  "deposit": 10000,
  "brokerage": 2000,
  "balloon": 30,
  "balloon_percentage": true
}
```

**Response**

```json
{
  "results": [
    {
      "organisation_id": 1,
      "organisation_name": "Dynamoney",
      "approval_id": 1,
      "approval_name": "Low doc to $150k, property owner",
      "doc_level": "low_doc",
      "status": "confirmed",
      "missing_fields": [
        "string"
      ],
      "deposit_percentage": 1.1,
      "deposit_amount": 1.1,
      "deposit_required": 1.1,
      "max_term": 1,
      "product_id": 1,
      "product_name": "Chattel mortgage",
      "rate_bracket_id": 1,
      "rate_bracket_name": "Tier 1",
      "base_min": "7.95",
      "base_max": "9.95",
      "e_min": "7.95",
      "e_max": "9.95",
      "repayment_min": "221.31",
      "repayment_max": "231.53",
      "balloon": 1.1,
      "commission": 1.1,
      "masked": true,
      "priced_bracket_count": 1
    }
  ],
  "priced_count": 1,
  "destination_count": 1,
  "degraded": "rates",
  "priced": [
    {}
  ],
  "financiers": [
    {
      "organisation_id": 1,
      "organisation_name": "Dynamoney",
      "approvals": [
        {
          "approval_id": 1,
          "approval_name": "Low doc to $150k, property owner",
          "doc_level": "low_doc",
          "status": "confirmed",
          "missing_fields": [
            "credit_score"
          ],
          "deposit_percentage": 1.1,
          "deposit_amount": 1.1,
          "deposit_required": 1.1,
          "max_term": 1,
          "rate_bracket_ids": [
            1
          ]
        }
      ]
    }
  ]
}
```

**SDK Code**

```python Matrix Calculator_example
import requests

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

payload = {
    "cost": "100000",
    "asset_value": 42,
    "term": 60,
    "advance_arrears": "arrears",
    "repayment_frequency": "monthly",
    "cost_gst": False,
    "abn_age": 36,
    "gst_age": 24,
    "credit_score": 720,
    "asset_state": "used",
    "home_owner": True,
    "deposit": 10000,
    "brokerage": 2000,
    "balloon": 30,
    "balloon_percentage": True
}
headers = {
    "Authorization": "Bearer <token>",
    "Content-Type": "application/json"
}

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

print(response.json())
```

```javascript Matrix Calculator_example
const url = 'https://api.finput.com.au/api/v1/matrix-calculator/';
const options = {
  method: 'POST',
  headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
  body: '{"cost":"100000","asset_value":42,"term":60,"advance_arrears":"arrears","repayment_frequency":"monthly","cost_gst":false,"abn_age":36,"gst_age":24,"credit_score":720,"asset_state":"used","home_owner":true,"deposit":10000,"brokerage":2000,"balloon":30,"balloon_percentage":true}'
};

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

```go Matrix Calculator_example
package main

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

func main() {

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

	payload := strings.NewReader("{\n  \"cost\": \"100000\",\n  \"asset_value\": 42,\n  \"term\": 60,\n  \"advance_arrears\": \"arrears\",\n  \"repayment_frequency\": \"monthly\",\n  \"cost_gst\": false,\n  \"abn_age\": 36,\n  \"gst_age\": 24,\n  \"credit_score\": 720,\n  \"asset_state\": \"used\",\n  \"home_owner\": true,\n  \"deposit\": 10000,\n  \"brokerage\": 2000,\n  \"balloon\": 30,\n  \"balloon_percentage\": true\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 Matrix Calculator_example
require 'uri'
require 'net/http'

url = URI("https://api.finput.com.au/api/v1/matrix-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\": \"100000\",\n  \"asset_value\": 42,\n  \"term\": 60,\n  \"advance_arrears\": \"arrears\",\n  \"repayment_frequency\": \"monthly\",\n  \"cost_gst\": false,\n  \"abn_age\": 36,\n  \"gst_age\": 24,\n  \"credit_score\": 720,\n  \"asset_state\": \"used\",\n  \"home_owner\": true,\n  \"deposit\": 10000,\n  \"brokerage\": 2000,\n  \"balloon\": 30,\n  \"balloon_percentage\": true\n}"

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

```java Matrix Calculator_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/matrix-calculator/")
  .header("Authorization", "Bearer <token>")
  .header("Content-Type", "application/json")
  .body("{\n  \"cost\": \"100000\",\n  \"asset_value\": 42,\n  \"term\": 60,\n  \"advance_arrears\": \"arrears\",\n  \"repayment_frequency\": \"monthly\",\n  \"cost_gst\": false,\n  \"abn_age\": 36,\n  \"gst_age\": 24,\n  \"credit_score\": 720,\n  \"asset_state\": \"used\",\n  \"home_owner\": true,\n  \"deposit\": 10000,\n  \"brokerage\": 2000,\n  \"balloon\": 30,\n  \"balloon_percentage\": true\n}")
  .asString();
```

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

$client = new \GuzzleHttp\Client();

$response = $client->request('POST', 'https://api.finput.com.au/api/v1/matrix-calculator/', [
  'body' => '{
  "cost": "100000",
  "asset_value": 42,
  "term": 60,
  "advance_arrears": "arrears",
  "repayment_frequency": "monthly",
  "cost_gst": false,
  "abn_age": 36,
  "gst_age": 24,
  "credit_score": 720,
  "asset_state": "used",
  "home_owner": true,
  "deposit": 10000,
  "brokerage": 2000,
  "balloon": 30,
  "balloon_percentage": true
}',
  'headers' => [
    'Authorization' => 'Bearer <token>',
    'Content-Type' => 'application/json',
  ],
]);

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

```csharp Matrix Calculator_example
using RestSharp;

var client = new RestClient("https://api.finput.com.au/api/v1/matrix-calculator/");
var request = new RestRequest(Method.POST);
request.AddHeader("Authorization", "Bearer <token>");
request.AddHeader("Content-Type", "application/json");
request.AddParameter("application/json", "{\n  \"cost\": \"100000\",\n  \"asset_value\": 42,\n  \"term\": 60,\n  \"advance_arrears\": \"arrears\",\n  \"repayment_frequency\": \"monthly\",\n  \"cost_gst\": false,\n  \"abn_age\": 36,\n  \"gst_age\": 24,\n  \"credit_score\": 720,\n  \"asset_state\": \"used\",\n  \"home_owner\": true,\n  \"deposit\": 10000,\n  \"brokerage\": 2000,\n  \"balloon\": 30,\n  \"balloon_percentage\": true\n}", ParameterType.RequestBody);
IRestResponse response = client.Execute(request);
```

```swift Matrix Calculator_example
import Foundation

let headers = [
  "Authorization": "Bearer <token>",
  "Content-Type": "application/json"
]
let parameters = [
  "cost": "100000",
  "asset_value": 42,
  "term": 60,
  "advance_arrears": "arrears",
  "repayment_frequency": "monthly",
  "cost_gst": false,
  "abn_age": 36,
  "gst_age": 24,
  "credit_score": 720,
  "asset_state": "used",
  "home_owner": true,
  "deposit": 10000,
  "brokerage": 2000,
  "balloon": 30,
  "balloon_percentage": true
] as [String : Any]

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

let request = NSMutableURLRequest(url: NSURL(string: "https://api.finput.com.au/api/v1/matrix-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()
```