# Changelog Newest first. Every entry says whether it can break something you already built. Entries are written in the commit that changes the API, not afterwards — CI refuses a change to the published surface that arrives without one. ## 2026-08-23 **Added · `xlsx` exports actually produce a spreadsheet.** `POST /api/exports` accepted `format: xlsx` and the job then failed. It now writes a real `.xlsx`, the file name ends in `.xlsx`, and the download carries the spreadsheet content type instead of `text/csv`. **Added · Rate limiting, for real.** The introduction had promised `60 req/min/token` and no limiter existed. There are now two: one for tokens and one for server-side event ingestion, both announced in the introduction and in `X-RateLimit-*` headers. **Possibly breaking** if you were sending more than the published budget — the headers tell you how close you are before anything is refused. **Changed · Listing endpoints cap `per_page`.** Seven listings —imports, exports, message templates, webhook endpoints, channel integrations, notifications and phone numbers— served whatever number you asked for. `per_page=100000` now comes back capped. See [Lists, paging and filters](/docs/guides/pagination). **Fixed · `GET /api/audit-logs` scoped to your location.** It was neither filtered by location nor authorised, so a token could read the audit trail of other accounts, old and new values included. **Fixed · 33 path parameters were named wrong in the specification.** `@urlParam contact` on `/api/contacts/{id}` and thirty-two like it. A generated client built the URL from the declared name, so it failed at run time instead of at generation time. **Possibly breaking** for a client generated before this date: regenerate it. **Changed · The specification is OpenAPI 3.1.** It validates against a standard validator in CI. The Postman collection is unchanged. **Changed · `POST /api/contacts/{id}/verify-email` returns the documented error shape.** It answered `422` without an `errors` object, breaking the `{message, errors}` contract the introduction promises. **Removed · The chat widget's endpoints left this reference.** `api/widget/*` is the embeddable chat's own contract, protected by a domain allow-list rather than by a token. It was never integrator API and being here misdescribed how it is secured. Nothing changed about the endpoints themselves.