> ## Documentation Index
> Fetch the complete documentation index at: https://docs.montereyfinancial.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Conventions

> Versioning, dates, money, organization scoping, rate limits, pagination, and shared error shapes.

These conventions apply across the Monterey Client API.

## Versioned paths

All client endpoints begin with `/v1`.

## Dates and times

Date parameters use `YYYY-MM-DD`. Transaction endpoints accept `from` and `to` independently, and each supplied bound is inclusive.

```text theme={null}
?from=2026-01-01&to=2026-01-31
?from=2026-01-01
?to=2026-01-31
```

Omit both bounds to retrieve the full scoped transaction history through cursor pagination. Null-dated legacy transactions are included after dated transactions. Supplying either bound excludes null-dated rows.

Timestamps in response bodies use UTC.

## Money

Monetary values are integer cents in USD. For example, `amount_cents: 12500` represents 12,500 USD cents. Treat a nullable amount as unknown, not zero.

## Organization scoping

Your API key defines an organization allowlist. Each access token minted from it carries that same scope.

Endpoints that accept `organization_id` support two modes:

* Omit it to query every organization in the token's allowlist.
* Include it to query one organization. An ID outside the allowlist returns `403`.

## API permissions

Your API key also carries explicit API permissions. Read and write are independent. A write scope does not imply the matching read scope, and a read scope does not imply the matching write scope.

The public client portal requires at least one API permission when you create a key. API permissions are fixed at key creation. You cannot edit them later. To change them, create a replacement key with the permissions you need, update your integration to use it, confirm traffic succeeds, and then revoke the old key.

Legacy or manual zero-permission keys are different. If one still has a valid organization allowlist, it can exchange for an access token, but resource endpoints reject it with `403 insufficient_scope`.

## Rate limits

The API applies two distributed limits:

| Bucket | Limit | Burst |
| - | -: | -: |
| Token exchange (`POST /v1/oauth/token`) | 10 requests per minute per source IP | 10 |
| Authenticated API requests | 600 requests per minute per API key | 100 |

Rate-limited responses include:

* `RateLimit-Limit`: sustained requests allowed per minute
* `RateLimit-Remaining`: capacity remaining in the current bucket
* `RateLimit-Reset`: seconds until the bucket has room for another request

A denied request also includes `Retry-After` and returns:

```json theme={null}
{
  "detail": {
    "error_code": "rate_limited",
    "bucket": "api",
    "limit_per_minute": 600,
    "burst_capacity": 100,
    "retry_after_seconds": 3,
    "reset_at": "2026-08-21T19:04:12Z"
  }
}
```

`bucket` is `api` or `token`, so you can distinguish account-data traffic from token-exchange traffic.

### Back off using `Retry-After`

Do not guess a fixed delay. Read the server-provided value:

```python theme={null}
import time

import httpx

response = httpx.get(
    "https://api.montereyfinancial.app/v1/accounts",
    headers={"Authorization": f"Bearer {access_token}"},
)
if response.status_code == 429:
    time.sleep(int(response.headers["Retry-After"]))
```

Add jitter when many workers share an API key. Continue observing `RateLimit-Remaining` so you can pace requests before a 429.

## Error shape

Application errors use a JSON `detail.error_code` envelope:

```json theme={null}
{
  "detail": {
    "error_code": "organization_out_of_scope"
  }
}
```

Missing endpoint permissions use the same envelope:

```json theme={null}
{
  "detail": {
    "error_code": "insufficient_scope"
  }
}
```

| Status | `error_code` | Cause |
| - | - | - |
| `400` | `unsupported_grant_type` | Token request does not use `client_credentials` |
| `400` | `invalid_date_range` | `to` is earlier than `from` |
| `401` | `invalid_client` | API key exchange failed |
| `401` | `missing_token` | Bearer token is missing |
| `401` | `invalid_token` | Bearer token is invalid or expired |
| `403` | `insufficient_scope` | Bearer token is valid but does not include the endpoint's required scope |
| `403` | `organization_out_of_scope` | `organization_id` is outside the token's allowlist |
| `404` | *per endpoint* | Resource does not exist or is out of scope |
| `409` | `ambiguous_identifier` | Multiple visible accounts share a lookup identifier; retry with `organization_id` |
| `409` | *per endpoint* | Requested write conflicts with resource state |
| `422` | *various* | FastAPI request validation failed |
| `429` | `rate_limited` | Token or API rate limit exceeded |

If you receive `403 insufficient_scope`, mint a token from a replacement API key with the required scopes. If you receive `403 organization_out_of_scope`, use an organization already in the key's allowlist or create a replacement key with the correct organizations.

## List responses and pagination

List endpoints return `items` and a `page` object:

```json theme={null}
{
  "items": [],
  "page": {
    "next_cursor": null,
    "has_more": false,
    "limit": 100
  }
}
```

Pass a non-null `next_cursor` into the next request:

```text theme={null}
GET /v1/transactions?limit=500
GET /v1/transactions?limit=500&cursor=<next_cursor>
```

| Limit | Value |
| - | -: |
| Default | 100 |
| Minimum | 1 |
| Maximum | 1000 |

The API does not support offset pagination.

## Write requests

* Send JSON bodies with `Content-Type: application/json`.
* `PATCH` is partial. Omitted fields keep their current values.
* Payment-method deletion and autopay cancellation are soft and idempotent.
* Cancelled autopay schedules cannot be reactivated.

## Card capture requests

`POST /v1/payment-methods/cards` uses `Idempotency-Key` to make create-card retries safe. Reuse the same key only for the same request body. A completed replay returns the stored `201` response. A conflicting body or in-flight retry returns `409`.

For card capture, you can omit both billing-address fields to use the selected borrower's current billing address. You can also send `billing_address_id` for a saved address or `billing_address` for a transient one. Send at most one of the two fields.


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