# Changelog

Changes to the Aiwyn Product API, newest first. Entries appear here when a release
reaches production, so everything on this page is live and callable today.

Each release is grouped by the kind of change it contains:

- **⚠️ Breaking changes** — require action before you upgrade
- **Added** — new endpoints, parameters, or response fields
- **Changed** — behavior or response shape changed in a backward-compatible way
- **Deprecated** — still works, but scheduled for removal
- **Removed** — no longer available
- **Fixed** — corrected behavior


Questions about a change? Email [api-support@aiwyn.ai](mailto:api-support@aiwyn.ai).

## v9.8.0 — 2026-09-16

### Added

- **`POST /api/v1/contacts/upsert`** — Upsert up to 100 contacts in one call, each linked to existing clients by external reference (`pmsRef`, `clientRef`) instead of Aiwyn ids; contacts are processed independently, so the response returns `succeeded` and `failed` lists keyed by request index. Omit `pmsRef` to create a new contact, omit `clients` to update the contact only, or send `active: false` to unlink a client.
- **`POST /api/v1/event-subscriptions`, `PATCH /api/v1/event-subscriptions/{id}`, `POST /api/v1/event-subscriptions/{id}/reactivate`** — Payment subscriptions must set `filterExpression` to `ownPaymentLinksOnly` (payments through links the subscribing API user minted), `paymentLinkOnly` (any quick payment link) or `allPayments` (every payment); the last two need the `PYMT_EVNT_ALL` role. Other values are rejected; other entity types and existing rows are unchanged.
- **`GET /api/v1/invoices/unpaid`, `POST /api/v1/clients/v1/link/payment`** — List a client's unpaid invoices by `clientRef` and create a single-use quick payment link for that client, locked to chosen invoices, an amount and a note (at least one argument is required); the new `INVC_R` and `PAYLNK_C` roles grant these two endpoints on their own, and `API_ADMIN` keeps granting them as before.


### Fixed

- **`POST /api/v1/event-subscriptions/{id}/reactivate`** — Reactivating a webhook subscription now answers `400` when its stored `filterExpression` is no longer allowed for your roles and `404` when the subscription does not exist, instead of `500` with a `Failed to reactivate event subscription:` prefix on the message; endpoints that already answered `404` now list it in their spec.


## v9.7.0 — 2026-09-02

### Added

- **`POST /api/v1/clients/v1/onboard`** — Onboard a client with its own `address` and an optional `billingAddress` (ISO alpha-2 `country`, US states stored as abbreviations), saved exactly as the Firm Portal "Create New Client" dialog saves them; the response returns the new `clientContactInfoId` and `billingAddressId`.


## v9.6.0 — 2026-08-18

### Added

- **`GET /gql/v1/client_types`, `GET /gql/v1/tax_regions`** — Two read-only lookup endpoints for resolving the `clientTypeId` and tax region values accepted by client onboarding (`POST /api/v1/clients/v1/onboard`). Both support basic page and pageSize pagination.


### Changed

- **`GET /gql/v1/engagement/{id}`, `POST /gql/v1/engagements`, `POST /gql/v1/engagements/search`** — Engagement read responses now include the engagement's `clientId` and a `jobs` array of linked jobs (id, name, status, `clientId`, `pmsRef`, `jobRef`, `sysRefs`, plus each link's `isActive` flag), so an engagement's client and jobs can be resolved without a separate lookup.