{
  "$schema": "./_mapping.schema.json",
  "provider": "mindbody",
  "name": "Mindbody",
  "vertical": "wellness",
  "verified_on": "2026-10-13",
  "docs": [
    {
      "title": "Mindbody Public API v6 reference",
      "url": "https://developers.mindbodyonline.com/PublicDocumentation/V6",
      "note": "Public, no login, but rendered client-side (APIMatic widget); the static spec files behind it answer 403 to non-browser clients. Field names were read from Mindbody's own generated SDK below, which is built from the same spec."
    },
    {
      "title": "Mindbody Public API v6 SDK (official, generated docs in doc/models and doc/controllers)",
      "url": "https://github.com/mindbody/Mindbody-API-SDKs/raw/main/PublicAPI/mindbody-public-api-python_generic_lib.zip",
      "note": "Linked from the developer portal. Wire JSON names are PascalCase (e.g. StartDateTime); the SDK maps them in each model's _names table."
    },
    {
      "title": "Mindbody Webhooks API",
      "url": "https://developers.mindbodyonline.com/WebhooksDocumentation",
      "note": "Public static page: subscriptions, signature, event names and payloads."
    }
  ],
  "access": {
    "public_docs": true,
    "how_to_get_access": "Create a developer account at developers.mindbodyonline.com and request to go live; each business (site) then activates your source with the activation code/link from GET /site/activationcode. Webhooks require the same API key and a subscription per site.",
    "auth": "Headers API-Key: <developer key>, SiteId: <site id>; staff-level calls also send Authorization: <staff user token> from POST /usertoken/issue.",
    "base_url": "https://api.mindbodyonline.com/public/v6 (webhooks: https://mb-api.mindbodyonline.com/push/api/v1)"
  },
  "splitclub": {
    "integration_provider": null,
    "recommended_path": "post_from_partner_server",
    "note": "SplitClub's inbound hook does not accept 'mindbody', and the 'custom' path today only verifies Square signatures, so Mindbody's X-Mindbody-Signature cannot be checked there. Run a small relay (partner server) that subscribes to Mindbody webhooks, verifies the signature, enriches via the Public API, and calls POST /v1/offerings and POST /v1/checkouts. Offerings/availability can also be polled nightly (GET /site/sessiontypes, /sale/services, /class/classes, /appointment/bookableitems). Pointers below are rooted at the SplitClub Offering (tiers and availability inline), Event, or checkout_create."
  },
  "objects": {
    "Offering": {
      "source": "GET /public/v6/site/sessiontypes (SessionTypes[], Type=Appointment → spa_treatment) and GET /public/v6/class/classdescriptions (ClassDescriptions[] → class)",
      "kind": "spa_treatment for appointment session types; class for class descriptions",
      "source_url": "https://github.com/mindbody/Mindbody-API-SDKs/raw/main/PublicAPI/mindbody-public-api-python_generic_lib.zip#doc/controllers/site.md",
      "fields": [
        {
          "to": "/external_id",
          "from": "SessionTypes[].Id | ClassDescriptions[].Id",
          "transform": "integer → string, prefix mb_st_ / mb_cd_ (the two ID spaces overlap)",
          "source_url": "https://github.com/mindbody/Mindbody-API-SDKs/raw/main/PublicAPI/mindbody-public-api-python_generic_lib.zip#doc/models/session-type.md"
        },
        {
          "to": "/kind",
          "from": "SessionTypes[].Type",
          "transform": "Appointment → spa_treatment; Class/Enrollment → class (classes are imported from ClassDescriptions instead); others → do not import",
          "source_url": "https://github.com/mindbody/Mindbody-API-SDKs/raw/main/PublicAPI/mindbody-public-api-python_generic_lib.zip#doc/models/session-type.md"
        },
        {
          "to": "/title",
          "from": "SessionTypes[].Name | ClassDescriptions[].Name",
          "source_url": "https://github.com/mindbody/Mindbody-API-SDKs/raw/main/PublicAPI/mindbody-public-api-python_generic_lib.zip#doc/models/class-description.md"
        },
        {
          "to": "/description",
          "from": "SessionTypes[].OnlineDescription | ClassDescriptions[].Description",
          "source_url": "https://github.com/mindbody/Mindbody-API-SDKs/raw/main/PublicAPI/mindbody-public-api-python_generic_lib.zip#doc/models/class-description.md"
        },
        {
          "to": "/media/0/url",
          "from": "ClassDescriptions[].ImageURL",
          "transform": "type=image; omit when absent",
          "source_url": "https://github.com/mindbody/Mindbody-API-SDKs/raw/main/PublicAPI/mindbody-public-api-python_generic_lib.zip#doc/models/class-description.md"
        },
        {
          "to": "/category",
          "from": "ClassDescriptions[].Category | SessionTypes[].Category",
          "transform": "map Mindbody category name to a SplitClub category slug from GET /v1/me (SplitClub-side table)",
          "source_url": "https://github.com/mindbody/Mindbody-API-SDKs/raw/main/PublicAPI/mindbody-public-api-python_generic_lib.zip#doc/models/session-type.md"
        },
        {
          "to": "/metadata/duration_minutes",
          "from": "SessionTypes[].DefaultTimeLength",
          "transform": "integer minutes → string (Offering has no duration field; slot ends_at carries it)",
          "source_url": "https://github.com/mindbody/Mindbody-API-SDKs/raw/main/PublicAPI/mindbody-public-api-python_generic_lib.zip#doc/models/session-type.md"
        },
        {
          "to": "/metadata/program_id",
          "from": "SessionTypes[].ProgramId",
          "transform": "integer → string; joins to pricing options (Services[].ProgramId)",
          "source_url": "https://github.com/mindbody/Mindbody-API-SDKs/raw/main/PublicAPI/mindbody-public-api-python_generic_lib.zip#doc/models/session-type.md"
        }
      ]
    },
    "PriceTier": {
      "source": "GET /public/v6/sale/services?SessionTypeIds=…&SellOnline=true (Services[], Mindbody 'pricing options')",
      "source_url": "https://github.com/mindbody/Mindbody-API-SDKs/raw/main/PublicAPI/mindbody-public-api-python_generic_lib.zip#doc/controllers/sale.md",
      "note": "Pointers are inside the Offering: /tiers/N. A pricing option can cover many session types and be a multi-visit Series or Unlimited; import only drop-ins (Count = 1) as SplitClub tiers.",
      "fields": [
        {
          "to": "/tiers/0/external_id",
          "from": "Services[].ProductId",
          "transform": "integer → string, prefix mb_po_ (ProductId is 'the unique ID of this pricing option'; Services[].Id is the barcode ID)",
          "source_url": "https://github.com/mindbody/Mindbody-API-SDKs/raw/main/PublicAPI/mindbody-public-api-python_generic_lib.zip#doc/models/service.md"
        },
        {
          "to": "/tiers/0/label",
          "from": "Services[].Name",
          "source_url": "https://github.com/mindbody/Mindbody-API-SDKs/raw/main/PublicAPI/mindbody-public-api-python_generic_lib.zip#doc/models/service.md"
        },
        {
          "to": "/tiers/0/amount",
          "from": "Services[].OnlinePrice (fallback Services[].Price)",
          "transform": "decimal dollars → integer cents (round half up)",
          "source_url": "https://github.com/mindbody/Mindbody-API-SDKs/raw/main/PublicAPI/mindbody-public-api-python_generic_lib.zip#doc/models/service.md"
        },
        {
          "to": "/tiers/0/currency",
          "from": "Sites[].CurrencyIsoCode (GET /public/v6/site/sites)",
          "transform": "ISO code → lower case",
          "source_url": "https://github.com/mindbody/Mindbody-API-SDKs/raw/main/PublicAPI/mindbody-public-api-python_generic_lib.zip#doc/models/site.md"
        },
        {
          "to": "/tiers/0/unit",
          "from": "const:per_person",
          "transform": "Mindbody prices a pricing option per client visit; skip options whose Count > 1 or Type is Series/Unlimited",
          "source_url": "https://github.com/mindbody/Mindbody-API-SDKs/raw/main/PublicAPI/mindbody-public-api-python_generic_lib.zip#doc/models/service.md"
        },
        {
          "to": "/tiers/0/fees/0/percent",
          "from": "Services[].TaxRate (only when LocationId is sent)",
          "transform": "type=tax; included=false unless Sites[].TaxInclusivePrices. Scale of TaxRate (0.07 vs 7) is not documented",
          "source_url": "https://github.com/mindbody/Mindbody-API-SDKs/raw/main/PublicAPI/mindbody-public-api-python_generic_lib.zip#doc/models/service.md",
          "unverified": true
        },
        {
          "to": "/tiers/0/fees/0/amount",
          "from": "Services[].TaxIncluded",
          "transform": "decimal dollars → integer cents; type=tax, included=true (amount of tax inside the price when inclusive pricing is on)",
          "source_url": "https://github.com/mindbody/Mindbody-API-SDKs/raw/main/PublicAPI/mindbody-public-api-python_generic_lib.zip#doc/models/service.md"
        }
      ]
    },
    "Availability": {
      "source": "GET /public/v6/appointment/bookableitems?SessionTypeIds=…&StartDate&EndDate (Availabilities[]) for treatments; GET /public/v6/class/classes (Classes[]) for class seats; GET /public/v6/class/classschedules (ClassSchedules[]) for recurrence",
      "source_url": "https://github.com/mindbody/Mindbody-API-SDKs/raw/main/PublicAPI/mindbody-public-api-python_generic_lib.zip#doc/controllers/appointment.md",
      "note": "Pointers are inside the Offering: /availability. A bookable item is a staff availability window, not a slot: step from StartDateTime by SessionType.DefaultTimeLength until BookableEndDateTime (the last allowed start) to emit slots, one per staff member.",
      "fields": [
        {
          "to": "/availability/timezone",
          "from": "Sites[].TimeZone",
          "transform": "Mindbody documents only 'the time zone the site is located in'; the string format (IANA vs Windows name) is not documented, so normalise to IANA",
          "source_url": "https://github.com/mindbody/Mindbody-API-SDKs/raw/main/PublicAPI/mindbody-public-api-python_generic_lib.zip#doc/models/site.md",
          "unverified": true
        },
        {
          "to": "/availability/slots/0/starts_at",
          "from": "Availabilities[].StartDateTime (stepped) | Classes[].StartDateTime",
          "transform": "Public API v6 returns site-local wall-clock time with no offset (documented on Availability.StartDateTime/EndDateTime as 'in the site local time zone'). Add the offset from the site's timezone (Site.TimeZone, see /availability/timezone) for that date.",
          "source_url": "https://github.com/mindbody/Mindbody-API-SDKs/raw/main/PublicAPI/mindbody-public-api-python_generic_lib.zip#doc/models/availability.md"
        },
        {
          "to": "/availability/slots/0/ends_at",
          "from": "starts_at + SessionType.DefaultTimeLength | Classes[].EndDateTime",
          "transform": "Public API v6 returns site-local wall-clock time with no offset (documented on Availability.StartDateTime/EndDateTime as 'in the site local time zone'). Add the offset from the site's timezone (Site.TimeZone, see /availability/timezone) for that date.",
          "source_url": "https://github.com/mindbody/Mindbody-API-SDKs/raw/main/PublicAPI/mindbody-public-api-python_generic_lib.zip#doc/models/class.md"
        },
        {
          "to": "/availability/slots/0/capacity",
          "from": "const:1 per Availabilities[] staff window | Classes[].WebCapacity - Classes[].WebBooked",
          "transform": "for classes use web (online) capacity; fall back to MaxCapacity - TotalBooked",
          "source_url": "https://github.com/mindbody/Mindbody-API-SDKs/raw/main/PublicAPI/mindbody-public-api-python_generic_lib.zip#doc/models/class.md"
        },
        {
          "to": "/availability/slots/0/external_id",
          "from": "Classes[].Id | Availabilities[].Id + start",
          "transform": "string; prefix mb_cls_ / mb_av_",
          "source_url": "https://github.com/mindbody/Mindbody-API-SDKs/raw/main/PublicAPI/mindbody-public-api-python_generic_lib.zip#doc/models/class.md"
        },
        {
          "to": "/availability/recurring/0/rrule",
          "from": "ClassSchedules[].DaySunday…DaySaturday, FrequencyType, FrequencyInterval",
          "transform": "day booleans → FREQ=WEEKLY;BYDAY=SU,MO,…; FrequencyInterval → INTERVAL. FrequencyType enum values not mapped here",
          "source_url": "https://github.com/mindbody/Mindbody-API-SDKs/raw/main/PublicAPI/mindbody-public-api-python_generic_lib.zip#doc/models/class-schedule.md",
          "unverified": true
        },
        {
          "to": "/availability/recurring/0/starts_at",
          "from": "ClassSchedules[].StartDate + ClassSchedules[].StartTime",
          "transform": "combine date and time of day, then add site offset (local, no offset)",
          "source_url": "https://github.com/mindbody/Mindbody-API-SDKs/raw/main/PublicAPI/mindbody-public-api-python_generic_lib.zip#doc/models/class-schedule.md"
        },
        {
          "to": "/availability/recurring/0/until",
          "from": "ClassSchedules[].EndDate",
          "source_url": "https://github.com/mindbody/Mindbody-API-SDKs/raw/main/PublicAPI/mindbody-public-api-python_generic_lib.zip#doc/models/class-schedule.md"
        },
        {
          "to": "/availability/recurring/0/capacity",
          "from": "ClassSchedules[].MaxCapacity",
          "source_url": "https://github.com/mindbody/Mindbody-API-SDKs/raw/main/PublicAPI/mindbody-public-api-python_generic_lib.zip#doc/models/class-schedule.md",
          "unverified": true
        }
      ]
    },
    "Event": {
      "source": "GET /public/v6/class/classes (Classes[], one scheduled class instance)",
      "source_url": "https://github.com/mindbody/Mindbody-API-SDKs/raw/main/PublicAPI/mindbody-public-api-python_generic_lib.zip#doc/controllers/class.md",
      "fields": [
        {
          "to": "/external_id",
          "from": "Classes[].Id",
          "transform": "integer → string, prefix mb_cls_",
          "source_url": "https://github.com/mindbody/Mindbody-API-SDKs/raw/main/PublicAPI/mindbody-public-api-python_generic_lib.zip#doc/models/class.md"
        },
        {
          "to": "/offering_external_id",
          "from": "Classes[].ClassDescription.Id",
          "transform": "prefix mb_cd_",
          "source_url": "https://github.com/mindbody/Mindbody-API-SDKs/raw/main/PublicAPI/mindbody-public-api-python_generic_lib.zip#doc/models/class.md"
        },
        {
          "to": "/title",
          "from": "Classes[].ClassDescription.Name",
          "source_url": "https://github.com/mindbody/Mindbody-API-SDKs/raw/main/PublicAPI/mindbody-public-api-python_generic_lib.zip#doc/models/class-description.md"
        },
        {
          "to": "/description",
          "from": "Classes[].ClassDescription.Description",
          "source_url": "https://github.com/mindbody/Mindbody-API-SDKs/raw/main/PublicAPI/mindbody-public-api-python_generic_lib.zip#doc/models/class-description.md"
        },
        {
          "to": "/starts_at",
          "from": "Classes[].StartDateTime",
          "transform": "Public API v6 returns site-local wall-clock time with no offset (documented on Availability.StartDateTime/EndDateTime as 'in the site local time zone'). Add the offset from the site's timezone (Site.TimeZone, see /availability/timezone) for that date.",
          "source_url": "https://github.com/mindbody/Mindbody-API-SDKs/raw/main/PublicAPI/mindbody-public-api-python_generic_lib.zip#doc/models/class.md"
        },
        {
          "to": "/ends_at",
          "from": "Classes[].EndDateTime",
          "transform": "Public API v6 returns site-local wall-clock time with no offset (documented on Availability.StartDateTime/EndDateTime as 'in the site local time zone'). Add the offset from the site's timezone (Site.TimeZone, see /availability/timezone) for that date.",
          "source_url": "https://github.com/mindbody/Mindbody-API-SDKs/raw/main/PublicAPI/mindbody-public-api-python_generic_lib.zip#doc/models/class.md"
        },
        {
          "to": "/capacity",
          "from": "Classes[].MaxCapacity",
          "source_url": "https://github.com/mindbody/Mindbody-API-SDKs/raw/main/PublicAPI/mindbody-public-api-python_generic_lib.zip#doc/models/class.md"
        },
        {
          "to": "/media/0/url",
          "from": "Classes[].ClassDescription.ImageURL",
          "source_url": "https://github.com/mindbody/Mindbody-API-SDKs/raw/main/PublicAPI/mindbody-public-api-python_generic_lib.zip#doc/models/class-description.md"
        },
        {
          "to": "/tiers",
          "from": "GET /sale/services?ClassId={Classes[].Id}",
          "transform": "pricing options that pay for this class → tiers, as in PriceTier",
          "source_url": "https://github.com/mindbody/Mindbody-API-SDKs/raw/main/PublicAPI/mindbody-public-api-python_generic_lib.zip#doc/controllers/sale.md"
        }
      ]
    },
    "Checkout": {
      "source": "Webhook appointmentBooking.created / classRosterBooking.created, enriched with GET /public/v6/appointment/staffappointments (Appointments[]) and GET /sale/services for the price",
      "source_url": "https://developers.mindbodyonline.com/WebhooksDocumentation",
      "note": "Mindbody has no price on an appointment; amount comes from the session type's pricing option. A Mindbody appointment is for one client, so a group = several appointments the relay groups into one checkout (SplitClub-side grouping, not a Mindbody field).",
      "fields": [
        {
          "to": "/external_booking_id",
          "from": "eventData.appointmentId | eventData.classRosterBookingId",
          "transform": "integer → string, prefix mb_appt_ / mb_roster_",
          "source_url": "https://developers.mindbodyonline.com/WebhooksDocumentation"
        },
        {
          "to": "/offering_external_id",
          "from": "eventData.sessionTypeId | eventData.classId",
          "transform": "prefix mb_st_ / mb_cls_",
          "source_url": "https://developers.mindbodyonline.com/WebhooksDocumentation"
        },
        {
          "to": "/description",
          "from": "eventData.appointmentName",
          "source_url": "https://developers.mindbodyonline.com/WebhooksDocumentation"
        },
        {
          "to": "/party_size",
          "from": "const:1 per appointment",
          "transform": "sum when the relay groups appointments",
          "source_url": "https://github.com/mindbody/Mindbody-API-SDKs/raw/main/PublicAPI/mindbody-public-api-python_generic_lib.zip#doc/models/appointment.md"
        },
        {
          "to": "/amount",
          "from": "Services[].OnlinePrice for the appointment's SessionTypeId",
          "transform": "decimal dollars → integer cents, × party_size",
          "source_url": "https://github.com/mindbody/Mindbody-API-SDKs/raw/main/PublicAPI/mindbody-public-api-python_generic_lib.zip#doc/models/service.md"
        },
        {
          "to": "/currency",
          "from": "Sites[].CurrencyIsoCode",
          "transform": "lower case",
          "source_url": "https://github.com/mindbody/Mindbody-API-SDKs/raw/main/PublicAPI/mindbody-public-api-python_generic_lib.zip#doc/models/site.md"
        },
        {
          "to": "/pay_by",
          "from": "eventData.startDateTime (webhook, UTC 'Z') | Appointments[].StartDateTime (site local)",
          "transform": "start minus the offering's cutoff_minutes; webhook times are UTC, convert to the site offset",
          "source_url": "https://developers.mindbodyonline.com/WebhooksDocumentation"
        },
        {
          "to": "/metadata/mindbody_site_id",
          "from": "eventData.siteId",
          "transform": "integer → string",
          "source_url": "https://developers.mindbodyonline.com/WebhooksDocumentation"
        },
        {
          "to": "/metadata/mindbody_client_id",
          "from": "eventData.clientId",
          "source_url": "https://developers.mindbodyonline.com/WebhooksDocumentation"
        }
      ]
    }
  },
  "webhooks": {
    "supported": true,
    "signature": {
      "header": "X-Mindbody-Signature",
      "algorithm": "HMAC-SHA256, base64, value prefixed 'sha256='",
      "signed_payload": "The raw request body (UTF-8), keyed with the messageSignatureKey returned by POST /subscriptions",
      "source_url": "https://developers.mindbodyonline.com/WebhooksDocumentation"
    },
    "events": [
      {
        "event": "appointmentBooking.created",
        "maps_to": "create Checkout for the appointment (party_size 1, amount from pricing option)",
        "source_url": "https://developers.mindbodyonline.com/WebhooksDocumentation",
        "fields": [
          {
            "to": "/external_booking_id",
            "from": "eventData.appointmentId",
            "transform": "integer → string",
            "source_url": "https://developers.mindbodyonline.com/WebhooksDocumentation"
          },
          {
            "to": "/offering_external_id",
            "from": "eventData.sessionTypeId",
            "source_url": "https://developers.mindbodyonline.com/WebhooksDocumentation"
          },
          {
            "to": "/description",
            "from": "eventData.appointmentName",
            "source_url": "https://developers.mindbodyonline.com/WebhooksDocumentation"
          },
          {
            "to": "/pay_by",
            "from": "eventData.startDateTime",
            "transform": "UTC ('Z'); minus cutoff_minutes",
            "source_url": "https://developers.mindbodyonline.com/WebhooksDocumentation"
          }
        ]
      },
      {
        "event": "appointmentBooking.updated",
        "maps_to": "update Checkout pay_by / cancel when eventData.status = Cancelled",
        "source_url": "https://developers.mindbodyonline.com/WebhooksDocumentation"
      },
      {
        "event": "appointmentBooking.cancelled",
        "maps_to": "cancel the open Checkout for eventData.appointmentId",
        "source_url": "https://developers.mindbodyonline.com/WebhooksDocumentation"
      },
      {
        "event": "classRosterBooking.created",
        "maps_to": "create Checkout for a class seat; refresh slot capacity from maxCapacity/webCapacity/totalBooked/webBooked",
        "source_url": "https://developers.mindbodyonline.com/WebhooksDocumentation",
        "fields": [
          {
            "to": "/external_booking_id",
            "from": "eventData.classRosterBookingId",
            "transform": "integer → string",
            "source_url": "https://developers.mindbodyonline.com/WebhooksDocumentation"
          },
          {
            "to": "/offering_external_id",
            "from": "eventData.classId",
            "source_url": "https://developers.mindbodyonline.com/WebhooksDocumentation"
          },
          {
            "to": "/pay_by",
            "from": "eventData.classStartDateTime",
            "transform": "UTC ('Z'); minus cutoff_minutes",
            "source_url": "https://developers.mindbodyonline.com/WebhooksDocumentation"
          }
        ]
      },
      {
        "event": "classRosterBooking.cancelled",
        "maps_to": "cancel the seat's Checkout",
        "source_url": "https://developers.mindbodyonline.com/WebhooksDocumentation"
      },
      {
        "event": "classRosterBookingStatus.updated",
        "maps_to": "ignore (sign-in status)",
        "source_url": "https://developers.mindbodyonline.com/WebhooksDocumentation"
      },
      {
        "event": "class.updated",
        "maps_to": "upsert Event (startDateTime/endDateTime UTC, isCancelled → cancel)",
        "source_url": "https://developers.mindbodyonline.com/WebhooksDocumentation",
        "fields": [
          {
            "to": "/external_id",
            "from": "eventData.classId",
            "transform": "prefix mb_cls_",
            "source_url": "https://developers.mindbodyonline.com/WebhooksDocumentation"
          },
          {
            "to": "/starts_at",
            "from": "eventData.startDateTime",
            "transform": "UTC 'Z' → re-express with site offset",
            "source_url": "https://developers.mindbodyonline.com/WebhooksDocumentation"
          },
          {
            "to": "/ends_at",
            "from": "eventData.endDateTime",
            "transform": "UTC 'Z' → re-express with site offset",
            "source_url": "https://developers.mindbodyonline.com/WebhooksDocumentation"
          }
        ]
      },
      {
        "event": "classSchedule.created",
        "maps_to": "upsert Availability.recurring (startDate/endDate/startTime/endTime/daysOfWeek)",
        "source_url": "https://developers.mindbodyonline.com/WebhooksDocumentation"
      },
      {
        "event": "classSchedule.updated",
        "maps_to": "upsert Availability.recurring",
        "source_url": "https://developers.mindbodyonline.com/WebhooksDocumentation"
      },
      {
        "event": "classSchedule.cancelled",
        "maps_to": "remove the recurrence",
        "source_url": "https://developers.mindbodyonline.com/WebhooksDocumentation"
      },
      {
        "event": "classDescription.updated",
        "maps_to": "upsert class Offering",
        "source_url": "https://developers.mindbodyonline.com/WebhooksDocumentation"
      },
      {
        "event": "clientSale.created",
        "maps_to": "reconcile only (sale already paid at Mindbody): saleId, totalAmountPaid decimal dollars → cents",
        "source_url": "https://developers.mindbodyonline.com/WebhooksDocumentation"
      },
      {
        "event": "siteBusinessDayClosure.created",
        "maps_to": "add Availability.blackout_dates",
        "source_url": "https://developers.mindbodyonline.com/WebhooksDocumentation"
      },
      {
        "event": "siteBusinessDayClosure.cancelled",
        "maps_to": "remove blackout date",
        "source_url": "https://developers.mindbodyonline.com/WebhooksDocumentation"
      },
      {
        "event": "location.updated",
        "maps_to": "ignore (refresh site/location data on poll)",
        "source_url": "https://developers.mindbodyonline.com/WebhooksDocumentation"
      }
    ],
    "note": "Envelope: messageId, eventId (the event name), eventSchemaVersion, eventInstanceOriginationDateTime, eventData. Webhooks API times are UTC ('YYYY-MM-DDTHH:mm:ssZ'), unlike the Public API's site-local times. Subscriptions are created with POST /subscriptions (eventIds, webhookUrl, eventSchemaVersion 1) and must then be PATCHed to Active."
  },
  "gaps": [
    "The Public API reference renders client-side; field names were confirmed from Mindbody's official generated SDK docs (same spec), not from the rendered page.",
    "Appointments carry no price: amount must be derived from pricing options for the session type, and staff-specific pricing (StaffId param) can change it.",
    "Sites[].TimeZone format is not documented (IANA vs Windows name); verify against a live site before using it as /availability/timezone.",
    "Public API date-times are site-local without offset (documented for availabilities; assumed for classes and appointments). Webhooks are UTC.",
    "Bookable items are staff windows, not slots; slots must be generated using DefaultTimeLength and BookableEndDateTime.",
    "No documented cancellation/late-cancel policy fields map to /policy/cancellation; the venue must supply them.",
    "Group bookings are not a Mindbody concept for appointments; one appointment = one client, so party grouping is SplitClub/relay logic.",
    "TaxRate scale and ClassSchedules FrequencyType values are not documented precisely enough to map (marked unverified)."
  ]
}