# Changelog

Changes to the API, newest first. Breaking changes are marked **[Breaking]** and announced here in advance; security fixes may ship immediately.

## October 2026

- **[Breaking] Mortgage files** - when `file_number` is omitted the file gets the organization's next number; the API key's user is recorded as the creator; the required-documents list is generated; and `borrowers` (up to 10) is validated before anything is saved. An `assigned_to` that isn't an active user returns 400 (it was ignored), and `draft` is rejected. `PUT`/`PATCH` writes only fields that actually change and runs no automations when nothing changed; a status change also sets `status_changed_at`. `PATCH /status` with the current status does nothing, and its `notes` appear in the file's notes in the app.
- **Borrowers** - a borrower with a name but no `id_number` gets a customer record, as in the app. ID number format, names (or `entity_name` for companies and associations) and enum values return 400 instead of 500, and an update is never partially saved. A new borrower gets the next `order_index`; the main borrower can't be removed while the file has other borrowers. New fields: `nickname`, `education`, `residence_type`.
- **File contacts and watchers** - file contacts have a `role` (default: the contact's type), so they appear in the app's "Parties involved" card, and the same contact can be linked in several roles. Link and watcher responses include the contact's or the user's details.
- **Customers** - a customer's mortgage files (`GET /customers/{id}`, `/customers/{id}/mortgage-files` and `GET /mortgage-files?customer_id=`) include files where the customer is a borrower - the list was almost always empty - and the delete guard (409) uses the same rule. Companies and associations use `entity_name`. `id_type`, `marital_status`, `education`, `residence_type` and the `id_number` format are validated. New writable fields: `nickname`, `education`, `residence_type`; search also matches `entity_name` and `nickname`.
- **Contacts** - `POST /contacts` works (it always returned 500). New types: `mortgage_advisor`, `real_estate_broker`, `housing_company`. Links to deleted mortgage files no longer block deleting a contact.
- **Leads** - a `status` sent through `PUT`/`PATCH` is handled like `PATCH /leads/{id}/status` (status history, `status_changed_at`, `first_response_time`), and sending the current status writes nothing. `GET /leads/statuses` returns one shape for system and custom statuses (`value`, `label`, `color {bg, text}`, `is_default`, `order`) and omits deactivated statuses. A lead created without `status` gets the organization's default status. `?status=` accepts a custom status key. Leads created through the API record `created_by`, appear in the lead's timeline and notify the organization's admins.
- **Tasks** - responses include `assignees` and `created_by`, and `completed_by` is recorded. `parent_task_id` rejects cycles and chains deeper than 10 levels. On `/mortgage-files/{id}/tasks/{taskId}`, a different `mortgage_file_id`, `lead_id` or `customer_id` returns 400 instead of being ignored.
- **Notes** - only the note's creator, or a key with `admin`, `*` or `mortgage-files:*`, can unlock or edit a locked note (otherwise 403 with `reason: note_locked`). Responses include `note_type`, `created_by`, `updated_by` and `completed_by`; the `is_*` flags must be booleans.
- **Timeline** - `metadata` contains only the documented keys of each event type. An unknown `event_type` filter returns 400.
- **[Breaking] Custom fields** - values are read from and saved to the mortgage file itself, where the app shows them; values set through the API did not appear in the app before. The `PUT`/`PATCH` response no longer has `id`, `created_at` and `updated_at`, and now has `field_name`. Values are validated against the field type; an inactive field returns 400.
- **Charges and payments** - recording, changing or unlinking a payment updates the charge status (`pending`, `partial` or `paid`), as in the app. `payment_source` must be an active payment source, a payment can't be linked to a cancelled charge (409), and a charge's milestone link must identify an existing milestone.
- **Reminders** - a reminder without `recipient_user_id` goes to the API key's user (or the file's assignee) instead of nobody. `channels` is validated, and moving a sent reminder to a future time re-arms it.
- **[Breaking] Document statuses** - a status change is recorded in the request's status history, as in the app, and can carry a `note`; `notes` is read-only. Requests dismissed from the file are hidden unless `include_dismissed=true`. `GET /required-documents` links status rows to requirements the way the app does and returns the rest in `data.unlinked_statuses`.
- **Milestones** - `GET /milestones` matches the file's milestones screen: display conditions, removed and carried-over milestones, the file's order and due dates. New `POST /mortgage-files/{id}/milestones/progress` completes or updates any milestone, including one with no progress row yet. Removed progress rows and checklist items are hidden unless `include_removed=true`.
- **[Breaking] Calculator mixes and analyses** - mix `data` must be in the calculator's format (`{version: 2, mixes: [...]}`) and is required on create, so mixes saved through the API open in the app. `analysis_data` must be a JSON object of up to 256KB.
- **Responses and routing** - responses contain only documented fields: internal columns, signature images and signature drafts are no longer returned. An unsupported method returns 405 with an `Allow` header (for example, `POST /mortgage-files/{id}` no longer creates a file), an unknown path returns 404, and a malformed ID returns 400. Responses are sent with `Cache-Control: private, no-store`.
- **Errors** - a temporary failure in the authentication service returns `503` with `reason: auth_service_error` (it was a `401`, which looked like a revoked key). A `429` carries a standard `Retry-After` header. `search` ignores `*` and is limited to 100 characters.
- **Security** - reminders no longer accept `metadata` (it could control message sending). A lead `source` that references a lead source, contact or customer must belong to your organization. A customer's mortgage files (in `GET /customers/{id}` and `/customers/{id}/mortgage-files`) require `mortgage-files:read`. Changing customer details through the borrower endpoints requires `customers:write`, and a field sent as `null` no longer erases a stored customer value. Task responses no longer include the linked customer's ID number or the linked lead's phone.
- **Subscription** - writes from an organization without an active subscription return 403 with `reason: subscription_inactive`, as in the app. Reading still works.
- The public documentation site launched at https://docs.banta.co.il in English and Hebrew, including an LLM version (`llms.txt`, `llms-full.txt` and Markdown per endpoint) and guides for authentication, permissions, pagination, errors and rate limits.
- The OpenAPI document is now in English and was reconciled with actual behavior: consistent error responses (401/403/404/429/500) on every endpoint, and previously undocumented fields on charges and milestones. Tag names in the spec are now English (for example `Leads`).
- `GET /api-docs/openapi.json` once again returns the full spec. It had been returning an outdated, abbreviated version.
- **Security** - IDs sent in request bodies (`customer_id`, `lead_id`, `source_lead_id`, `parent_task_id`, `recipient_user_id`, `charge_id`) are validated against your organization. An ID that belongs to another organization returns 400.
- **[Breaking] Permissions** - the general `write` permission no longer allows `DELETE`, matching the "Read & write" option in the app. Deleting requires `admin`, `resource:*` or `resource:delete`.
- **Deletes** - `DELETE /mortgage-files/{id}` and `DELETE /customers/{id}` now delete the record. They previously returned success without deleting it.
- **Statuses** - leads accept the organization's custom statuses. A new mortgage file gets the organization's default status (or `setup`) instead of the invalid `new`. `GET /mortgage-files/statuses` returns the real system statuses, `GET /mortgage-files/{id}/status-history` works, and a file status change saves `notes` as `status_comment`. A lead status change saves `notes` in the status history only and no longer overwrites the lead's notes.
- **Tasks** - creating tasks works. Status values are `open`, `in_progress`, `completed` and `cancelled` (`done` is accepted as `completed`), and `completed_at` is set and cleared automatically.
- **Notes** - a locked note can be unlocked with `is_locked: false`.
- **Errors** - values the database rejects return 400 (duplicates return 409) instead of 500, and `child_errors` contains error codes only.
- `GET /customers/{id}/mortgage-files` returns `{ data, count }` with the customer's mortgage files.

## August 2026

- **Charges** - a charge can be linked to a milestone with `milestone_id` and `milestone_status_key` (sent together), with an optional `milestone_due_offset_days`. When the milestone is completed, the due date is set automatically. A manually entered due date is never overwritten.
- **Leads** - `DELETE /leads/{id}` permanently deletes the lead. A deleted lead cannot be restored.

## May 2026

- New endpoints nested under mortgage files: notes, file contacts, watchers, documents, signatures, generated documents, document statuses, reminders, charges, payments, analyses, calculator mixes, custom fields and milestones.
- Top-level tasks (`/tasks`), linked to a file, a lead or a customer - or standalone.
- The key screen offers a **Custom** option with resource/action permissions (`leads:read` and so on), including the new `tasks` resource.

## April 2026

- Security hardening: keys are stored hashed only, 401 responses explain the `reason`, a rate limit of 60 requests per minute per key, and list pages capped at 500.
- Permissions are enforced per key (resource and action); a missing permission returns 403.
- An API log entry for every successful write.

## January 2026

- Contacts (`/contacts`), system lists (`/lists`) and status endpoints for leads and files.
- Incomes, bank accounts and obligations when creating a mortgage file, and more ID types for borrowers (passport, association, company).

---

Part of the banta API documentation. Full index: https://docs.banta.co.il/llms.txt
