# Changelog

> Notable changes to the AYETO API.

Changes that affect API clients are listed here, newest first. Additions that do not
change existing behaviour (a new optional field, a new endpoint) are listed too, so you
can see what became available.

## 2026-10-03

- Malformed list queries are rejected with `422` and a clear `detail` instead of `500`:
  a condition without 3 or 4 elements, a `filters` element that is neither an array nor
  an object, a group object with no key or several keys, an `AND` / `OR` group whose
  value is not a non-empty array, groups nested deeper than 32 levels, a negative
  `limit_from`, and a `limit_to` lower than `limit_from`.
- `429` responses of the rate limiter have the body `{"detail": "Too many requests"}`
  like every other error (the `reason` key is gone); `Retry-After` is unchanged.
- A missing API key scope is answered with `401` `API key is invalid` everywhere.
- `.../get` and `.../delete` endpoints also accept the id in a JSON body
  `{"id": "<uuid>"}`; the `entity_id` query parameter still works. Neither, or two
  different ids, gives `422`. A body sent to them must be JSON.
- New `POST /user_credit/get_self` and `POST /version` (GET still works and shares the
  rate limit); `/version` is rate limited on the static tier (1,200 requests a minute).
- `POST /ai_tool/get_all` no longer returns hidden or deprecated tools.
- New `POST /conversation/count` (scope `ayeto.conversation`, same body as
  `/conversation/find`).
- Conversation cost (`POST /usage/cost/conversation`) is the sum of the credits actually
  charged, not a repricing at current prices; it includes the text tokens of image
  models and no longer fails with `404` for models removed since.
- Chat with a model that cannot stream stores the answer and returns it (before, the
  answer was lost and the response returned the user's message).
- Chat attachments are checked and stored before anything else: an attachment refused
  with `422` (`file is too large`, a storage quota, invalid data) no longer leaves the
  user message behind. Malformed base64 returns `422` `invalid base64 data in attachment
  '<filename>'` (or `invalid data URI in attachment '<filename>'`) instead of `500`.
  The `size` field of attachments is no longer required and is ignored.
- A chat follow-up to a conversation created in an organization runs in that
  organization when the request names none (charged there, membership required);
  naming a different organization returns `422` `the conversation belongs to another
  organization`. Another user's conversation is refused with `403` before any
  attachment is stored.
- The structured chat stream (`runner_version` `"2"`) no longer sends the unused
  `iteration` field.
- Booster database: creating a record with a key that already exists returns `422`
  `a record with key '<key>' already exists` instead of `500`; `limit_from` without
  `limit_to` returns up to 100 records from `limit_from` (`limit_from` must be lower
  than `1000`); malformed `AND` / `OR` filters return `422` instead of `500`.
- Data loader: unsupported file types return `422` `unsupported file type '<mime>'` and
  are not charged.
- Workflows: a file named by its id in the run input stays the user's and is no longer
  deleted with the run (files sent as base64 still belong to the run).

## 2026-10-02

- Booster database collection rules apply only to panels in public database mode; in
  private mode they are ignored. Users a panel is shared with read-only can now write
  its records and take locks (in both modes).
- `POST /tts/mp3` requires the new `ayeto.tts` scope and `POST /data-loader/load` the new
  `ayeto.data_loader` scope. Existing API keys were given both scopes; keys created by
  pairing a desktop client (`ayeto.connector` only) can no longer call these endpoints.
- `POST /tts/mp3` and `POST /data-loader/load` accept an optional `organization_id`: the
  request runs in the organization and is charged to the user's credit there (admins and
  members only; guests and non-members get `403`).
- `POST /tts/mp3` returns `422` with `not enough user credit` / `not enough organization
  credit` when the credit runs out, instead of `500` `Failed to generate audio`.
- Chat refuses a model switched off by the administrators (requested directly or as the
  assistant's model) with `422` `model is disabled`, and an automatic model with no
  available model with `422` `model is not available`; `model is deprecated` is returned
  before the conversation is touched.
- Reading another user's conversation with `/conversation/get` (refused with `404`) no
  longer updates its `accessed` field.
- The `language` header of an API request no longer changes the user's preferred
  language in the AYETO app (before, every request saved it, and a request without the
  header reset it to English).
- `POST /assistant/avatar/get` accepts API keys with the new `ayeto.assistant` scope,
  which can now be selected when creating a key (it also covers `/assistant/find`).
- New documentation of API v3, replacing the earlier beta notes.
- Workflows are available on the API: reading, running, streaming runs, approvals,
  editing, publishing, export and import (`ayeto.workflow`, `ayeto.workflow.write`).
- Private booster database API with its own scopes (`ayeto.booster.database`,
  `ayeto.booster.database.write`).
