=== Indyzen Wellness Sync for Zenoti ===
Contributors: indyzen
Tags: zenoti, spa, booking, availability, appointment
Requires at least: 5.8
Tested up to: 6.9
Requires PHP: 7.4
Stable tag: 1.3.0
License: GPLv2 or later
License URI: https://www.gnu.org/licenses/gpl-2.0.html

Display Zenoti spa availability in a beautiful, mobile-friendly dashboard for your customers.

== Description ==

Indyzen Wellness Sync for Zenoti is a WordPress plugin that seamlessly integrates with the Zenoti API to display real-time spa service availability on your website. Perfect for spas, salons, and wellness centers using Zenoti as their management system.

= Features =

* **Real-time Availability**: Display live availability from your Zenoti account
* **Mobile-Friendly Dashboard**: Beautiful, responsive design that works on all devices
* **Easy Integration**: Simple shortcode implementation - just add `[indyzen_wellness_sync_dashboard]` to any page
* **Smart Caching**: Optimized performance with intelligent data caching
* **Customizable**: Clean, modern design that fits any website theme
* **Free + Pro Ready**: Free plugin is fully functional; Indyzen Wellness Sync Pro for Zenoti unlocks advanced capabilities

= How It Works =

1. Install and activate the plugin
2. Enter your Zenoti API credentials in the settings
3. Add the `[indyzen_wellness_sync_dashboard]` shortcode to any page or post
4. Your customers can now view available appointment slots in real-time

= Requirements =

* Active Zenoti account with API access
* Zenoti API key, Center ID, and Service ID
* API key permissions depending on strategy:
  * `POST /v1/queue/available_times` (Queue API strategy)
  * `POST /v1/bookings` (Standard Booking — create draft)
  * `GET /v1/bookings/{booking_id}/slots` (Standard Booking — fetch slots)
  * `GET /v1/centers/{center_id}/therapists` (Manual fallback)
  * `GET /v1/appointments` (Manual fallback)
* WordPress 5.8 or higher
* PHP 7.4 or higher

== Installation ==

= Automatic Installation =

1. Log in to your WordPress admin panel
2. Navigate to Plugins > Add New
3. Search for "Indyzen Wellness Sync for Zenoti"
4. Click "Install Now" and then "Activate"

= Manual Installation =

1. Download the plugin zip file
2. Log in to your WordPress admin panel
3. Navigate to Plugins > Add New > Upload Plugin
4. Choose the downloaded zip file and click "Install Now"
5. Activate the plugin

= Configuration =

1. Navigate to Indyzen Wellness Sync for Zenoti in your WordPress admin menu
2. Enter your Zenoti API Key
3. Enter your Zenoti Center ID
4. Enter your Zenoti Service ID (the service you want to display availability for)
5. Choose an Availability Strategy (Queue API, Standard Booking, or Manual)
6. If using Standard Booking, enter a Guest ID (anonymous/walk-in guest from Zenoti)
7. To unlock advanced features, install and activate the external Indyzen Wellness Sync Pro for Zenoti add-on (sold via LemonSqueezy) and enter your Pro LemonSqueezy license key in wp-admin
8. Save settings

= Usage =

Add the shortcode `[indyzen_wellness_sync_dashboard]` to any page or post where you want to display the availability dashboard. For the next bookable start (today only, at least the configured lead time away) use `[indyzen_wellness_sync_next]`.

Example:
```
[indyzen_wellness_sync_dashboard]
[indyzen_wellness_sync_next]
```

You can override the Service ID per shortcode:
```
[indyzen_wellness_sync_dashboard service_id="your-service-id-here"]
```

If Indyzen Wellness Sync Pro for Zenoti is active, additional shortcode variants are available:
```
[indyzen_wellness_sync_dashboard template="compact"]
```

== Frequently Asked Questions ==

= Where do I get a Zenoti API key? =

You can obtain your Zenoti API key from your Zenoti account settings. Contact Zenoti support if you need assistance accessing your API credentials.

= How do I find my Center ID? =

Your Center ID can be found in your Zenoti admin panel under your location settings. It's typically a unique identifier for your spa location.

= How often does the availability data update? =

Today’s day is cached for 15 minutes (future dates for 6 hours) under a key that includes center, service, date, and strategy. Two shortcodes with different Service IDs do not share a cache. On a 429 or Zenoti outage the last successful day is served instead of a blank error. `[indyzen_wellness_sync_next]` is also refreshed in the browser via `GET /wp-json/indyzen-wellness/v1/availability` so a page-cached host cannot freeze a stale answer.

= What is included in Free vs Pro? =

Free owns the availability engine and `[indyzen_wellness_sync_next]` (today only, default 30-minute lead).  
Indyzen Wellness Sync Pro for Zenoti adds a configurable start-time grid, morning/afternoon/evening capacity, multi-day lookahead, future-only vs all-today display, business hours / blackouts, and rendering controls.

= What are the availability strategies? =

Capacity (therapist schedules): recommended when you need a full day of starts or period totals. Builds per-provider free intervals from the roster window minus appointments.  
Standard Booking: Zenoti calculates availability using center hours, therapist schedules, room capacity, and equipment. Requires a Guest ID.  
Queue API: fast same-day “next opening” via POST /v1/queue/available_times. Default for a walk-in board. Cannot fill a time grid.

= Can I customize the appearance? =

Yes! The plugin uses standard CSS classes that you can override in your theme's custom CSS. The main wrapper uses the ID `#spa-dashboard-wrapper`.

= How do I upgrade to Pro? =

Free is fully functional without any paid license or key.
To unlock advanced slot rules and rendering controls, install and activate the external Indyzen Wellness Sync Pro for Zenoti add-on (sold via LemonSqueezy), enter your Pro LemonSqueezy license key in wp-admin, and configure it.

= Is this plugin GDPR compliant? =

The plugin only displays availability data and does not collect or store any personal information from your website visitors.

== Screenshots ==

1. Front-end output of the `[indyzen_wellness_sync_dashboard]` shortcode showing available appointment slots
2. Admin settings page for API key, Center ID, and shortcode reference
3. Responsive Indyzen Wellness Sync for Zenoti dashboard layout across desktop, tablet, and mobile

== Changelog ==

= 1.3.0 =
* Public `indyzen_wellness_sync()` / `indyzen_wellness_sync_get_day()` and a per-provider interval day model
* Cache keyed per center, service, date, strategy, duration, and cleanup (15-minute TTL today / 6 hours future); last-good copy on Zenoti errors; 429 cooldown
* `[indyzen_wellness_sync_next]` — next bookable start ≥ lead time, today only; REST hydrator at `GET /wp-json/indyzen-wellness/v1/availability`
* Minimum lead time (default 30 minutes) applied at render, so a cached slot drops off as soon as it falls inside the window
* Dashboard section hooks for Pro injection; optional `future_only` shortcode attribute (`yes`/`no`)
* Admin copy: period/grid features require Pro; Capacity (therapist schedules) is recommended for a full day of starts; Queue cannot fill a time grid

= 1.2.3 =
* Readme: 1.2.0 **Upgrade Notice** shortened to meet Plugin Check 300-character limit

= 1.2.2 =
* Hardening: shortcode output from `indyzen_wellness_sync_shortcode_html` is passed through `wp_kses_post()` before display (WordPress.org escaping guidance for filtered HTML)
* Hardening: Zenoti API requests use `wp_safe_remote_get` / `wp_safe_remote_post` instead of `wp_remote_*`
* `languages/index.php` now includes the standard `ABSPATH` guard

= 1.2.1 =
* Version bump: readme stable tag and front-end asset version aligned with WordPress.org packaging after shortcode prefix review

= 1.2.0 =
* Align distribution identity: plugin name **Indyzen Wellness Sync for Zenoti**, text domain and admin slug `indyzen-wellness-sync`, main file `indyzen-wellness-sync.php`, release zip folder `indyzen-wellness-sync`
* **Shortcode:** availability dashboard uses `[indyzen_wellness_sync_dashboard]` (WordPress.org unique-prefix requirement; replaces unprefixed `spa_dashboard`)
* **Breaking change for developers:** all extension hooks and internal identifiers now use the `indyzen_wellness_sync_*` prefix (replacing `zenoti_pulse_*`). Update any add-on (including Pro) accordingly
* One-time migration copies saved settings and active caches from legacy option/transient keys where present; legacy draft-booking transients are cleared
* Consolidated public changelog to three releases for clarity

= 1.1.0 =
* Queue API as default availability strategy; Service ID throughout (replaces legacy booking-ID flow); optional `service_id` shortcode attribute
* Availability Strategy selector: Queue API, Standard Booking (draft booking + slots), or Manual therapist/appointment gap calculation
* Guest ID field and 30-minute draft booking transient cache for Standard Booking
* Extension hooks for strategies, API normalization, slot pipeline, and shortcode rendering
* Queue API request body and error handling aligned with Zenoti (including soft handling of some 400 responses)
* WordPress 6.9 tested; GPLv2 or later license alignment; `languages/` directory and `.distignore` packaging hygiene
* External Pro add-on documented (LemonSqueezy); External Services section in readme; in-plugin license field and related cron removed from free plugin
* Uninstall removes plugin options and main availability cache

= 1.0.0 =
* Initial release: real-time Zenoti availability dashboard, `[indyzen_wellness_sync_dashboard]` shortcode, 15-minute caching, mobile-responsive UI
* Configurable service duration, cleanup time (manual strategy), custom no-availability message, optional booking URL
* PHPCS/WPCS tooling and standards pass for WordPress.org quality
* Documentation for required Zenoti API permissions, Free vs Pro positioning, and support at indyzen.pro

== Upgrade Notice ==

= 1.3.0 =
Availability cache is now keyed per service and date. New minimum lead time (default 30 minutes) hides soon-to-start slots at display time. No migration required.

= 1.2.3 =
Readme-only fix for plugin directory checks. No migration required.

= 1.2.2 =
Security and standards hardening. No migration required.

= 1.2.1 =
Maintenance release. No migration required.

= 1.2.0 =
Rebrand and slug update. Reactivate from Plugins if needed; settings migrate automatically. Replace [spa_dashboard] with [indyzen_wellness_sync_dashboard]. Developers: rename zenoti_pulse_* hooks to indyzen_wellness_sync_* in Pro or custom code.

== Support ==

For support, feature requests, or bug reports, please contact:
* Website: https://indyzen.pro
* Email: support@indyzen.pro

== Credits ==

Developed by indyzen - https://indyzen.pro

== External Services ==

=== Zenoti API ===
This plugin sends requests to the Zenoti API to retrieve availability data and calculate time slots for your configured service and center.

Data sent/used:
* Your Zenoti API key (sent in request headers).
* `center_id` and `service_id` (configured in wp-admin; used to determine which availability to fetch).
* For Standard Booking: `guest_id` (configured/entered; used to create a draft booking).
* For Queue API: a JSON request body containing `center_id`, `consider_online_hours`, and the selected `service_id`.
* For draft booking: `date`, `center_id`, and a `guests` payload containing your selected `service_id`.

Endpoint(s) used:
* `POST /v1/queue/available_times`
* `POST /v1/bookings`
* `GET /v1/bookings/{booking_id}/slots`
* `GET /v1/centers/{center_id}/therapists`
* `GET /v1/appointments`

Terms of service: https://www.zenoti.com/legal
Privacy policy: https://www.zenoti.com/privacy.html

== Privacy Policy ==

Indyzen Wellness Sync for Zenoti does not collect, store, or transmit any personal data from your website visitors. The plugin only communicates with the Zenoti API to retrieve availability information based on your configured API credentials.
