Architecture
The integration consists of five core modules:- HTTP Client (
client.ts) — Authentication, request handling, retries, and rate-limiting - API Endpoints (
endpoints.ts) — Type-safe methods for all Zenoti REST endpoints - Data Mappers (
mappers.ts) — Transform Zenoti response types into EIP domain models - React Query Hooks (
hooks.ts) — Cached data fetching with automatic fallback to seed data - TypeScript Types (
types.ts) — Complete type definitions for all Zenoti API responses
Key Features
- Automatic token management — Bearer tokens are cached and refreshed at 90% of their 24-hour lifetime
- Exponential backoff — Automatic retry on 429 rate-limit and 5xx errors with configurable delays
- Type safety — Full TypeScript coverage for requests, responses, and domain mappings
- Demo mode fallback — Seamlessly switches between live Zenoti data and seed data based on connection state
- Multi-center support — Aggregate data across all locations or filter by specific center ID
Quick Start
Configuration
The integration reads configuration from Vite environment variables:Base URL for the Zenoti API. Varies by data center:
- US:
https://api.zenoti.com - EU:
https://api-eu.zenoti.com - AU:
https://api-au.zenoti.com
Long-lived API key for server-to-server authentication. Valid for ~1 year. Preferred method for production use.
Application ID from Zenoti Admin > Setup > Apps. Required for bearer token authentication.
Secret key generated alongside the Application ID. Required for bearer token authentication.
Organization/account name in Zenoti. Required for bearer token authentication.
Authentication Methods
Zenoti supports two authentication methods:API Key (Recommended)
Long-lived key for server-to-server calls. SetVITE_ZENOTI_API_KEY and the client will use it automatically.
Bearer Token
Generated dynamically from Application ID + Secret Key. The client caches tokens and refreshes them at 90% of their 24-hour lifetime.Error Handling
All API methods throw typed errors:ZenotiApiError— HTTP errors (4xx, 5xx) with status code and response bodyZenotiAuthError— Authentication failures during token generation
Data Flow
- Fetch —
endpoints.tsmethods call Zenoti REST API viazenotiRequest() - Map —
mappers.tsfunctions transform Zenoti types into EIP domain models - Cache — React Query hooks provide cached, auto-refreshing data with seed fallback
- Render — Dashboard components consume EIP-typed data uniformly
API Coverage
| Zenoti Resource | Endpoint Method | EIP Type | Mapper |
|---|---|---|---|
| Centers | listCenters() | Location | mapCenter() |
| Services | listServices() | Service | mapService() |
| Guests | searchGuests() | Client | mapGuest() |
| Appointments | listAppointments() | Appointment | mapAppointment() |
| Invoices | getInvoice() | — | — |
| Collections | listCollections() | DailyMetrics | mapCollection() |
| Sales Reports | getSalesReport() | DailyMetrics | mapSalesReport() |
| Employees | listEmployees() | — | — |
Next Steps
HTTP Client
Authentication, retries, and rate-limiting
API Endpoints
All available endpoint methods
Data Mappers
Zenoti to EIP type transformations
React Hooks
Query hooks with caching and fallback