# Units and formats

Every field in the API follows the same handful of conventions. Learn them once here, and each
field in the [API reference](/reference) only has to say which one it uses.

## Rates and ratios are percents

A rate or a ratio is a plain number in percent: `5.25` means 5.25%, not 525%.

This covers interest rates, prime adjustments, loan-to-value (LTV), gross and total debt service
(GDS and TDS), insurance premium rates, the LTV on an equity report, and a referral partner's
`conversion_rate`.

```json
{ "interest_rate": 4.99, "ltv": 48.8, "gds": 31.2 }
```

Do not multiply by 100 before you show one, and do not divide by 100 before you send one. Some
older fields were decimal fractions, such as `0.0499`. They all changed to percents, and the
[changelog](/changelog) records each one.

## Money is in dollars

An amount is a number in Canadian dollars, with cents after the decimal point: `450000` is
$450,000 and `1234.56` is $1,234.56. The API never uses cents as an integer.

## Terms are in months

A term or an amortization is a whole number of months: `60` is a five-year term, and `300` is a
25-year amortization.

## Timestamps and dates

| Kind      | Format                            | Example                      |
| --------- | --------------------------------- | ---------------------------- |
| Timestamp | ISO 8601, in UTC                  | `2026-10-07T14:20:00.000Z`   |
| Date      | `YYYY-MM-DD`, with no time or zone | `2026-11-30`                 |

A date, such as a closing date or a maturity date, is a calendar day. It has no time zone, so
`2026-11-30` is November 30 wherever your server runs. Don't parse it into a timestamp at
midnight UTC: in Toronto that is still November 29.

When you send a date, send `YYYY-MM-DD`. Each date field in the reference says if it also accepts a
full timestamp.

## Null, and leaving a field out

In a response, a value that BrokerPlus does not have is `null`. The field is still there.

In an update (`PATCH`), the two are different. Leave a field out to keep its value, and send `null`
to clear it.

## Names and ids

- Every field name is `snake_case`.
- Every record has an `id`. Ids are opaque strings. Don't parse them or sort by them.
- Every record has an `object` field that names its type, such as `"deal"`, `"contact"`, or
  `"task"`. It never changes for a type, so you can route on it.
- Where a record points at another one, it usually carries a readable name next to the id, for
  example `assigned_broker_id` and `assigned_broker_name`. The name is for display. Use the id to
  look the record up.

A lender-coded value, such as a property type, comes as a `code` you can store and a `label` you
can show. Send the numeric code when you update it, not a quoted number or the label. The request
schema in the [API reference](/reference) lists the accepted codes. An invalid code returns the
accepted codes and their labels in `error.details.fieldErrors`.

A province is the one coded value that you can also send as its two-letter code, for example `ON`
instead of `50`. On read, a coded province also has `abbreviation`, the two-letter code.

For `PATCH /v1/deals/{id}/application`, `mortgage_insurer` uses `10` for CMHC, `20` for Sagen,
and `30` for Canada Guaranty. `payment_frequency` uses `26` for bi-weekly and `52` for weekly.
Acceleration is separate: send `payment_accelerated: true` with either frequency for accelerated
payments, or `false` for regular payments. Send `null` to clear the acceleration setting.

## The response envelope

Every response is JSON with the same outer shape. A success has `success: true` and the record, or
the list, in `data`:

```json
{ "success": true, "data": { "object": "contact", "id": "cmsclk2a9...", "first_name": "Sam" } }
```

A list adds `pagination`. See [Pagination](/pagination). A failure has `success: false` and an
`error` object. See [Errors](/errors).

## Unknown fields

We add fields often, and the beta label means a field can also change. Ignore any field you do not
recognize, instead of failing on it.
