# Changelog

What changed in the Exayard API, MCP server, webhooks, SDK, CLI and these docs. Newest first.

## 2026-10-06

### The read:usage scope

`GET /v1/usage` needs the `read:usage` scope. An app reads only its own usage: asking for another app's answers 403
`forbidden`. See [Scopes](https://developers.exayard.com/concepts/scopes.md) and [Pricing](https://developers.exayard.com/pricing.md#usage-by-app-key-or-end-user).

### Archive takes the write scope

Archiving needs the resource's own write scope, not `admin:org`: `write:projects` for a project or a page,
`write:products` for a product or a list, `write:vendors` for a vendor, `write:labor` for a labor rate, crew or
equipment, and `write:conversations` for a conversation.

### Widgets and custom properties are admin only

Only an admin of the company can create, change or remove a widget or a custom property, in Exayard. An app that
tries gets 403 `forbidden`, whatever its key or scopes.

### A second takeoff start answers 409

Starting a takeoff for a project that already has one running answers 409 `ANALYSIS_IN_PROGRESS`, from both
`POST /v1/projects/{id}/assessments` and `POST /v1/projects/{id}/analysis/run`. It used to answer 400 with the
detail "Invalid request". See [Errors](https://developers.exayard.com/concepts/errors.md#ANALYSIS_IN_PROGRESS).

### Disconnecting an integration that is not there answers 404

`DELETE /v1/integrations/{id}` with a malformed or unknown id answers 404 `not_found`. It used to answer 400.

### Restoring a project

`POST /v1/projects/{id}/restore` answers 204 when the project was archived, and 409 `conflict` when the project is
already active.

### Unknown line-item fields are named

A line item sent with a field the API does not know answers 400 `invalid_request`. `detail` names each unknown field
and lists the fields a line item takes. Nothing is saved.

### Attach moves the file

`POST /v1/projects/{id}/files/{fileId}/attach` moves the file into the project. A file from another project brings
its pages with it and leaves that project. A file that has not been processed yet is processed now. The reference
used to call this a link.

## 2026-10-05

### Keys live in apps

Apps hold keys starting `exa_live_` or `exa_test_`. An app can have up to 25 active keys, and each key can have an
expiry. A key set to work in its own company implies that company, so calls need no company id. Older `ak_` keys keep
working. See [Apps and keys](https://developers.exayard.com/apps-and-keys.md).

### Sandboxes

Test in a sandbox: a company linked to yours, with `exa_test_` keys. In a sandbox, AI answers given during a request
are samples at $0. Samples for takeoffs and file reads are coming. See [Environments and sandboxes](https://developers.exayard.com/environments.md).

Correction, 2026-10-06: takeoffs and file reads in a sandbox already return sample results at no charge, marked
`"sample": true`. Nothing in a sandbox runs for real AI usage.

### End users and usage

Send your own customer id in the `Exayard-End-User` header. Read the company's AI usage by end user, app, key or
operation with `GET /v1/usage`. See [End users](https://developers.exayard.com/concepts/end-users.md) and
[Pricing](https://developers.exayard.com/pricing.md#usage-by-app-key-or-end-user).

### What a call cost

Takeoffs, estimates and bids carry a `usage` field with the credits and the amount the work cost. See
[Pricing](https://developers.exayard.com/pricing.md#what-a-call-cost-the-usage-field).

### Webhook tests, deliveries and resend

Send a test event to an endpoint, list its deliveries, and resend one. `exayard listen` forwards events to your laptop.
See [Subscribe to webhooks](https://developers.exayard.com/guides/subscribe-to-webhooks.md).

### Rate limit per key

A key that works in its own company gets 60 calls a minute of its own, within its app's ceiling. See
[Rate limits per key](https://developers.exayard.com/apps-and-keys.md#rate-limits-per-key).

### Idempotency kept apart per app

Two apps that sent the same `Idempotency-Key` could get each other's kept response. Kept responses are now kept apart
by app, key and company. See [Idempotency](https://developers.exayard.com/concepts/idempotency.md#whose-keys-they-are).

### Leaked keys

Every key has a fixed start and a checksum, so a scanner can find it. We are joining GitHub's secret scanning
program. Once that is live, when GitHub reports an `exa_` key in a public repository, we revoke it at once and email
the admins of the app's company. See [Security](https://developers.exayard.com/apps-and-keys.md#security).

### SDK 0.3.0 and CLI 0.5.0

`@exayard/sdk` 0.3.0 and `@exayard/cli` 0.5.0 come to npm with the next release. See the [Quickstart](https://developers.exayard.com/quickstart.md) and
[Use the CLI](https://developers.exayard.com/guides/use-the-cli.md).

### Docs search, Markdown copies and this changelog

Search every docs page with `/` or Cmd-K. Each page has a "Copy as Markdown" button and a Markdown copy at its address with `.md` added, such as [/quickstart.md](https://developers.exayard.com/quickstart.md), and [/llms.txt](https://developers.exayard.com/llms.txt) lists them all for AI coding agents. Tables in the docs now render as tables.

## 2026-04-23

### MCP server

124 tools, prompts and elicitation, structured content and tool annotations.

### Webhook endpoints

Signed with HMAC-SHA256, retried for up to 3 days.

### OAuth Dynamic Client Registration

MCP clients register themselves (RFC 7591) without anyone filling in a form.

### Errors as RFC 9457 problem details

Every error is `application/problem+json` with a stable `code`, `doc_url` and `request_id`.
