> ## Documentation Index
> Fetch the complete documentation index at: https://developer.boothzen.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Changelog

> API + portal release history.

This changelog covers the BoothZen public API (`/api/v1/*`), webhooks, and the developer-facing surface area (SDKs, plugins, portal). It follows [Keep a Changelog](https://keepachangelog.com/) conventions.

<Note>
  Future API changes will be **additive within v1** — new fields, new endpoints, new optional parameters. Breaking changes will ship as `v2` with parallel availability for at least 12 months.
</Note>

## API additions — 2026-05-26

Additive extensions to v1 driven by the candidcamera-integration workstream. All backwards-compatible; existing keys keep working without changes.

### Added

* **`POST /api/v1/payment-intents`** — create a Stripe payment intent for an existing booking and capture the card inline using Stripe Elements (no redirect, no iframe). Requires the new `payments:write` scope. Returns `{ id, client_secret, status, amount, currency, booking_id, created_at }`.
* **`GET /api/v1/payment-intents/{pi_id}`** — retrieve a payment intent by its Stripe id for server-side reconciliation. Requires the new `payments:read` scope. Tenant isolation: a foreign intent returns `404` to avoid revealing its existence.
* **Two new scopes** on `ApiKey`: `payments:read`, `payments:write`. ScopeCatalog grows from 16 → 18 ids.
* **`price_from` on `GET /api/v1/availability`** — each day in the response now carries `price_from: { amount, currency } | null` (the cheapest visible package on that date, with holiday-rule adjustment applied) so partners can render a "from £X" calendar label without a second round-trip.
* **`metadata` bag on Booking / Customer / Lead / Invoice** — opaque key/value passthrough, up to 50 keys, max 500-char string values. Use for partner-side correlation IDs (venue lookups, lead UUIDs, UTM tags, GA4 client ids, accounting-system references). Round-trips through `POST`/`PATCH`/`GET` verbatim. Wholesale-replace on PATCH (no key-level merge).
* **`POST /api/v1/bookings` now computes `total_amount` when `package_id` is provided** — base price × holiday-rule adjustment for the event\_date, with `deposit_amount` mirroring the package's flat or percentage deposit on the adjusted total. Lets partner wizards display a real price at "review" step without a separate quote endpoint or a follow-up PATCH. Without `package_id`, total stays 0 (backwards-compat with the pre-v0.5 PATCH-later flow).

### Laravel SDK releases

* **`boothzen/laravel-sdk` v0.2.0** — `BoothZen\Laravel\Webhooks\Events` typed constants for the 13 outbound events; `paymentIntents()->create()` resource.
* **v0.3.0** — `me()->get()` for API-key introspection (tenant + scopes + mode); `leads()->createWithCustomer()` two-step helper for anonymous lead capture; `paymentIntents()->get()` for retrieve-by-id.
* **v0.4.0** — `availability()->list($from, $to)` returning `list<AvailabilityDay>` with per-unit slots and the new `price_from` Money.
* **v0.5.0** — `metadata: array<string,string>` on Booking/Customer/Lead/Invoice DTOs; `Booking::fromArray()` reads the canonical `total_amount` envelope field (was previously expecting `total`, which never existed on the wire).

## v1.0.0 — 2026-05-10

The v1 contract lock. Everything below was shipped across Phases 140 through 148 and is covered by Spectator contract tests in CI.

### Added

* **Public REST API v1** (Phase 140). 7 resource controllers (bookings, leads, quotes, invoices, customers, services, units) and the availability endpoint. Cursor pagination, prefixed string IDs (`bk_`, `ld_`, `qt_`, `inv_`, `cu_`, `srv_`, `un_`), `{amount, currency}` money envelopes, ISO-8601 UTC datetimes. Stripe-shape error envelopes. IETF `RateLimit-*` headers and per-API-key buckets (600/min).
* **API key surface** (Phase 140-01). `bz_live_*` and `bz_test_*` Bearer keys with SHA-256-hashed storage, scope enforcement, and full mode isolation. Managed at [admin/settings/api-keys](https://app.boothzen.com/admin/settings/api-keys).
* **Idempotency** (Phase 140-04). `Idempotency-Key` header on `POST`/`PATCH` with 24h Redis-backed replay cache, keyed per tenant + key.
* **OAuth 2.1 PKCE** (Phase 141). `/oauth/authorize` + `/oauth/token` endpoints, mandatory PKCE, rotating refresh tokens, tokens interchangeable with API keys on `/api/v1/*`. Apps managed at [admin/settings/oauth-apps](https://app.boothzen.com/admin/settings/oauth-apps).
* **Webhooks** (Phase 142). 13 fan-out events from 6 observers, Stripe-pattern HMAC-SHA256 signatures (`BoothZen-Signature: t=...,v1=...`), 5-minute tolerance window, 1m–12h exponential-backoff retries, auto-disable after 20 consecutive failures.
* **Widget SDK polish + full-flow booking widget** (Phase 143).
* **Laravel SDK** (Phase 144). Published to Packagist as [`boothzen/laravel-sdk`](https://packagist.org/packages/boothzen/laravel-sdk), built on Saloon v4. Includes `SignatureVerifier` helper for webhooks.
* **WordPress plugin v0.1.0** (Phase 145). Custom post type `bz_booking`, 4 Gutenberg blocks, 4 shortcodes, Elementor + Divi bridges, webhook receiver, WP-CLI commands.
* **Joomla 5 module v0.1.0** (Phase 146).
* **Zapier + Make.com integrations** (Phase 147).
* **Developer portal** at [developer.boothzen.com](https://developer.boothzen.com) (Phase 148). Live OpenAPI 3.1 spec, no spec drift, single source of truth for credentials management deep-linked to the main app.

### Conventions locked in v1

* Money is always `{ amount: <integer minor units>, currency: <ISO-4217> }`.
* Datetimes are always ISO-8601 UTC with the `Z` suffix.
* Resource IDs are always opaque strings with a stable prefix.
* Pagination is always cursor-based (`?cursor=...&limit=25`, `next_cursor` in body).
* Errors are always the Stripe-shape envelope (`error.type`, `error.code`, `error.message`, `error.request_id`).
* Two equivalent hosts: `https://app.boothzen.com/api/v1/*` (canonical) and `https://{slug}.boothzen.com/api/v1/*` (tenant-branded).
