NAV Navbar

Mindbody Affiliate API

The Mindbody Affiliate API gives your users the ability to find, book, and pay for fitness and wellness classes offered by businesses within the Mindbody Network. Whether you want to offer your users a “Guest Checkout” experience or facilitate repeat bookings, you will find this API easy to use and capable of providing delightful experiences to your users.

The Affiliate API is an HTTP-based API, so it works with any language that has an HTTP library. Requests use standard HTTP verbs such as GET, POST, and DELETE. JSON is returned and accepted by all endpoints. The API documentation uses the JSON data types defined by W3Schools. The resource documentation describes requests and responses in detail for each endpoint.

Example Use Cases

  • Let guest users find, book, and pay for classes
  • Let authenticated users find, book, and pay for classes
  • Show a user the state of their account, including bookings, purchases, and passes

Data Model

The affiliate API data model

Getting Started

  1. Contact us to become a Mindbody Network Partner.
  2. Get your API key, client key, and client secret for our development environment.
  3. Begin coding your integration and download our Postman zip file.
  4. Use your Sandbox Mindbody Demo Businesses to develop and test your integration.
  5. Complete your integration.
  6. Perform a Launch Checklist Review with Mindbody.
  7. Get your API key, client key, and client secret for production and increase your rate limits.

Designing a UX for Consumers

At Mindbody, we believe in designing delightful experiences for our end-users. This guide provides insights into the mind of wellness-seekers so that you can use the Affiliate API to provide your wellness-seekers with the best experience possible.

A Matter of Convenience

The primary concern of wellness-seekers when trying to find wellness services is convenience. Users are more likely to establish a relationship with a business that:

  • Is affordable
  • Is on their way to or from work/home
  • Consistently has openings in its classes
  • Offers classes at times outside their working hours

The Search for Wellness

Use GET Locations with either an address or latitude/longitude query parameter to set the geographical center of the location search.

Location is paramount. Users want to search for services in their immediate area, or in a specific area, generally near their work or school. We recommend allowing users to search in both ways.

Allow your users to change the size of their search area by altering the radius query parameter being passed to GET Locations.

Because “convenience” does not mean the same thing for each user, we also recommend allowing your users to increase or decrease the size of the area they are searching for wellness services.

Use the searchText query parameter on the GET Locations call to search by category or business name.

When users are trying to find a new wellness service, they usually try to search by category. They may use categorical terms such as:

  • Yoga
  • Pilates
  • Cycling
  • Crossfit
  • Barre
  • Dance
  • Etc.

On occasion, users may know the name of the business they want to find but are not sure of its location. This might happen, for instance, if they were referred to the business by a friend.

There are some users who do not necessarily know what they are looking for; they just want to discover the available wellness services in or around their area.

Collect information about the business from the subscriber object returned from the GET Locations call.

Common things users want to know about a business include:

  1. Name
  2. Street address and business description
  3. Reviews
  4. Business photos (such as pictures of the floor-space, front desk, etc.)
  5. Whether or not the location offers introductory (one-time) deals

Collect information about the classes offered at the location by using the GET Classes call.

Once a user selects a location, their focus is likely to shift to the classes offered by that location. Typically, users are most concerned with a class’s:

  1. Start and end times
  2. Name and description
  3. Staff description/biographies
  4. Staff photos
  5. Difficulty level

Do a location search via GET Locations behind the scenes, then use GET Classes for each of the locations near your user to create an interface where users select classes before locations.

Depending on your interface, a user might select a class before they look at the class’s location. When this happens, they are less concerned with the business, but they may still check to see if the location appeals to them. We recommend presenting the same location information as outlined above for this workflow.

Pricing

Use GET PricingOptions to find information about the pricing that will pay for a specific class.

Use GET PricingOptions (by location) to show all pricing options offered at a location, regardless of the location’s offered classes.

Some users are on the hunt for the best pricing/service combination. Of primary importance when showing pricing is the:

  1. Price
  2. Name
  3. Description
  4. Number of sessions

If a pricing option returned from GET PricingOptions has a userRestrictions value of IntroductoryOfferFirstTimeCustomerOfPricingOption or IntroductoryOfferFirstTimeCustomerAtBusiness, it is a deal.

When showing deals (discounted, one-time-purchase pricing options) to users, it is important to contrast the price of the deal with the class’s normal price. Otherwise, the benefit of purchasing the deal is not immediately apparent to the user.

Call POST Booking when you user is ready to book into a class.

Peer Opinion

Check the ratings object returned from GET Locations to find the rating information associated with a specific location.

Reviews and ratings for wellness businesses can play a secondary role in the user’s search for services. Users are more likely to trust a new business if they can see a large number of reviews and most of the reviews are positive.

As your users begin taking classes, you may want to begin capturing your own information about the classes to create enhanced experiences for future users. Things you may be interested in capturing include:

  1. What kind of music do they play in this class?
  2. Is this class good for beginners?
  3. What is the room temperature?
  4. What is the teacher like?
  5. Is there more cardio or strength training in this class?
  6. What classes are trending in the area?
  7. What pricing options are most frequently purchased in the area?

Additional Tips

A location’s contact info is stored in the contactInfo object returned from the GET Locations call.

A business’s cancellation policy can be found in the cancellationPolicy returned from the GET Locations call.

A business’s refund policy can be found in the refundPolicy returned from the GET Locations call.

  1. Grouping is important when showing information to your wellness-seekers. Make sure that the current date is prominently displayed on your interface, preferably close to your class times. Grouping the date next to class times decreases the cognitive load placed on the user.

  2. When classes are not bookable by your users, be sure to give them an indication as to why this is the case. It is disconcerting for the user to see a list of unbookable classes without some kind of context as to why they cannot be booked. Recommendations for each indicator are outlined in the Resource documentation.

  3. Make the business’s contact information very easy to find by displaying it on multiple pages. If users encounter workflows that your app or the Affiliate API do not support, it is important that they have quick access to help.

  4. Make the business’s cancellation and refund policies very easy to find and display them on multiple pages. Prominently displaying this information will more clearly direct users to the business if they need help with a refund or cancellation.

  5. Do not sacrifice specificity for brevity. For example, if the user already has a pass on file, do not show their potential class as “free.” Rather, indicate that they already have a valid payment on file that they can use.

If you have any further questions, comments, or insights, please do not hesitate to contact us!

Authentication and Security

Assuming that you encoded the string "clientKey:clientSecret" and your API key is "yourAPIKey" , each of your requests would have headers as demonstrated below.

curl -X GET \
-H "API-Key: yourAPIKey" \
-H "Authorization:Basic Y2xpZW50S2V5OmNsaWVudFNlY3JldA==" \
-A "yourAppName" \
"https://mb-api.mindbodyonline.com/affiliate/api/v1/locations/13909/classes"
var client = new RestClient("https://mb-api.mindbodyonline.com/affiliate/api/v1/locations/13909/classes");
var request = new RestRequest(Method.GET);
request.AddHeader("authorization", "Basic Y2xpZW50S2V5OmNsaWVudFNlY3JldA==");
request.AddHeader("api-key", "yourAPIKey");
IRestResponse response = client.Execute(request);
<?php

$request = new HttpRequest();
$request->setUrl('https://mb-api.mindbodyonline.com/affiliate/api/v1/locations/13909/classes');
$request->setMethod(HTTP_METH_GET);

$request->setHeaders(array(
  'authorization' => 'Basic Y2xpZW50S2V5OmNsaWVudFNlY3JldA==',
  'api-key' => 'yourAPIKey'
));

try {
  $response = $request->send();

  echo $response->getBody();
} catch (HttpException $ex) {
  echo $ex;
}
?>
import http.client

conn = http.client.HTTPSConnection("mb-api.mindbodyonline.com")

headers = {
    'api-key': "yourAPIKey",
    'authorization': "Basic Y2xpZW50S2V5OmNsaWVudFNlY3JldA=="
    }

conn.request("GET", "/affiliate/api/v1/locations/13909/classes", headers=headers)

res = conn.getresponse()
data = res.read()

print(data.decode("utf-8"))
require 'uri'
require 'net/http'

url = URI("https://mb-api.mindbodyonline.com/affiliate/api/v1/locations/13909/classes")

http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
http.verify_mode = OpenSSL::SSL::VERIFY_NONE

request = Net::HTTP::Get.new(url)
request["api-key"] = 'yourAPIKey'
request["authorization"] = 'Basic Y2xpZW50S2V5OmNsaWVudFNlY3JldA=='

response = http.request(request)
puts response.read_body

When making a call without an API-Key header, you will receive a 401 HTTP status code and the following error response:

{
    "error": {
        "errorCode": "14010001",
        "errorType": "missingAPIKeyHeader",
        "message": "Missing API-Key Header."
    }
}

When making a call without an Authorization header, you will receive a 401 HTTP status code and the following error response:

{
    "error": {
        "errorCode": "14010002",
        "errorType": "missingAuthorizationHeader",
        "message": "Missing Authorization Header."
    }
}

The Affiliate API uses API keys and basic access authentication. Once you have become an approved Mindbody Network Partner, you will receive an API key, a client key, and a client secret. To make a successful API call:

  1. Pass your API key as an API-Key header.
  2. Encode your client key and client secret, then pass the encoded string as an Authorization header, preceded by the word “Basic” and a space.

To correctly encode your client key and client secret, concatenate them together separated by a colon, then use a Base64 library to convert them to an encoded string. For example, if your client key is "clientKey" and your client secret is "clientSecret", you will encode the string, "clientKey:clientSecret". Once encoded, you would pass the value in an Authorization header as Basic {yourEncodedClientKeyAndClientSecret}.

If you make a call and either the API-Key or Authorization header contains an invalid value, you will receive a 401 HTTP status code and an empty response body.

If you have verified that you are using the correct authentication information (according to your account) and you are still receiving a 401, contact our developer support department.

HTTPS

All calls to the Affiliate API must use HTTPS connections, utilizing TLS v1.2 or higher. Any connections made via an older version of TLS are not guaranteed to work correctly.

Your Sandbox Environment

Once you have access to the Affiliate API, Mindbody will create sandboxed business data specific to your integration. This data is fictitious but structured in exactly the same way as a real business. You will have full access to these demo businesses for development and testing purposes; you can experiment with changing their settings and data from our web-base user interface.

For a detailed introduction to managing a business’ settings and data, check out Testing Best Practices.

After you have tested and finalized your integration, Mindbody will give you production access to the location, class, and pricing data in the Mindbody Network for which you have been approved. Unlike sandboxed data, you cannot access live business data via our web-based user interface. When you are ready to go live, contact our developer support team.

Working with Your User Data

The Affiliate API identifies users based on the uniqueUserId you pass to the POST Booking call. Once you have completed the user’s initial booking, you can use this ID to:

  • Create new bookings on a previously purchased pass
  • Find account details such as:
    • bookings
    • purchases
    • passes

The uniqueUserId must:

  • Be between 1 and 64 characters in length
  • Contain only:
    • alphanumeric characters (lowercase)
    • _ (underscores)
    • - (hyphens)
    • ~ (tildes)
    • . (periods)

Base URL

https://mb-api.mindbodyonline.com/affiliate/api/v1

Versioning

If Mindbody introduces an API change that breaks preexisting API contracts, we will create a new API version number and provide you with a transition guide.

Current Version: 1
Previous Version: NA

Pagination

Making Requests

Each Affiliate API endpoint will specify whether or not it supports pagination.

Endpoints that support pagination accept maxResults and offset query parameters.

maxResults specifies the maximum number of records you want the call to return. The documentation for each endpoint will call out the accepted maxResults values for that endpoint.

offset specifies the number of records you want the call to skip. If offset is not included in the request, the call does not skip any records.

Understanding Responses

Example of an API call that returns multiple results and supports pagination:

{
    "offset": 10,
    "maxResults": 10,
    "totalResults": 154,
    "items": [
        {
            "field1": "value1"
        }
    ]
}

Example of an API call that returns multiple results but does not support pagination:

{
    "items": [
        {
            "field1": "value1"
        }
    ]
}

Example of an API call that returns a single resource:

{
    "field1": "value1"
}
Name Type Description
offset number The number of records skipped over to reach the returned results.
maxResults number The maximum number of records returned in the results.
totalResults number The total number of records found that match the request parameters.
items array of objects Contains the records found by the query.

Ordering Results

The following example demonstrates how to order passes by their expiration date. The results of this call will show the pass that isexpiring soonest first and the pass that expiring latest last.

curl -X GET \
-A "{yourAppName}" \
-H "API-Key: {yourAPIKey}" \
-H "Authorization: Basic {yourEncodedClientKeyAndClientSecret}" \
"https://mb-api.mindbodyonline.com/affiliate/api/v1/users/{uniqueUserId}/passes?orderBy=expirationDateTime&order=desc"
var client = new RestClient("https://mb-api.mindbodyonline.com/affiliate/api/v1/users/{uniqueUserId}/passes?orderBy=expirationDateTime&order=desc");
var request = new RestRequest(Method.GET);
request.AddHeader("authorization", "Basic {yourEncodedClientKeyAndClientSecret}");
request.AddHeader("api-key", "{yourAPIKey}");
IRestResponse response = client.Execute(request);
<?php

$request = new HttpRequest();
$request->setUrl('https://mb-api.mindbodyonline.com/affiliate/api/v1/users/{uniqueUserId}/passes');
$request->setMethod(HTTP_METH_GET);

$request->setQueryData(array(
  'orderBy' => 'expirationDateTime',
  'order' => 'desc'
));

$request->setHeaders(array(
  'authorization' => 'Basic {yourEncodedClientKeyAndClientSecret}',
  'api-key' => '{yourAPIKey}'
));

try {
  $response = $request->send();

  echo $response->getBody();
} catch (HttpException $ex) {
  echo $ex;
}
?>
import http.client

conn = http.client.HTTPSConnection("mb-api.mindbodyonline.com")

headers = {
    'api-key': "{yourAPIKey}",
    'authorization': "Basic {yourEncodedClientKeyAndClientSecret}"
    }

conn.request("GET", "/api/v1/users/{uniqueUserId}/passes?orderBy=expirationDateTime&order=desc", headers=headers)

res = conn.getresponse()
data = res.read()

print(data.decode("utf-8"))
require 'uri'
require 'net/http'

url = URI("https://mb-api.mindbodyonline.com/affiliate/api/v1/users/{uniqueUserId}/passes?orderBy=expirationDateTime&order=desc")

http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
http.verify_mode = OpenSSL::SSL::VERIFY_NONE

request = Net::HTTP::Get.new(url)
request["api-key"] = '{yourAPIKey}'
request["authorization"] = 'Basic {yourEncodedClientKeyAndClientSecret}'

response = http.request(request)
puts response.read_body

Many of the endpoints in the Affiliate API let you order result sets by using the orderBy and order query parameters.

orderBy designates which field orders the results. The documentation for individual endpoints will call out both the default orderBy field and acceptable values for this parameter.

order orders the results in ascending or descending order based on the field specified by orderBy. Acceptable values are either "asc" or "desc". The documentation for each endpoint will call out the default order value for that endpoint.

Dates and Times

The Affiliate API returns and accepts dates and times in ISO 8601 format as defined by the RFC 339 specification.

In Requests

When you pass dates/times to the API, it treats them as UTC dates and ignores any time zone offset information included in the request. An example of an acceptable format is YYYY-MM-DDThh:mm:ssZ. You should convert any local date/time ranges you are working with to UTC when querying the API. For example, you would pass January 15th, 2017 at 8:00 AM (PST) to the API as "2017-01-15:T16:00:00Z" because PST is eight hours behind UTC.

In Responses

The API returns UTC dates/times. For example, a class that happens on January 5th, 2017 at 2:15PM (EST) would be represented by "2017-01-05T19:15:00Z" because EST is five hours behind UTC. All date/time pairs are returned in the format YYYY-MM-DDTHH:mm:ssZ.

We recommend that you give users a visual cue when they find classes outside their current time zone. You can convert the class’s start and end times into their local time zone by using the location.olsonTimeZone property returned on all class objects.

For example, John Smith lives in California but is flying to New York today for vacation. He wants to find a fitness class near his hotel. If he finds a class on your app that takes place at 7:00 PM, it is unclear whether it is eastern time or pacific; the class’s time is ambiguous, so John cannot know for sure when it takes place. For clarity, consider appending “(EST)”, “(local time)”, or “(7 hours from now)” to the class time.

Rate Limits

Rate limits are in place to ensure fast response times and stability. Too many requests within a small period of time may be rejected. If you need increased rate limits, please contact your account manager.

There are several strategies you can employ to avoid hitting your rate limits. Consider caching location and class information (we recommend caching for no longer than 24 hours).

Resource ID Conventions

When fetching information for a specific location, all IDs returned are unique within the scope of that location’s subscriber. For example, a class ID at a subscriber called “ACME Yoga” will always be unique, regardless of the number of locations that “ACME Yoga” has. However, when looking at classes at a different subscriber, for example “ACME Pilates”, you may see the same class IDs. Those are different classes, even though they might share IDs.

Subscriber, location, pass, purchase, and booking IDs are always globally unique.

Errors

In the Affiliate API, HTTP response codes indicate the status of a request.

  • Codes in the 200 range indicate success.
  • Codes in the 400 range indicate errors in the provided information (e.g., a required parameter was omitted, a parameter violated its minimum or maximum constraint, etc.).
  • Codes in the 500 range indicate errors from our servers. Please contact us immediately if you receive a 500 error.
{
    "error": {
        "errorCode": "14000001",
        "errorType": "missingAPIKeyHeader",
        "message": "Missing API-Key Header."
    }
}

The Affiliate API returns errors for many reasons. We recommend writing code that gracefully handles all possible errors as documented for each endpoint.

In addition to HTTP codes, the API returns a JSON error response object (as demonstrated on the right).

Name Type Description
errorCode string A code for the specific error returned. You can safely parse these values to numbers.
errorType string A categorical code indicating which aspect of the request was invalid.
message string A brief message explaining why you received the error.

Testing Best Practices

The data returned from the Affiliate API can and does change. Mindbody subscribers are constantly changing their classes, pricing, and locations – often as part of their marketing strategy, to increase their brand presence, or to expand their business.

As you develop your integration with the API, it is important that you test your app’s ability to correctly handle changes in the data. This is especially true when a change breaks a workflow. Email us to request a testing guide that will walk you through altering your Mindbody Demo Business Data so you can make sure your app is smoothly handling data changes.

Tutorials

Find services, pay, and book

Summary

This tutorial demonstrates how to use the Affiliate API to create an experience in which your user:

  1. Looks through Mindbody subscriber locations in their area
  2. Selects the location in which they are interested
  3. Chooses a class they want to book at the selected location
  4. Selects the pricing option they want to purchase to reconcile the class
  5. Enters their credit card and contact information
  6. Books into the class using their newly purchased pricing option

Workflow

  1. Call GET Locations and allow your user to select a location. At a minimum, store the location’s:

    1. id
    2. olsonTimeZone
    3. subscriber.id
    4. subscriber.creditCardTypesAccepted
    5. subscriber.hasLiabilityWaiver
  2. Using the stored location’s id, call GET Classes. Allow your user to select a class and store its id.

  3. Using the selected class’ stored id, call GET PricingOptions. Allow your user to select a pricing option, and store its id.

  4. Call POST Booking using the stored location, class, and pricing option IDs.

    We recommend using the stored subscriber.creditCardTypesAccepted (from Step 1 above) to ensure your users are not trying to use invalid credit cards.

    Upon receiving a successful booking response, we recommend displaying the booking’s:

    1. class.name
    2. class.startDateTime
    3. class.endDateTime
    4. class.registrationNotes
    5. staff.firstName
    6. subscriber.name
    7. location.name
    8. location.contactInfo (formatted appropriately)
  5. This step is optional, but recommended because it will ease the user’s front desk experience at the subscriber and in your app.

    Check the hasLiabilityWaiver bit that we stored in Step 1. If it is true, call GET LiabilityWaivers and collect the user’s signature as a PNG image. Next, call POST LiabilityWaivers to save the user’s signature to the subscriber.

    If possible, we recommend implementing your system so it tracks which users have already signed waivers for specific subscribers. Doing so allows you to request a signature from users only when the liability waiver text has changed or it’s their first time booking at the subscriber, rather than asking for a signature each time they book.

Book services with a pass

Summary

This tutorial demonstrates how to use the Affiliate API to create an experience in which your user:

  1. Looks through Mindbody subscriber locations in their area
  2. Selects the location in which they are interested
  3. Chooses a class they want to book at the selected location
  4. Selects a previously purchased pass
  5. Books into the class using their chosen pass

Workflow

  1. Call GET Passes and store the results.

  2. Call GET Locations and allow your user to select a location. At a minimum, store the location’s:

    1. id
    2. olsonTimeZone
    3. subscriber.id
    4. subscriber.hasLiabilityWaiver
  3. Using the stored location’s id, call GET Classes.

    Assuming passes were returned and stored in Step 1, check if any will reconcile classes at the selected location. When a pass and class’s subscriber.id match, and the class’s serviceCategoryIds array contains the pass’ serviceCategoryId, this indicates that the pass will reconcile the class. You can alter your display to indicate that the user already has a pass on file that would cover a visit to the matched class(es). For example, you may choose to display the word “Book” for classes that can be reconciled by the user’s passes.

    Allow your user to select a class and store its id.

  4. Call POST Booking using the stored location, class, and pass IDs.

    Upon receiving a successful booking response, we recommend displaying the booking’s:

    1. class.name
    2. class.startDateTime
    3. class.endDateTime
    4. class.registrationNotes
    5. staff.firstName
    6. subscriber.name
    7. location.name
    8. location.contactInfo (formatted appropriately)
  5. This step is optional, but recommended because it will ease the user’s front desk experience at the subscriber and in your app.

    Check the hasLiabilityWaiver bit that we stored in Step 1. If it is true, call GET LiabilityWaivers and collect the user’s signature as a PNG image. Next, call POST LiabilityWaivers to save the user’s signature to the subscriber.

    If possible, we recommend implementing your system so it tracks which users have already signed waivers for specific subscribers. Doing so allows you to request a signature from users only when the liability waiver text has changed or it’s their first time booking at the subscriber, rather than asking for a signature each time they book.

Find services paid for by a pass

Summary

This tutorial demonstrates how to use the Affiliate API to create an experience in which your user:

  1. Chooses a pass they want to use to book a class
  2. Is shown a list of available classes that the pass will pay for
  3. Selects the class they would like to book
  4. Books into the chosen class using the selected pass

Workflow

  1. Call GET Passes and allow your user to select a pass for which they want to find classes. At a minimum, store the selected pass’s:

    1. id
    2. serviceCategoryId
    3. purchase.id
    4. expirationDateTime
  2. Call GET Purchase by ID using the pass’ stored purchase.id, then store the purchase’s location.id.

  3. Call GET Classes using the purchase’s stored location.id.

    Pass the stored serviceCategoryId, in the call’s serviceCategoryIds query parameter.

    If it is not null, pass the stored expirationDateTime, in the call’s endDateTime query parameter. If it is null, do not pass the endDateTime query parameter.

    Allow your user to select a class and store its id.

  4. Call POST Booking using the stored location, class, and pass IDs.

    Upon receiving a successful booking response, we recommend displaying the booking’s:

    1. class.name
    2. class.startDateTime
    3. class.endDateTime
    4. class.registrationNotes
    5. staff.firstName
    6. subscriber.name
    7. location.name
    8. location.contactInfo (formatted appropriately)

Resources

Locations

Subscribers

Subscribers are companies that use Mindbody to manage their businesses. A subscriber can make their class and pricing information available in the Affiliate API by joining the Mindbody Network.

Locations

A location is the physical space where classes are held. Each subscriber must set up at least one location, but they could have multiple. For example, “ACME Pilates” might have studios on both South 1st Street and North 22nd Street. Each location will have a unique address.

GET

Getting a location by geo coordinates:

curl -X GET \
-H "API-Key: {yourAPIKey}" \
-H "Authorization: Basic {yourEncodedClientKeyAndClientSecret}" \
-A "{yourAppName}" \
"https://mb-api.mindbodyonline.com/affiliate/api/v1/locations?latitude=35.247137&longitude=-120.643215"
var client = new RestClient("https://mb-api.mindbodyonline.com/affiliate/api/v1/locations?latitude=35.247137&longitude=-120.643215");
var request = new RestRequest(Method.GET);
request.AddHeader("authorization", "Basic {yourEncodedClientKeyAndClientSecret}");
request.AddHeader("api-key", "{yourAPIKey}");
IRestResponse response = client.Execute(request);
<?php

$request = new HttpRequest();
$request->setUrl('https://mb-api.mindbodyonline.com/affiliate/api/v1/locations');
$request->setMethod(HTTP_METH_GET);

$request->setQueryData(array(
  'latitude' => '35.247137',
  'longitude' => '-120.643215'
));

$request->setHeaders(array(
  'authorization' => 'Basic {yourEncodedClientKeyAndClientSecret}',
  'api-key' => '{yourAPIKey}'
));

try {
  $response = $request->send();

  echo $response->getBody();
} catch (HttpException $ex) {
  echo $ex;
}
?>
import http.client

conn = http.client.HTTPSConnection("mb-api.mindbodyonline.com")

headers = {
    'api-key': "{yourAPIKey}",
    'authorization': "Basic {yourEncodedClientKeyAndClientSecret}"
    }

conn.request("GET", "/api/v1/locations?latitude=35.247137&longitude=-120.643215", headers=headers)

res = conn.getresponse()
data = res.read()

print(data.decode("utf-8"))
require 'uri'
require 'net/http'

url = URI("https://mb-api.mindbodyonline.com/affiliate/api/v1/locations?latitude=35.247137&longitude=-120.643215")

http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
http.verify_mode = OpenSSL::SSL::VERIFY_NONE

request = Net::HTTP::Get.new(url)
request["api-key"] = '{yourAPIKey}'
request["authorization"] = 'Basic {yourEncodedClientKeyAndClientSecret}'

response = http.request(request)
puts response.read_body

Getting a location by address:

curl -X GET \
-H "API-Key: {yourAPIKey}" \
-H "Authorization: Basic {yourEncodedClientKeyAndClientSecret}" \
-A "{yourAppName}" \
"https://mb-api.mindbodyonline.com/affiliate/api/v1/locations?address=4051%20Broad%20St%2C%20San%20Luis%20Obispo%2C%20CA%2C%2093401"
var client = new RestClient("https://mb-api.mindbodyonline.com/affiliate/api/v1/locations?address=4051%20Broad%20St%2C%20San%20Luis%20Obispo%2C%20CA%2C%2093401");
var request = new RestRequest(Method.GET);
request.AddHeader("authorization", "Basic {yourEncodedClientKeyAndClientSecret}");
request.AddHeader("api-key", "{yourAPIKey}");
IRestResponse response = client.Execute(request);
<?php

$request = new HttpRequest();
$request->setUrl('https://mb-api.mindbodyonline.com/affiliate/api/v1/locations');
$request->setMethod(HTTP_METH_GET);

$request->setQueryData(array(
  'address' => '4051 Broad St, San Luis Obispo, CA, 93401'
));

$request->setHeaders(array(
  'authorization' => 'Basic {yourEncodedClientKeyAndClientSecret}',
  'api-key' => '{yourAPIKey}'
));

try {
  $response = $request->send();

  echo $response->getBody();
} catch (HttpException $ex) {
  echo $ex;
}
?>
import http.client

conn = http.client.HTTPSConnection("mb-api.mindbodyonline.com")

headers = {
    'api-key': "{yourAPIKey}",
    'authorization': "Basic {yourEncodedClientKeyAndClientSecret}"
    }

conn.request("GET", "/affiliate/api/v1/locations?address=4051%20Broad%20St%2C%20San%20Luis%20Obispo%2C%20CA%2C%2093401", headers=headers)

res = conn.getresponse()
data = res.read()

print(data.decode("utf-8"))
require 'uri'
require 'net/http'

url = URI("https://mb-api.mindbodyonline.com/affiliate/api/v1/locations?address=4051%20Broad%20St%2C%20San%20Luis%20Obispo%2C%20CA%2C%2093401")

http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
http.verify_mode = OpenSSL::SSL::VERIFY_NONE

request = Net::HTTP::Get.new(url)
request["api-key"] = '{yourAPIKey}'
request["authorization"] = 'Basic {yourEncodedClientKeyAndClientSecret}'

response = http.request(request)
puts response.read_body

https://mb-api.mindbodyonline.com/affiliate/api/v1/locations

This endpoint searches for locations in the following ways:

  1. By address
  2. By longitude and latitude
  3. By countryCode
  4. By locationId
  5. By subscriberId
  6. By searchText

Some of the above search methods cannot be mixed. See query parameters on this call for more information. If none of the above query parameters are passed, all locations are returned.

You can retrieve a specific location either by utilizing the locationId query parameter or by calling GET (by ID).

Pagination

This endpoint supports pagination.

Best Practices

  • Use when looking for locations near a specific address.
  • Use when looking for locations near a geo-location (latitude/longitude pair).
  • Use to retrieve a specific location’s details.
  • Use when searching for locations associated with a specific keyword or search phrase.
  • Use when pulling the cancellation or refund policy text for a specific subscriber.
  • Use before calling GET Classes.
  • Use the returned subscriber.creditCardTypesAccepted to indicate the kinds of credit cards the subscriber accepts. We recommend showing this information to your users prior to allowing them to complete a booking.

Headers

Name Type Description
API-Key string Your API key.
Authorization string Your encoded client key and client secret.
See Authentication and Security for help creating this string.

Query Parameters

Name Type Description
latitude
Optional: When omitted, you must also omit longitude.
number The latitude portion of the latitude/longitude pair that acts as the geographical center of your location search. When searching based on geographical coordinates, you must use both latitude and longitude and may additionally use the following query parameters:
  • subscriberId
  • radius
  • countryCode
  • searchText
  • locationId
max: 90 | min: -90
longitude
Optional: When omitted, you must also omit latitude.
number The longitude portion of the latitude/longitude pair that acts as the geographical center of your location search. When searching based on geographical coordinates, you must use longitude with latitude and may additionally use the following query parameters:
  • subscriberId
  • radius
  • countryCode
  • searchText
  • locationId
max: 180 | min: -180
address
Optional
string The address that acts as the geographical center of your location search. You can use the city or postal code portion of the address if a full address is not available.
You can use address with the following query parameters:
  • subscriberId
  • radius
  • countryCode
  • searchText
  • locationId
Examples:
?address=4051 Broad St,San Luis Obispo,CA,93401
?address=San Luis Obispo,CA
?address=93401max length: 100
radius
Optional
number Used with the geographical center of your search, radius sets the area (in miles) for the search. When you pass radius, make sure you also pass either an address, or a latitude/longitude pair, otherwise the call will fail.default: 15 | max: 60 | min: 0
locationId
Optional
number Filters the results down to the single location identified by this ID. You can use locationId with any other valid query parameter combination, or by itself. This is the id property on the location object returned from this call and the location.id property returned from other calls in the API.
subscriberId
Optional
number Filters the results down to locations that belong to the subscriber identified by this ID. You can use subscriberId with any other valid query parameter combination, or by itself. This is the subscriber.id property returned on most calls in the API, including this one.
countryCode
Optional
string Filters results to only show locations within the specified country (based on the ISO ALPHA-2 country code specification).

Accepted Values:
  • US
You can use countryCode with any other valid query parameter combination, or by itself.
searchText
Optional
string Filters the results down to locations where the passed in searchText matches text in the location name and subscriber name. Locations where the searchText matches the category of services that the business is likely to offer are also returned. Please note that when searching by searchText, we make a good attempt at matching businesses and services, but the locations included in the result set are not guaranteed to offer the services being searched for.

Example Values:
  • Barre
  • Bootcamp
  • Boxing
  • Circuit Training
  • CrossFit
  • Dance
  • Group
  • Gym
  • High Intensity Training
  • Hot Yoga
  • Indoor Cycling
  • Kickboxing
  • Martial Arts
  • MMA
  • Personal Training
  • Pilates
  • Rock Climbing
  • Spin
  • Strength Training
  • Yoga
You can use searchText with any other valid query parameter combination, or by itself.
maxResults
Optional
number Sets the maximum number of records returned in the results.default: 500 | max: 1000 | min: 0
offset
Optional
number Sets the number of records skipped over to reach the returned results.default: 0 | min: 0
orderBy
Optional
string Designates which field in the response body orders the results.

Accepted Values:
  • locationId
  • locationName
  • subscriberId
  • subscriberName
  • ratingsTotal
  • ratingsAverage
  • postalCode
  • stateCode
Defaults (in order of priority):
  1. If searchText is passed, it takes priority – locations are ordered by how closely they match the passed text.
  2. When a geographical center is established for the search (by passing either an address or latitude/longitude pair), locations are ordered based on their distance from that center.
  3. When neither of the above apply, locations are ordered by their ids.
The above defaults only apply if you do not pass an orderBy query parameter with your request.
order
Optional
string Orders the results in ascending or descending order based on the field specified by orderBy.

Accepted Values:
  • asc
  • desc
default: asc

Response

HTTP Status Code: 200 OK

{
    "items": [
        {
            "id": 13540,
            "name": "ACME Yoga",
            "description": null,
            "olsonTimeZone": "America/Los_Angeles",
            "ratings": {
                "total": 150,
                "average": 4.32
            },
            "subscriber": {
                "id": 1354158,
                "name": "ACME Yoga",
                "description": null,
                "website": "http://www.acmeyoga.com",
                "cancellationPolicy": null,
                "refundPolicy": null,
                "locale": "en-US",
                "hasLiabilityWaiver": false,
                "imageUrls": [],
                "creditCardTypesAccepted": [
                    "Visa",
                    "MasterCard",
                    "Discover",
                    "AmericanExpress"
                ]
            },
            "contactInfo": {
                "phone": "5551231234",
                "streetAddress": "4051 Broad St Suite 220",
                "city": "San Luis Obispo",
                "stateCode": "CA",
                "postalCode": "93401",
                "countryCode": "US",
                "longitude": -120.642881,
                "latitude": 35.247461
            },
            "distance": 1.23
        }
    ],
    "offset": 0,
    "maxResults": 1,
    "totalResults": 79
}

Name Type Description
id number The location’s globally unique ID.
name string The location’s name.
description string The location’s subscriber-configured description.
olsonTimeZone string The location’s time zone in Olson format (e.g., "America/Los_Angeles"). Possible time zones.
ratings object Contains rating information for the location.
ratings.total number The total number of times users have rated classes at this location.
ratings.average number The average quality rating (out of 5 stars, e.g., 3.26).
subscriber object Contains information about the subscriber to whom the location belongs.
subscriber.id number The subscriber’s globally unique ID.
subscriber.name string The subscriber’s name.
subscriber.description string The subscriber’s business description.
subscriber.website string The URL for the subscriber’s main website.
subscriber.cancellationPolicy string The subscriber’s cancellation policy text.
subscriber.refundPolicy string The subscriber’s refund policy text.
subscriber.locale string The primary spoken language used at the subscriber, represented by a C# culture string (e.g., "en-US" for United States English). Possible cultures.
subscriber.hasLiabilityWaiver boolean When true, indicates that the subscriber requires new users to agree to a liability waiver. We recommend prompting your users to sign a liability waiver for locations where this is true to ease their front-desk experience at the subscriber. See GET LiabilityWaivers and POST LiabilityWaivers.

When false, indicates that the subscriber does not require new users to agree to a liability waiver.
subscriber.imageURLs array of objects Contains information about the different sizes of images available for the subscriber’s logo.
subscriber.imageURLs.size string The size of the image.

Possible Values:
  • "XLarge" - The subscriber’s logo image with a maximum width and height of 600 pixels.
  • "Large" - The subscriber’s logo image with a maximum width and height of 200 pixels.
  • "Unscaled" - The subscriber’s logo image with its original size. Subscribers cannot have images larger than 4MB.
subscriber.imageURLs.url string The URL for the image.

subscriber.creditCardTypesAccepted array of strings Which credit card types the subscriber will accept as a form of payment.

Possible Values:
  • "Visa"
  • "AmericanExpress"
  • "MasterCard"
  • "Discover"
We recommend using this array to validate all credit cards passed to the POST Booking endpoint for this location’s subscriber.We recommend using this array to validate all credit cards passed to the POST Booking endpoint for this location’s subscriber.
contactInfo object Contains contact information for the location.
contactInfo.phone string The location’s phone number.
contactInfo.streetAddress string The street address portion of the location’s address.
contactInfo.city string The city portion of the location’s address.
contactInfo.stateCode string The state code portion of the location’s address (e.g. "CA" for California in the USA.).
contactInfo.postalCode string The postal code portion of the location’s address.
contactInfo.countryCode string The location’s country (e.g., "US"). This value will always be an ISO ALPHA-2 Code.
contactInfo.longitude number The location’s longitude.
contactInfo.latitude number The location’s latitude.
distance number The distance in miles between the location and the geographical center of your search. This value may be null if a geographical center could not be calculated for your search.

Errors

Example Error:

{
    "error": {
        "errorCode": "14000004",
        "errorType": "invalidParameter",
        "message": "The following parameter is invalid: radius."
    }
}

This endpoint may return the errors listed below. We recommend that you catch and handle each error for an optimal, frictionless user experience. We also recommend attempting to reproduce each error during your development and test process in order to ensure that your back-end application is handling them correctly.

HTTP Status Code errorCode errorType Description
400 14000004 invalidParameter Returned when a query parameter:
  • Has violated its minimum acceptable value
  • Has violated its maximum acceptable value
  • Is required but is missing
Check the error’s message property to find the name of the invalid query parameter.
400 14000006 invalidParameterCombination Returned if you pass a query parameter with another query parameter that cannot be used with the first (e.g., passing a lat/long pair as well as an address).
401 14010001 missingAPIKeyHeader An API-Key header was not included in the request.
401 14010002 missingAuthorizationHeader An Authorization header was not included in the request.
429 14290001 tooManyRequests You have exceeded the rate limit for this endpoint.
429 14290002 dailyRequestLimitExceeded You have exceeded the daily request limit for this endpoint.

GET (by ID)

curl -X GET \
-H "API-Key: {yourAPIKey}" \
-H "Authorization: Basic {yourEncodedClientKeyAndClientSecret}" \
-A "{yourAppName}" \
"https://mb-api.mindbodyonline.com/affiliate/api/v1/locations/{locationId}"
var client = new RestClient("https://mb-api.mindbodyonline.com/affiliate/api/v1/locations/{locationId}");
var request = new RestRequest(Method.GET);
request.AddHeader("authorization", "Basic {yourEncodedClientKeyAndClientSecret}");
request.AddHeader("api-key", "{yourAPIKey}");
IRestResponse response = client.Execute(request);
<?php

$request = new HttpRequest();
$request->setUrl('https://mb-api.mindbodyonline.com/affiliate/api/v1/locations/{locationId}');
$request->setMethod(HTTP_METH_GET);

$request->setHeaders(array(
  'authorization' => 'Basic {yourEncodedClientKeyAndClientSecret}',
  'api-key' => '{yourAPIKey}'
));

try {
  $response = $request->send();

  echo $response->getBody();
} catch (HttpException $ex) {
  echo $ex;
}
?>
import http.client

conn = http.client.HTTPSConnection("mb-api.mindbodyonline.com")

headers = {
    'api-key': "{yourAPIKey}",
    'authorization': "Basic {yourEncodedClientKeyAndClientSecret}"
    }

conn.request("GET", "/api/v1/locations/{locationId}", headers=headers)

res = conn.getresponse()
data = res.read()

print(data.decode("utf-8"))
require 'uri'
require 'net/http'

url = URI("https://mb-api.mindbodyonline.com/affiliate/api/v1/locations/{locationId}")

http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
http.verify_mode = OpenSSL::SSL::VERIFY_NONE

request = Net::HTTP::Get.new(url)
request["api-key"] = '{yourAPIKey}'
request["authorization"] = 'Basic {yourEncodedClientKeyAndClientSecret}'

response = http.request(request)
puts response.read_body

https://mb-api.mindbodyonline.com/affiliate/api/v1/locations/{locationId}

This endpoint finds and returns the single location associated with the passed ID.

Pagination

This endpoint does not support pagination.

Best Practices

  • Use when looking for full location details when you already have the location’s ID.

Headers

Name Type Description
API-Key string Your API key.
Authorization string Your encoded client key and client secret.
See Authentication and Security for help creating this string.

URL Parameters

Name Type Description
locationId number Returns the single location identified by this ID. This is the id property on the location object returned from this call and the location.id property returned from other calls in the API.

Response

Partial example of response content structure:

{
    "olsonTimeZone": "America/Los_Angeles",
    "id": 13540,
    ...
}

This response object is the same as the objects contained in the items field in the GET Locations response . View that documentation for detailed information about the response object’s fields.

Errors

Example Error:

{
    "error": {
        "errorCode": "14040001",
        "errorType": "locationNotFound",
        "message": "Location not found."
    }
}

This endpoint may return the errors listed below. We recommend that you catch and handle each error for an optimal, frictionless user experience. We also recommend attempting to reproduce each error during your development and test process in order to ensure that your back-end application is handling them correctly.

HTTP Status Code errorCode errorType Description
401 14010001 missingAPIKeyHeader An API-Key header was not included in the request.
401 14010002 missingAuthorizationHeader An Authorization header was not included in the request.
404 14040001 locationNotFound The locationId passed as a URL Parameter was not found.
429 14290001 tooManyRequests You have exceeded the rate limit for this endpoint.
429 14290002 dailyRequestLimitExceeded You have exceeded the daily request limit for this endpoint.

Classes

Classes

Classes have specific dates, start and end times, and represent actual events that your users can book into. Each class is taught by a staff member and has a capacity that defines the maximum number of bookings the class will accept.

Class types differentiate classes within a subscriber. For example, “Vinyasa Yoga” and “Hatha Yoga” are two different class types. A subscriber may schedule a class type multiple times. For example, ACME Yoga, has scheduled a “Vinyasa Yoga,” class on Mondays from 10:00 AM to 11:00 AM as well as on Wednesdays from 2:00 PM to 3:00 PM; both of these classes have the same class type.

A class refers to an individual occurrence of a class type. For example, the “Vinyasa Yoga” class scheduled on Monday, 9/19/2016 from 10:00 AM to 11:00 AM is a single class.

Available capacity refers to the number of remaining bookings available for a specific class. For example, if a class allows a maximum of 10 bookings and currently has 6, the class has an available capacity of 4.

Service Categories

Service categories are groups of classes that share pricing options. As part of the set-up process, subscribers assign each class to a specific service category. Once assigned, a class’ service category does not change.

By default, classes can only be reconciled either through the purchase of a new pricing option or by reusing a previously purchased pass. However, subscribers can relate service categories so that a pricing option in one category can pay for classes in another. Each class’ serviceCategoryIds property contains all service categories that will pay for the class.

GET

curl -X GET \
-H "API-Key: {yourAPIKey}" \
-H "Authorization: Basic {yourEncodedClientKeyAndClientSecret}" \
-A "{yourAppName}" \
"https://mb-api.mindbodyonline.com/affiliate/api/v1/locations/{locationId}/classes"
var client = new RestClient("https://mb-api.mindbodyonline.com/affiliate/api/v1/locations/{locationId}/classes");
var request = new RestRequest(Method.GET);
request.AddHeader("authorization", "Basic {yourEncodedClientKeyAndClientSecret}");
request.AddHeader("API-Key", "{yourAPIKey}");
IRestResponse response = client.Execute(request);
<?php

$request = new HttpRequest();
$request->setUrl('https://mb-api.mindbodyonline.com/affiliate/api/v1/locations/{locationId}/classes');
$request->setMethod(HTTP_METH_GET);

$request->setHeaders(array(
  'authorization' => 'Basic {yourEncodedClientKeyAndClientSecret}',
  'API-Key' => '{yourAPIKey}'
));

try {
  $response = $request->send();

  echo $response->getBody();
} catch (HttpException $ex) {
  echo $ex;
}
?>
import http.client

conn = http.client.HTTPSConnection("mb-api.mindbodyonline.com")

headers = {
    'API-Key': "{yourAPIKey}",
    'authorization': "Basic {yourEncodedClientKeyAndClientSecret}"
    }

conn.request("GET", "/api/v1/locations/{locationId}/classes", headers=headers)

res = conn.getresponse()
data = res.read()

print(data.decode("utf-8"))
require 'uri'
require 'net/http'

url = URI("https://mb-api.mindbodyonline.com/affiliate/api/v1/locations/{locationId}/classes")

http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
http.verify_mode = OpenSSL::SSL::VERIFY_NONE

request = Net::HTTP::Get.new(url)
request["API-Key"] = '{yourAPIKey}'
request["authorization"] = 'Basic {yourEncodedClientKeyAndClientSecret}'

response = http.request(request)
puts response.read_body

https://mb-api.mindbodyonline.com/affiliate/api/v1/locations/{locationId}/classes

This endpoint gets classes that are taking place at a specific location.

You can retrieve a specific class by calling GET (by ID).

Pagination

This endpoint supports pagination.

Best Practices

Headers

Name Type Description
API-Key string Your API key.
Authorization string Your encoded client key and client secret.
See Authentication and Security for help creating this string.

URL Parameters

Name Type Description
locationId number Specifies from which location to fetch classes. This is the id property on the location object returned from this call and the location.id property returned from other calls in the API.

Query Parameters

Name Type Description
startDateTime
Optional
string The UTC date/time that sets the beginning of the time-frame within which you are searching for classes. Classes with UTC start times on or after this date/time are returned.

See Dates and Times in Requests for more information.default: now | max: 365 days from now | min: now
endDateTime
Optional
string The UTC date/time that sets the end of the time-frame within which you are searching for classes. Classes with UTC start times before this date/time are returned.

See Dates and Times in Requests for more information.default: 14 days from now | max: 365 days from now | min: now
classTypeId
Optional
number Filters the results down to classes that have the specified class type. This is the typeId property on the class object returned from this call.
staffLastName
Optional
string Filters the results down to classes with staff members whose last names match this parameter. This is the staff.lastName property in the class object returned from this call. This parameter does not filter on assistant teacher names.max length: 50
availableForBooking
Optional: When omitted, the results contain all classes regardless of current capacity.
boolean When true, filters the results to classes:
  1. with available capacity
  2. where the current time falls within the class’s booking window
When false, filters the results to classes:
  1. with no available capacity
  2. where the current time falls outside the class’s booking windows
serviceCategoryIds
Optional
string Filters the results down to classes paid for by the specified service category or categories. Pass multiple service categories in a comma-separated list.

For example, ?serviceCategoryIds=24,8 would return classes paid for by service category 24, service category 8, or both.

Classes paid for by related service categories will also be returned in this call. For example, if a service category with an ID of 5 pays for a service category with an ID of 9, ?serviceCategoryIds=9 will return classes that can be paid for by either category.

The serviceCategoryIds property on the class object returned from this call contains this value.
maxResults
Optional
number Sets the maximum number of records returned in the results.default: 500 | max: 1000 | min: 0
offset
Optional
number Sets the number of records skipped over to reach the returned results.default: 0 | min: 0
orderBy
Optional
string Designates which field in the response body orders the results.

Accepted Values:
  • startDateTime
  • endDateTime
  • name
  • priceLowest
  • priceHighest
default: startDateTime
order
Optional
string Orders the results in ascending or descending order based on the field specified by orderBy.

Accepted Values:
  • asc
  • desc
default: asc

Response

HTTP Status Code: 200 OK

{
    "items": [
        {
            "id": 31034,
            "typeId": 7,
            "name": "Beginning Hatha Yoga",
            "description": "A gentle introduction to the Hatha practice.",
            "classSize": 15,
            "availableCapacity": 7,
            "registrationNotes": "Bring a yoga mat and a large bottle of water.",
            "startDateTime": "2016-12-15T17:00:00Z",
            "endDateTime": "2016-12-15T18:00:00Z",
            "assistantNames": [],
            "roomName": null,
            "bookingWindow": {
                "startDateTime": "2016-12-15T14:13:26.737Z",
                "endDateTime": "2016-12-15T17:00:00Z",
                "dailyStartTime": null,
                "dailyEndTime": null
            },
            "cancellationsAllowed": true,
            "cancellationWindowEndTime": "2016-12-15T16:00:00Z",
            "serviceCategoryIds": [
                25
            ],
            "sessionsDeducted": 1,
            "availability": {
                "statusCode": 10,
                "message": "Available for booking"
            },
            "price": {
                "lowest": 15,
                "highest": 80
            },
            "classImageURLs": [
                {
                    "size": "XLarge",
                    "url": "https://clients.mindbodyonline.com
                    /studios/ACMEYoga/reservations/7_xLarge.jpg?v=23"
                },
                {
                    "size": "Large",
                    "url": "https://clients.mindbodyonline.com
                    /studios/ACMEYoga/reservations/7_large.jpg?v=23"
                },
                {
                    "size": "Unscaled",
                    "url": "https://clients.mindbodyonline.com
                    /studios/ACMEYoga/reservations/7_.jpg?v=23"
                }
            ],
            "staff": {
                "id": 3,
                "firstName": "Thomas",
                "lastName": "Jones",
                "gender": "Male",
                "staffImageURLs": [
                    {
                        "size": "XLarge",
                        "url": "https://clients.mindbodyonline.com
                        /studios/ACMEYoga/staff/3_xLarge.jpg?v=23"
                    },
                    {
                        "size": "Large",
                        "url": "https://clients.mindbodyonline.com
                        /studios/ACMEYoga/staff/3_large.jpg?v=23"
                    },
                    {
                        "size": "Mobile",
                        "url": "https://clients.mindbodyonline.com
                        /studios/ACMEYoga/staff/3_mobile.jpg?v=23"
                    }
                ],
                "bio": null
            },
            "location": {
                "id": 12856,
                "name": "ACME Yoga",
                "olsonTimeZone": "America/Los_Angeles",
                "subscriber": {
                    "id": 13548,
                    "name": "ACME Yoga"
                }
            },
            "category": {
                "id": 194,
                "name": "Yoga"
            },
            "subCategory": {
                "id": 199,
                "name": "Hatha"
            },
            "isVirtual": true
        }
    ],
    "offset": 0,
    "maxResults": 1,
    "totalResults": 213
}
Name Type Description
id number The ID for this specific class at the current subscriber; the class’s ID.
typeId number The ID for the class’s class type within the current subscriber.
name string The name of the class.
description string The class’ subscriber-configured description. This string contains HTML.
classSize number The class’s capacity; how many total bookings the class accepts.
availableCapacity number The number of remaining bookings for the class (e.g., A class with a classSize of 10 with 6 spaces booked has an availableCapacity of 4.). This value will be -9999 if the subscriber has configured classes to hide this information from users.
registrationNotes string Special notes or instructions the subscriber wants to relay to users who are booking the class. For example, "Make sure you bring a sweat towel and bottle of water!".
startDateTime string The date and time when the class starts (in UTC).

See Dates and Times in Responses for more information.
endDateTime string The date and time when the class ends (in UTC).

See Dates and Times in Responses for more information.
assistantNames array of strings Contains the names of all assistant teachers assigned to the class.
roomName string The name of the room where the class is held (e.g., "Sun Room" or "Studio A"). This value might be null if the subscriber has hidden class rooms.
bookingWindow object Contains information that specifies when users can book the class. If the current time is outside this booking window, you can use this information to give users a time-frame when they will be able to make bookings.
bookingWindow.startDateTime string The date and time after which the class accepts bookings (in UTC).

See Dates and Times in Responses for more information.
bookingWindow.endDateTime string The date and time after which the class no longer accepts bookings (in UTC).

See Dates and Times in Responses for more information.
bookingWindow.dailyStartTime string The time of day after which the class accepts bookings (in UTC).

See Dates and Times in Responses for more information.
bookingWindow.dailyEndTime string The time of day after which bookings are no longer accepted for the class (in UTC).

See Dates and Times in Responses for more information.
cancellationsAllowed boolean When true, indicates that the subscriber allows users to cancel bookings they make in this class, up to the cancellationWindowEndTime.

When false, indicates that the subscriber does not allow users to cancel bookings they make in this class, regardless of the cancellationWindowEndTime.
cancellationWindowEndTime string The date and time after which cancellations can no longer be made for bookings in the class (in UTC).

See Dates and Times in Responses for more information.
serviceCategoryIds array of numbers The IDs of the service categories whose pricing options can pay for the class.
sessionsDeducted number The number of sessions consumed from passes used to pay for this class. For example, a subscriber may configure their system so that a 30-minute class consumes 1 session while a 60-minute class consumes 2 sessions.
availability object Contains information that determines whether or not users can book the class. You may want to display classes that are not currently available for booking to your users, because they may be available for booking at another date or time. If you do show unavailable classes, it is a very important design best practice to give a visual indicator to your users so they know that the class is not currently available for booking.
availability.statusCode number A numeric code identifying whether or not users can book the class.

Possible Values:
  • 10 - Indicates that users can book the class.
  • 50 - Indicates that users cannot book the class because of booking windows configured by the subscriber.
  • 60 - Indicates that the class is full, but the user should contact the subscriber to see if they can attend the class; there might be space in the class, but it is not exposed to users.
  • 70 - Indicates that users cannot book the class because it is full; do not prompt the user to contact the subscriber.
  • 80 - Indicates that the subscriber cancelled the class; users can no longer book into it.
availability.message string A short, informative message that describes why the above statusCode was returned.
price object Contains pricing information for the class.
price.lowest number The cost of the least expensive pricing option that can pay for this class.
price.highest number The cost of the most expensive pricing option that can pay for this class.
classImageURLs array of objects Contains information about the different sizes of images available for the class.
classImageURLs.size string The size of the image.

Possible Values:
  • "XLarge" - The class’s image with a maximum width and height of 600 pixels.
  • "Large" - The class’s image with a maximum width and height of 200 pixels.
  • "Unscaled" - The class’s image with its original size. Classes cannot have images larger than 4MB.
classImageURLs.url string The URL for the image.

staff object Contains information about the staff member who teaches the class.
staff.id number The staff member’s ID within the current subscriber.
staff.firstName string The staff member’s first name. This value might be null if the subscriber has hidden staff names.

If the subscriber uses staff nicknames, this value will be the staff’s nickname if they have one configured.
staff.lastName string The staff member’s last name. This value will be null if the subscriber has hidden staff names.

If the subscriber uses staff nicknames, this value will be null if the staff member has a nickname configured.
staff.gender string The staff member’s gender.

Possible Values:
  • "Male"
  • "Female"
staff.staffImageURLs array of objects Contains information about the different sizes of images available for the staff member.
staff.staffImageURLs.size string The size of the image.

Possible Values:
  • "XLarge" - The staff’s image with a maximum width and height of 600 pixels.
  • "Large" - The staff’s image with a maximum width and height of 200 pixels.
  • "Mobile" - The staff’s image with a maximum width and height of 128 pixels.
staff.staffImageURLs.url string The URL for the image.

staff.bio string The staff member’s biography.
location object Contains information about the location where the class is taking place.
location.id number The location’s globally unique ID.
location.name string The location’s name.
location.olsonTimeZone string The location’s time zone in Olson format (e.g., "America/Los_Angeles"). Possible time zones.
location.subscriber object Contains information about the subscriber to whom the location belongs.
location.subscriber.id number The subscriber’s globally unique ID.
location.subscriber.name string The subscriber’s name.
category object Contains information about the category assigned to the class. Categories are assigned to classes to help further describe the offering and provide a common tag for grouping.
category.id number The category’s ID.
category.name string The category’s name.
subCategory object Contains information about the sub-category assigned to the class.
subCategory.id number The sub-category’s ID.
subCategory.name string The sub-category’s name.
isVirtual boolean When true, indicates that the class supports livestreaming.

When false, indicates that the class does not support livestreaming.

Errors

Example Error:

{
    "error": {
        "errorCode": "14000004",
        "errorType": "invalidParameter",
        "message": "The following parameter is invalid: radius."
    }
}

This endpoint may return the errors listed below. We recommend that you catch and handle each error for an optimal, frictionless user experience. We also recommend attempting to reproduce each error during your development and test process in order to ensure that your back-end application is handling them correctly.

HTTP Status Code errorCode errorType Description
400 14000004 invalidParameter Returned when a query parameter:
  • Has violated its minimum acceptable value
  • Has violated its maximum acceptable value
  • Is required but is missing
  • Is used with other incompatible query parameters
Check the error’s message property to find the name of the invalid query parameter.
401 14010001 missingAPIKeyHeader An API-Key header was not included in the request.
401 14010002 missingAuthorizationHeader An Authorization header was not included in the request.
404 14040001 locationNotFound The locationId passed as a URL Parameter was not found.
429 14290001 tooManyRequests You have exceeded the rate limit for this endpoint.
429 14290002 dailyRequestLimitExceeded You have exceeded the daily request limit for this endpoint.

GET (by ID)

curl -X GET \
-H "API-Key: {yourAPIKey}" \
-H "Authorization: Basic {yourEncodedClientKeyAndClientSecret}" \
-A "{yourAppName}" \
"https://mb-api.mindbodyonline.com/affiliate/api/v1/locations/{locationId}/classes/{classId}"
var client = new RestClient("https://mb-api.mindbodyonline.com/affiliate/api/v1/locations/{locationId}/classes/{classId}");
var request = new RestRequest(Method.GET);
request.AddHeader("authorization", "Basic {yourEncodedClientKeyAndClientSecret}");
request.AddHeader("api-key", "{yourAPIKey}");
IRestResponse response = client.Execute(request);
<?php

$request = new HttpRequest();
$request->setUrl('https://mb-api.mindbodyonline.com/affiliate/api/v1/locations/{locationId}/classes/{classId}');
$request->setMethod(HTTP_METH_GET);

$request->setHeaders(array(
  'authorization' => 'Basic {yourEncodedClientKeyAndClientSecret}',
  'api-key' => '{yourAPIKey}'
));

try {
  $response = $request->send();

  echo $response->getBody();
} catch (HttpException $ex) {
  echo $ex;
}
?>
import http.client

conn = http.client.HTTPSConnection("mb-api.mindbodyonline.com")

headers = {
    'api-key': "{yourAPIKey}",
    'authorization': "Basic {yourEncodedClientKeyAndClientSecret}"
    }

conn.request("GET", "/api/v1/locations/{locationId}/classes/{classId}", headers=headers)

res = conn.getresponse()
data = res.read()

print(data.decode("utf-8"))
require 'uri'
require 'net/http'

url = URI("https://mb-api.mindbodyonline.com/affiliate/api/v1/locations/{locationId}/classes/{classId}")

http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
http.verify_mode = OpenSSL::SSL::VERIFY_NONE

request = Net::HTTP::Get.new(url)
request["api-key"] = '{yourAPIKey}'
request["authorization"] = 'Basic {yourEncodedClientKeyAndClientSecret}'

response = http.request(request)
puts response.read_body

https://mb-api.mindbodyonline.com/affiliate/api/v1/locations/{locationId}/classes/{classId}

This endpoint finds and returns the single class associated with the passed ID.

Pagination

This endpoint does not support pagination.

Best Practices

  • Use to fetch class details for a specific class. You must already have the class’s ID and the class’s location ID.

Headers

Name Type Description
API-Key string Your API key.
Authorization string Your encoded client key and client secret.
See Authentication and Security for help creating this string.

URL Parameters

Name Type Description
locationId number Specifies from which location you are fetching the specific class. This is the id property on the location object returned from GET Locations.
classId number Returns the single class identified by this ID. This is the id property on the class object returned from this call and the class.id property returned from other calls in the API.

Response

Partial example of response content structure:

{
    "id": 31034,
    "typeId": 7,
    ...
}

This response object is the same as the objects contained in the items field in the GET Classes response . View that documentation for detailed information about the response object’s fields.

Errors

Example Error:

{
    "error": {
        "errorCode": "14040005",
        "errorType": "classNotFound",
        "message": "Class not found."
    }
}

This endpoint may return the errors listed below. We recommend that you catch and handle each error for an optimal, frictionless user experience. We also recommend attempting to reproduce each error during your development and test process in order to ensure that your back-end application is handling them correctly.

HTTP Status Code errorCode errorType Description
401 14010001 missingAPIKeyHeader An API-Key header was not included in the request.
401 14010002 missingAuthorizationHeader An Authorization header was not included in the request.
404 14040001 locationNotFound The locationId passed as a URL Parameter was not found.
404 14040005 classNotFound The classId passed as a URL Parameter was not found.
429 14290001 tooManyRequests You have exceeded the rate limit for this endpoint.
429 14290002 dailyRequestLimitExceeded You have exceeded the daily request limit for this endpoint.

PricingOptions

Pricing Options

When a user pays for a class, they are actually purchasing a pricing option. Once purchased, pricing options become passes on a user’s account, which they can use to book classes. Pricing options can have any number of sessions attached to them (think of a 10-class punch card, only digital). Bookings consume these sessions to mark themselves as paid or reconciled (much like a punch on a punch card).

There are 3 different types of pricing options:

  1. Drop-in pricing options pay for a single class (they only have one session assigned to them).
  2. Series pricing options pay for multiple classes (e.g., a “5-class pack”).
  3. Unlimited pricing options pay for an unlimited number of classes (e.g., a “30 days unlimited”).

A pricing option can pay for bookings that take place between its activation and expiration dates. A subscriber can configure a pricing option’s activation date in 3 different ways:

  1. On the purchase date - the activation date will be the date when the user purchased the pricing option.
  2. On the client’s first visit - the pricing option will activate on the same date as the user’s first booking that the pricing option reconciles. Until it is used to reconcile a booking, the activation date will match the purchase date.
  3. On a set date - the activation date is a specific date (e.g., 12/15/2016) which will not change regardless of purchase or booking dates.

A pricing option’s expiration date is calculated based on its activation date.

GET

Getting pricing options for a class:

curl -X GET \
-H "API-Key: {yourAPIKey}" \
-H "Authorization: Basic {yourEncodedClientKeyAndClientSecret}" \
-A "{yourAppName}" \
"https://mb-api.mindbodyonline.com/affiliate/api/v1/locations/{locationId}/classes/{classId}/pricingOptions"
var client = new RestClient("https://mb-api.mindbodyonline.com/affiliate/api/v1/locations/{locationId}/classes/{classId}/pricingOptions");
var request = new RestRequest(Method.GET);
request.AddHeader("authorization", "Basic {yourEncodedClientKeyAndClientSecret}");
request.AddHeader("api-key", "{yourAPIKey}");
IRestResponse response = client.Execute(request);
<?php

$request = new HttpRequest();
$request->setUrl('https://mb-api.mindbodyonline.com/affiliate/api/v1/locations/{locationId}/classes/{classId}/pricingOptions');
$request->setMethod(HTTP_METH_GET);

$request->setHeaders(array(
  'authorization' => 'Basic {yourEncodedClientKeyAndClientSecret}',
  'api-key' => '{yourAPIKey}'
));

try {
  $response = $request->send();

  echo $response->getBody();
} catch (HttpException $ex) {
  echo $ex;
}
?>
import http.client

conn = http.client.HTTPSConnection("mb-api.mindbodyonline.com")

headers = {
    'api-key': "{yourAPIKey}",
    'authorization': "Basic {yourEncodedClientKeyAndClientSecret}"
    }

conn.request("GET", "/api/v1/locations/{locationId}/classes/{classId}/pricingOptions", headers=headers)

res = conn.getresponse()
data = res.read()

print(data.decode("utf-8"))
require 'uri'
require 'net/http'

url = URI("https://mb-api.mindbodyonline.com/affiliate/api/v1/locations/{locationId}/classes/{classId}/pricingOptions")

http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
http.verify_mode = OpenSSL::SSL::VERIFY_NONE

request = Net::HTTP::Get.new(url)
request["api-key"] = '{yourAPIKey}'
request["authorization"] = 'Basic {yourEncodedClientKeyAndClientSecret}'

response = http.request(request)
puts response.read_body

https://mb-api.mindbodyonline.com/affiliate/api/v1/locations/{locationId}/classes/{classId}/pricingOptions

This endpoint finds pricing options for a specific class.

Pagination

This endpoint does not support pagination.

Best Practices

  • Use after fetching classes via the GET Classes call.
  • Use before making a POST Booking call.
  • Use if the user is not using a pass on their account to pay for their booking.

Headers

Name Type Description
API-Key string Your API key.
Authorization string Your encoded client key and client secret.
See Authentication and Security for help creating this string.

URL Parameters

Name Type Description
locationId number Specifies from which location you are fetching the specific class. This is the id property on the location object returned from GET Locations.
classId number Specifies for which class to fetch pricing options. This is the id property on the class object returned from GET Classes.

Response

HTTP Status Code: 200 OK

{
    "items": [
        {
            "id": 5176,
            "serviceCategoryId": 25,
            "name": "Single Yoga Class",
            "type": "DropIn",
            "description": null,
            "sessionCount": 1,
            "subtotal": 15,
            "tax": 0.75,
            "total": 15.75,
            "currencyCode": "USD",
            "activationType": "OnPurchaseDate",
            "userRestrictions": [
                "None"
            ],
            "expirationTimeUnit": "Months",
            "expirationTimeUnitValue": 12,
            "activationDateTime": "2017-01-15T16:00:00Z",
            "expirationDateTime": "2018-01-15T16:00:00Z"
        }
    ]
}
Name Type Description
id number The pricing option’s ID at the current subscriber.
serviceCategoryId number The ID of the service category at the current subscriber to which the pricing option belongs.
name string The pricing option’s name.
type string Describes the type of the pricing option.

Possible Values:
  • "DropIn"
  • "Series"
  • "Unlimited"
description string The pricing option’s subscriber-configured description.
sessionCount number The number of sessions for which this pricing option will pay.
subtotal number The total cost of the pricing option before applying taxes.
tax number The total cost of taxes for the pricing option.
total number The total cost of the pricing option, including taxes.
currencyCode string A currency code based on the ISO 4217 specification (e.g., "USD" represents the US dollar).
activationType string Specifies the pricing option’s activation type.

Possible Values:
  1. "OnPurchaseDate" - Indicates that the pricing option’s activation date will be the date when the user purchases the pricing option.
  2. "OnFirstVisitScheduledWithPass" - Indicates that the pricing option will activate on the same date as the user’s first booking that the pricing option reconciles. Until it is used to reconcile a booking, the activation date will match the purchase date.
  3. "CustomDate" - Indicates that the pricing option’s activation date is a specific date (e.g., 12/15/2016) which will not change regardless of purchase or booking dates.
userRestrictions array of strings Specifies whether or not the subscriber restricts the purchasing of this pricing option to users that meet specific criteria.

Possible Values:
  1. "None" - Indicates that all users can purchase this pricing option, regardless of their history at the subscriber.
  2. "IntroductoryOfferFirstTimeCustomerOfPricingOption" - Indicates that only users who have never before purchased this pricing option may purchase it now.
  3. "IntroductoryOfferFirstTimeCustomerAtBusiness" - Indicates that only users who have no previous purchases at this subscriber may purchase this pricing option.
expirationTimeUnit string The type of unit used to calculate the pricing option’s expiration date (e.g., this is the “months” in a pricing option that isactive for “12 months”).

Possible Values:
  1. "Days" - Indicates that the pricing option’s expiration date is calculated in a number of days from its activation date.
  2. "Months" - Indicates that the pricing option’s expiration date is calculated in a number of months from its activation date.
This is always used with expirationTimeUnitValue.
expirationTimeUnitValue number The number of expirationUnits used to calculate the pricing option’s expiration date (e.g., this is the “12” in a pricing option that isactive for “12 months”).

This is always used with expirationTimeUnit.
activationDateTime string The date and time after which the pricing option reconciles bookings (in UTC).

See Dates and Times in Responses for more information.
expirationDateTime string The date and time after which the pricing option no longer reconciles bookings (in UTC).

See Dates and Times in Responses for more information.

Errors

Example Error:

{
    "error": {
        "errorCode": "14040005",
        "errorType": "classNotFound",
        "message": "Class not found."
    }
}

This endpoint may return the errors listed below. We recommend that you catch and handle each error for an optimal, frictionless user experience. We also recommend attempting to reproduce each error during your development and test process in order to ensure that your back-end application is handling them correctly.

HTTP Status Code errorCode errorType Description
401 14010001 missingAPIKeyHeader An API-Key header was not included in the request.
401 14010002 missingAuthorizationHeader An Authorization header was not included in the request.
404 14040001 locationNotFound The locationId passed as a URL Parameter was not found.
404 14040005 classNotFound The classId passed as a URL Parameter was not found.
429 14290001 tooManyRequests You have exceeded the rate limit for this endpoint.
429 14290002 dailyRequestLimitExceeded You have exceeded the daily request limit for this endpoint.

GET (by location)

Getting pricing options for a location:

curl -X GET \
-H "API-Key: {yourAPIKey}" \
-H "Authorization: Basic {yourEncodedClientKeyAndClientSecret}" \
-A "{yourAppName}" \
"https://mb-api.mindbodyonline.com/affiliate/api/v1/locations/{locationId}/pricingOptions"
var client = new RestClient("https://mb-api.mindbodyonline.com/affiliate/api/v1/locations/{locationId}/pricingOptions");
var request = new RestRequest(Method.GET);
request.AddHeader("authorization", "Basic {yourEncodedClientKeyAndClientSecret}");
request.AddHeader("api-key", "{yourAPIKey}");
IRestResponse response = client.Execute(request);
<?php

$request = new HttpRequest();
$request->setUrl('https://mb-api.mindbodyonline.com/affiliate/api/v1/locations/{locationId}/pricingOptions');
$request->setMethod(HTTP_METH_GET);

$request->setHeaders(array(
  'authorization' => 'Basic {yourEncodedClientKeyAndClientSecret}',
  'api-key' => '{yourAPIKey}'
));

try {
  $response = $request->send();

  echo $response->getBody();
} catch (HttpException $ex) {
  echo $ex;
}
?>
import http.client

conn = http.client.HTTPSConnection("mb-api.mindbodyonline.com")

headers = {
    'api-key': "{yourAPIKey}",
    'authorization': "Basic {yourEncodedClientKeyAndClientSecret}"
    }

conn.request("GET", "/api/v1/locations/{locationId}/pricingOptions", headers=headers)

res = conn.getresponse()
data = res.read()

print(data.decode("utf-8"))
require 'uri'
require 'net/http'

url = URI("https://mb-api.mindbodyonline.com/affiliate/api/v1/locations/{locationId}/pricingOptions")

http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
http.verify_mode = OpenSSL::SSL::VERIFY_NONE

request = Net::HTTP::Get.new(url)
request["api-key"] = '{yourAPIKey}'
request["authorization"] = 'Basic {yourEncodedClientKeyAndClientSecret}'

response = http.request(request)
puts response.read_body

https://mb-api.mindbodyonline.com/affiliate/api/v1/locations/{locationId}/pricingOptions

This endpoint finds pricing options that can be purchased and used at a specific location.

Pagination

This endpoint does not support pagination.

Best Practices

  • If you are creating an interface that lets your users shop based on their chosen pricing, use after fetching locations via the GET Locations call.

Headers

Name Type Description
API-Key string Your API key.
Authorization string Your encoded client key and client secret.
See Authentication and Security for help creating this string.

URL Parameters

Name Type Description
locationId number Specifies for which location you are fetching pricing options. This is the id property on the location object returned from GET Locations.

Query Parameters

Name Type Description
serviceCategoryIds
Optional
string Filters the results down to pricing options within the specified service category or categories. Pass multiple service categories in a comma-separated list.

For example, ?serviceCategoryIds=24,8 would return pricing for both service category 24 and 8.

The serviceCategoryId property on the pricing option object returned from this call will match one of the passed values.

Response

Partial example of response content structure:

{
    "items": [
        {
            "id": 5176,
            "serviceCategoryId": 25,
            ...
        }
    ]
}

This response object is the same as the response returned from GET PricingOptions with one, minor difference.

If a pricing option’s activationType is OnFirstVisitScheduledWithPass, both its activationDateTime and expirationDateTime will be null – we cannot calculate these values without knowing which class the user is booking.

You can calculate these values once your user chooses a class.

For example, Jane Doe just used your app to find all pricing available at a location. She chose a “5 pack” pricing option that activates on the user’s first visit, then she continued through the workflow and selected a class that takes place tomorrow at 10:00 AM (UTC). Prior to purchase, you want to show her the time-frame she has to use the pricing option. If the pricing option’s expirationTimeUnit is "Months" and its expirationTimeUnitValue is 6, you could show its expirationDateTime as six months from tomorrow.

View the GET PricingOptions response documentation for detailed information about this endpoint’s response object.

Errors

Example Error:

{
    "error": {
        "errorCode": "14040001",
        "errorType": "locationNotFound",
        "message": "Location not found."
    }
}

This endpoint may return the errors listed below. We recommend that you catch and handle each error for an optimal, frictionless user experience. We also recommend attempting to reproduce each error during your development and test process in order to ensure that your back-end application is handling them correctly.

HTTP Status Code errorCode errorType Description
400 14000004 invalidParameter Returned when a query parameter:
  • Has violated its minimum acceptable value
  • Has violated its maximum acceptable value
  • Is required but is missing
  • Is used with other incompatible query parameters
Check the error’s message property to find the name of the invalid query parameter.
401 14010001 missingAPIKeyHeader An API-Key header was not included in the request.
401 14010002 missingAuthorizationHeader An Authorization header was not included in the request.
404 14040001 locationNotFound The locationId passed as a URL Parameter was not found.
429 14290001 tooManyRequests You have exceeded the rate limit for this endpoint.
429 14290002 dailyRequestLimitExceeded You have exceeded the daily request limit for this endpoint.

Bookings

Bookings

Users create bookings when they reserve a space in a class. During the booking process and use of POST booking, users can either use their available pass(es) or purchase a new pricing option to reconcile the booking. Once purchased, a pricing option becomes an active pass in the user’s account.

By default, a user cannot book into overlapping classes. For example, Fred Jones might try to book a Yoga and a Pilates class, both of which run from 4:30 to 5:30 on Wednesday. Because Fred cannot be in two places at once, this is not allowed. Subscribers can configure their settings to allow overlapping bookings, but it is not common.

Booking Windows

Subscribers configure booking windows which set restrictions around when users can book into classes. If a user tries to book outside the booking window, the booking will fail. Booking windows apply to all classes within a service category.

As an example, Jane Doe is trying to book a Yoga class for 5:00 PM this evening. If the class’s booking window opened 30 minutes ago, she’s been able to book for a half hour. If the booking window closes in 3 hours, Jane still has that much time to book her class. On the other hand, if the class’s booking window starts in 30 minutes, or if it ended 30 minutes ago, she would not be able to book.

Subscribers can also configure daily booking windows to restrict the time of day before and after which users can make new bookings. Let’s pretend that ACME Yoga set up this restriction so that users can only make new bookings between the hours of 7:00 AM and 10:00 PM each day. If the current time is not between 7:00 AM and 10:00 PM, users cannot make any new bookings regardless of the class’s time.

Cancellations

If a user wants to cancel a booking, they can, but only if the cancellation is valid according to all configured subscriber settings.

When a user cancels a booking, the session used to pay for the booking returns to the pass on the user’s account; no monetary funds are issued to the user. Other users can now book the spot that became available due to the cancellation.

Use the GET Locations call to retrieve a subscriber’s cancellation policy text.

Cancellation Windows

A cancellation window specifies the time frame within which users can cancel bookings. For example, if the cancellation window ends in 30 minutes, a user would not be able to cancel their booking 60 minutes from now. Like booking windows, cancellation windows uniformly apply to all classes in the same service category.

GET

curl -X GET \
-H "API-Key: {yourAPIKey}" \
-H "Authorization: Basic {yourEncodedClientKeyAndClientSecret}" \
-A "{yourAppName}" \
"https://mb-api.mindbodyonline.com/affiliate/api/v1/users/{uniqueUserId}/bookings"
var client = new RestClient("https://mb-api.mindbodyonline.com/affiliate/api/v1/users/{uniqueUserId}/bookings");
var request = new RestRequest(Method.GET);
request.AddHeader("authorization", "Basic {yourEncodedClientKeyAndClientSecret}");
request.AddHeader("api-key", "{yourAPIKey}");
IRestResponse response = client.Execute(request);
<?php

$request = new HttpRequest();
$request->setUrl('https://mb-api.mindbodyonline.com/affiliate/api/v1/users/{uniqueUserId}/bookings');
$request->setMethod(HTTP_METH_GET);

$request->setHeaders(array(
  'authorization' => 'Basic {yourEncodedClientKeyAndClientSecret}',
  'api-key' => '{yourAPIKey}'
));

try {
  $response = $request->send();

  echo $response->getBody();
} catch (HttpException $ex) {
  echo $ex;
}
?>
import http.client

conn = http.client.HTTPSConnection("mb-api.mindbodyonline.com")

headers = {
    'api-key': "{yourAPIKey}",
    'authorization': "Basic {yourEncodedClientKeyAndClientSecret}"
    }

conn.request("GET", "/api/v1/users/{uniqueUserId}/bookings", headers=headers)

res = conn.getresponse()
data = res.read()

print(data.decode("utf-8"))
require 'uri'
require 'net/http'

url = URI("https://mb-api.mindbodyonline.com/affiliate/api/v1/users/{uniqueUserId}/bookings")

http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
http.verify_mode = OpenSSL::SSL::VERIFY_NONE

request = Net::HTTP::Get.new(url)
request["api-key"] = '{yourAPIKey}'
request["authorization"] = 'Basic {yourEncodedClientKeyAndClientSecret}'

response = http.request(request)
puts response.read_body

https://mb-api.mindbodyonline.com/affiliate/api/v1/users/{uniqueUserId}/bookings

This endpoint returns bookings for the specified user.

You can retrieve a specific booking by calling GET (by ID).

Pagination

This endpoint supports pagination.

Best Practices

  • Use when constructing an account status page to show the user a list of their bookings.

Headers

Name Type Description
API-Key string Your API key.
Authorization string Your encoded client key and client secret.
See Authentication and Security for help creating this string.

URL Parameters

Name Type Description
uniqueUserId string The user’s unique identifier within your system. This ID must:
  • Be between 1 and 64 characters in length
  • Contain only:
    • alphanumeric characters (lowercase)
    • _ (underscores)
    • - (hyphens)
    • ~ (tildes)
    • . (periods)

Query Parameters

Name Type Description
locationId
Optional
number Filters the results down to the user’s bookings at the location identified by this ID. This is the id property on the location object returned from the GET Locations call and the location.id property returned from other calls in the API.
subscriberId
Optional
number Filters the results down to the user’s bookings at the subscriber identified by this ID. This is the subscriber.id property on the location object returned from the GET Locations call.
maxResults
Optional
number Sets the maximum number of records returned in the results.default: 20 | max: 100 | min: 0
offset
Optional
number Sets the number of records skipped over to reach the returned results.default: 0 | min: 0
orderBy
Optional
string Designates which field in the response body orders the results.

Accepted Values:
  • locationId
  • subscriberId
  • bookingDateTime
  • classStartDateTime
default: classStartDateTime
order
Optional
string Orders the results in ascending or descending order based on the field specified by orderBy.

Accepted Values:
  • asc
  • desc
default: asc

Response

HTTP Status Code: 200 OK

{
    "items": [
        {
            "id": "f5405d87-46a0-4b48-a384-e26159e130d6",
            "bookingDateTime": "2016-12-15T19:51:49.357Z",
            "state": "Booked",
            "sessionsDeducted": 1,
            "pass": {
                "id": "4117bed4-615a-40d2-968c-9aac2412c4dd",
                "type": "DropIn",
                "name": "Single Yoga Class"
            },
            "class": {
                "id": 1234151,
                "typeId": 7,
                "name": "Beginning Hatha Yoga",
                "description": "A gentle introduction to the Hatha practice.",
                "registrationNotes": "Bring a yoga mat and a large bottle of water.",
                "classImageURLs": [
                    {
                        "size": "XLarge",
                        "url": "https://clients.mindbodyonline.com
                        /studios/ACMEYoga/reservations/7_xLarge.jpg?v=23"
                    },
                    {
                        "size": "Large",
                        "url": "https://clients.mindbodyonline.com
                        /studios/ACMEYoga/reservations/7_large.jpg?v=23"
                    },
                    {
                        "size": "Unscaled",
                        "url": "https://clients.mindbodyonline.com
                        /studios/ACMEYoga/reservations/7_.jpg?v=23"
                    }
                ],
                "startDateTime": "2016-12-15T17:00:00Z",
                "endDateTime": "2016-12-15T18:00:00Z",
                "assistantNames": [],
                "roomName": null,
                "cancellationsAllowed": true,
                "cancellationWindowEndTime": "2016-12-15T16:00:00Z",
                "serviceCategoryIds": [
                    25
                ],
                "staff": {
                    "id": 3,
                    "firstName": "Thomas",
                    "lastName": "Jones",
                    "gender": "Male",
                    "staffImageURLs": [
                        {
                            "size": "XLarge",
                            "url": "https://clients.mindbodyonline.com
                            /studios/ACMEYogastaff/3_xLarge.jpg?v=23"
                        },
                        {
                            "size": "Large",
                            "url": "https://clients.mindbodyonline.com
                            /studios/ACMEYogastaff/3_large.jpg?v=23"
                        },
                        {
                            "size": "Mobile",
                            "url": "https://clients.mindbodyonline.com
                            /studios/ACMEYogastaff/3_mobile.jpg?v=23"
                        }
                    ],
                    "bio": null
                },
                "location": {
                    "id": 12856,
                    "name": "ACME Yoga",
                    "olsonTimeZone": "America/Los_Angeles",
                    "subscriber": {
                        "id": 13548,
                        "name": "ACME Yoga"
                    }
                }
            }
        }
    ],
    "offset": 0,
    "maxResults": 1,
    "totalResults": 15
}
Name Type Description
id string The booking’s globally unique identifier (a GUID).
bookingDateTime string The date and time when the API successfully created the booking; the booking’s creation timestamp (in UTC).

See Dates and Times in Responses for more information.
state string The booking’s current state.

Possible Values:
  • "Booked" - Indicates that the booking is still booked and scheduled.
  • "CancelledByUser" - Indicates that the user cancelled the booking.
  • "CancelledByBusiness" - Indicates that the subscriber cancelled the booking.
sessionsDeducted number The number of sessions the booking will deduct from the associated pass.
pass object Contains information about the pass that ispaying for the booking.
pass.id string The pass’s globally unique identifier (a GUID).
pass.type string The type of the pass.

Possible Values:
  • "DropIn"
  • "Series"
  • "Unlimited"
pass.name string The pass’s name.
class object Contains information about the class where the booking holds a space.
class.id number The ID for this specific class within the current subscriber; the class’s ID.
class.typeId number The ID for the class’s class type within the current subscriber.
class.name string The name of the class.
class.description string The class’ subscriber-configured description. This string contains HTML.
class.registrationNotes string Special notes or instructions the subscriber wants to relay to users who are booking the class. For example, "Make sure you bring a sweat towel and bottle of water!".
class.classImageURLs array of objects Contains information about the different sizes of images available for the class.
class.classImageURLs.size string The size of the image.

Possible Values:
  • "XLarge" - The class’s image with a maximum width and height of 600 pixels.
  • "Large" - The class’s image with a maximum width and height of 200 pixels.
  • "Unscaled" - The class’s image with its original size. Classes cannot have images larger than 4MB.
class.classImageURLs.url string The URL for the image.

class.startDateTime string The date and time when the class starts (in UTC).

See Dates and Times in Responses for more information.
class.endDateTime string The date and time when the class ends (in UTC).

See Dates and Times in Responses for more information.
class.assistantNames array of strings Contains the names of all assistant teachers assigned to the class.
class.roomName string The name of the room where the class is held (e.g., "Sun Room" or "Studio A"). This value might be null if the subscriber hides their classes’ rooms.
class.cancellationsAllowed boolean When true, indicates that the subscriber allows users to cancel bookings they make in this class, up to the cancellationWindowEndTime.

When false, indicates that the subscriber does not allow users to cancel bookings they make in this class, regardless of the cancellationWindowEndTime.
class.cancellationWindowEndTime string The date and time after which cancellations can no longer be made for bookings in the class (in the location’s time zone).
class.serviceCategoryIds array of numbers The IDs of the service categories whose pricing options can pay for the class.
class.staff object Contains information about the staff member who teaches the class.
class.staff.id number The staff member’s ID within the current subscriber.
class.staff.firstName string The staff member’s first name. This value might be null if the subscriber has hidden staff names.

If the subscriber uses staff nicknames, this value will be the staff’s nickname if they have one configured.
class.staff.lastName string The staff member’s last name. This value will be null if the subscriber has hidden staff names.

If the subscriber uses staff nicknames, this value will be null if the staff member has a nickname configured.
class.staff.gender string The staff member’s gender.

Possible Values:
  • "Male"
  • "Female"
class.staff.staffImageURLs array of objects Contains information about the different sizes of images available for the staff member.
class.staff.staffImageURLs.size string The size of the image.

Possible Values:
  • "XLarge" - The staff’s image with a maximum width and height of 600 pixels.
  • "Large" - The staff’s image with a maximum width and height of 200 pixels.
  • "Mobile" - The staff’s image with a maximum width and height of 128 pixels.
class.staff.staffImageURLs.url string The URL for the image.

class.staff.bio string The staff member’s biography.
class.location object Contains information about the location where the class is taking place.
class.location.id number The location’s globally unique ID.
class.location.name string The location’s name.
class.location.olsonTimeZone string The location’s time zone in Olson format (e.g., "America/Los_Angeles"). Possible time zones.
class.location.subscriber object Contains information about the subscriber to whom the location belongs.
class.location.subscriber.id number The subscriber’s globally unique ID.
class.location.subscriber.name string The subscriber’s name.

Errors

Example Error:

{
    "error": {
        "errorCode": "14000004",
        "errorType": "invalidParameter",
        "message": "The following parameter is invalid: locationId."
    }
}

This endpoint may return the errors listed below. We recommend that you catch and handle each error for an optimal, frictionless user experience. We also recommend attempting to reproduce each error during your development and test process in order to ensure that your back-end application is handling them correctly.

HTTP Status Code errorCode errorType Description
400 14000004 invalidParameter Returned when a query parameter:
  • Has violated its minimum acceptable value
  • Has violated its maximum acceptable value
  • Is required but is missing
  • Is used with other incompatible query parameters
Check the error’s message property to find the name of the invalid query parameter.
401 14010001 missingAPIKeyHeader An API-Key header was not included in the request.
401 14010002 missingAuthorizationHeader An Authorization header was not included in the request.
404 14040010 userNotFound The uniqueUserId passed as a URL Parameter was not found.
429 14290001 tooManyRequests You have exceeded the rate limit for this endpoint.
429 14290002 dailyRequestLimitExceeded You have exceeded the daily request limit for this endpoint.

GET (by ID)

curl -X GET \
-H "API-Key: {yourAPIKey}" \
-H "Authorization: Basic {yourEncodedClientKeyAndClientSecret}" \
-A "{yourAppName}" \
"https://mb-api.mindbodyonline.com/affiliate/api/v1/users/{uniqueUserId}/bookings/{bookingId}"
var client = new RestClient("https://mb-api.mindbodyonline.com/affiliate/api/v1/users/{uniqueUserId}/bookings/{bookingId}");
var request = new RestRequest(Method.GET);
request.AddHeader("authorization", "Basic {yourEncodedClientKeyAndClientSecret}");
request.AddHeader("api-key", "{yourAPIKey}");
IRestResponse response = client.Execute(request);
<?php

$request = new HttpRequest();
$request->setUrl('https://mb-api.mindbodyonline.com/affiliate/api/v1/users/{uniqueUserId}/bookings/{bookingId}');
$request->setMethod(HTTP_METH_GET);

$request->setHeaders(array(
  'authorization' => 'Basic {yourEncodedClientKeyAndClientSecret}',
  'api-key' => '{yourAPIKey}'
));

try {
  $response = $request->send();

  echo $response->getBody();
} catch (HttpException $ex) {
  echo $ex;
}
?>
import http.client

conn = http.client.HTTPSConnection("mb-api.mindbodyonline.com")

headers = {
    'api-key': "{yourAPIKey}",
    'authorization': "Basic {yourEncodedClientKeyAndClientSecret}"
    }

conn.request("GET", "/api/v1/users/{uniqueUserId}/bookings/{bookingId}", headers=headers)

res = conn.getresponse()
data = res.read()

print(data.decode("utf-8"))
require 'uri'
require 'net/http'

url = URI("https://mb-api.mindbodyonline.com/affiliate/api/v1/users/{uniqueUserId}/bookings/{bookingId}")

http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
http.verify_mode = OpenSSL::SSL::VERIFY_NONE

request = Net::HTTP::Get.new(url)
request["api-key"] = '{yourAPIKey}'
request["authorization"] = 'Basic {yourEncodedClientKeyAndClientSecret}'

response = http.request(request)
puts response.read_body

https://mb-api.mindbodyonline.com/affiliate/api/v1/users/{uniqueUserId}/bookings/{bookingId}

This endpoint finds and returns the single booking associated with the passed ID.

Pagination

This endpoint does not support pagination.

Best Practices

  • Use to pull booking details for a booking where you already have its ID.
  • Use after making a POST Booking call to show the user their new booking.

Headers

Name Type Description
API-Key string Your API key.
Authorization string Your encoded client key and client secret.
See Authentication and Security for help creating this string.

URL Parameters

Name Type Description
uniqueUserId string The user’s unique identifier within your system. This ID must:
  • Be between 1 and 64 characters in length
  • Contain only:
    • alphanumeric characters (lowercase)
    • _ (underscores)
    • - (hyphens)
    • ~ (tildes)
    • . (periods)
bookingId string Returns the single booking associated with this globally unique identifier (a GUID). This is the id property on the booking object returned from this call and the booking.id property returned from other calls in the API.

Response

Partial example of response content structure:

{
    "booking": {
        "id": "f5405d87-46a0-4b48-a384-e26159e130d6",
        "bookingDateTime": "2016-12-15T19:51:49.357Z",
        ...
    }
    ...
}

This response object is the same as the objects contained in the items field in the GET Bookings response . View that documentation for detailed information about the response object’s fields.

Errors

Example Error:

{
    "error": {
        "errorCode": "14040020",
        "errorType": "bookingNotFound",
        "message": "Booking not found."
    }
}

This endpoint may return the errors listed below. We recommend that you catch and handle each error for an optimal, frictionless user experience. We also recommend attempting to reproduce each error during your development and test process in order to ensure that your back-end application is handling them correctly.

HTTP Status Code errorCode errorType Description
401 14010001 missingAPIKeyHeader An API-Key header was not included in the request.
401 14010002 missingAuthorizationHeader An Authorization header was not included in the request.
404 14040010 userNotFound The uniqueUserId passed as a URL Parameter was not found.
404 14040020 bookingNotFound The bookingId passed as a URL Parameter was not found.
429 14290001 tooManyRequests You have exceeded the rate limit for this endpoint.
429 14290002 dailyRequestLimitExceeded You have exceeded the daily request limit for this endpoint.

POST

curl -X POST \
-A "{yourAppName}" \
-H "API-Key: {yourAPIKey}" \
-H "Authorization: Basic {yourEncodedClientKeyAndClientSecret}" \
-H "Content-Type: application/json" \
-d '{
    "locationId": 86784,
    "classId": 5134512,
    "bookingReconciliation":
    {
        "id": "153458",
        "type": "PricingOption",
        "pricingOptionTotal": 15.75
    },
    "suppressBookingConfirmationEmail": true,
    "suppressPurchaseReceiptEmail": true,
    "subscriberMarketingOptIn": false,
    "userFirst": "Joseph",
    "userLast": "Smith",
    "userEmail": "[email protected]",
    "userPhone": "8055555462",
    "uniqueUserId": "aa4d78ad-5fde-40f4-bc15-a392b9643989",
    "paymentDetails":
    {
        "creditCardNumber": "4012888888881881",
        "creditCardExpirationYear": 2028,
        "creditCardExpirationMonth": 1,
        "billingName": "Joseph Smith",
        "billingAddressLine1": "4051 Broad St",
        "billingAddressLine2": "STE 201",
        "billingCity": "San Luis Obispo",
        "billingState": "CA",
        "billingPostalCode": "93401"
    }
}' \
"https://mb-api.mindbodyonline.com/affiliate/api/v1/bookings"
var client = new RestClient("https://mb-api.mindbodyonline.com/affiliate/api/v1/bookings");
var request = new RestRequest(Method.POST);
request.AddHeader("content-type", "application/json");
request.AddHeader("authorization", "Basic {yourEncodedClientKeyAndClientSecret}");
request.AddHeader("api-key", "{yourAPIKey}");
request.AddParameter("application/json", "{\n    \"locationId\": 86784,\n    \"classId\": 5134512,\n    \"bookingReconciliation\":\n    {\n        \"id\": \"153458\",\n        \"type\": \"PricingOption\",\n        \"pricingOptionTotal\": 15.75\n    },\n    \"suppressBookingConfirmationEmail\": true,\n    \"suppressPurchaseReceiptEmail\": true,\n    \"subscriberMarketingOptIn\": false,\n    \"userFirst\": \"Joseph\",\n    \"userLast\": \"Smith\",\n    \"userEmail\": \"[email protected]\",\n    \"userPhone\": \"8055555462\",\n    \"uniqueUserId\": \"aa4d78ad-5fde-40f4-bc15-a392b9643989\",\n    \"paymentDetails\":\n    {\n        \"creditCardNumber\": \"4012888888881881\",\n        \"creditCardExpirationYear\": 2028,\n        \"creditCardExpirationMonth\": 1,\n        \"billingName\": \"Joseph Smith\",\n        \"billingAddressLine1\": \"4051 Broad St\",\n        \"billingAddressLine2\": \"STE 201\",\n        \"billingCity\": \"San Luis Obispo\",\n        \"billingState\": \"CA\",\n        \"billingPostalCode\": \"93401\"\n    }\n}", ParameterType.RequestBody);
IRestResponse response = client.Execute(request);
<?php

$request = new HttpRequest();
$request->setUrl('https://mb-api.mindbodyonline.com/affiliate/api/v1/bookings');
$request->setMethod(HTTP_METH_POST);

$request->setHeaders(array(
  'content-type' => 'application/json',
  'authorization' => 'Basic {yourEncodedClientKeyAndClientSecret}',
  'api-key' => '{yourAPIKey}'
));

$request->setBody('{
    "locationId": 86784,
    "classId": 5134512,
    "bookingReconciliation":
    {
        "id": "153458",
        "type": "PricingOption",
        "pricingOptionTotal": 15.75
    },
    "suppressBookingConfirmationEmail": true,
    "suppressPurchaseReceiptEmail": true,
    "subscriberMarketingOptIn": false,
    "userFirst": "Joseph",
    "userLast": "Smith",
    "userEmail": "[email protected]",
    "userPhone": "8055555462",
    "uniqueUserId": "aa4d78ad-5fde-40f4-bc15-a392b9643989",
    "paymentDetails":
    {
        "creditCardNumber": "4012888888881881",
        "creditCardExpirationYear": 2028,
        "creditCardExpirationMonth": 1,
        "billingName": "Joseph Smith",
        "billingAddressLine1": "4051 Broad St",
        "billingAddressLine2": "STE 201",
        "billingCity": "San Luis Obispo",
        "billingState": "CA",
        "billingPostalCode": "93401"
    }
}');

try {
  $response = $request->send();

  echo $response->getBody();
} catch (HttpException $ex) {
  echo $ex;
}
?>
import http.client

conn = http.client.HTTPSConnection("mb-api.mindbodyonline.com")

payload = "{\n    \"locationId\": 86784,\n    \"classId\": 5134512,\n    \"bookingReconciliation\":\n    {\n        \"id\": \"153458\",\n        \"type\": \"PricingOption\",\n        \"pricingOptionTotal\": 15.75\n    },\n    \"suppressBookingConfirmationEmail\": true,\n    \"suppressPurchaseReceiptEmail\": true,\n    \"subscriberMarketingOptIn\": false,\n    \"userFirst\": \"Joseph\",\n    \"userLast\": \"Smith\",\n    \"userEmail\": \"[email protected]\",\n    \"userPhone\": \"8055555462\",\n    \"uniqueUserId\": \"aa4d78ad-5fde-40f4-bc15-a392b9643989\",\n    \"paymentDetails\":\n    {\n        \"creditCardNumber\": \"4012888888881881\",\n        \"creditCardExpirationYear\": 2028,\n        \"creditCardExpirationMonth\": 1,\n        \"billingName\": \"Joseph Smith\",\n        \"billingAddressLine1\": \"4051 Broad St\",\n        \"billingAddressLine2\": \"STE 201\",\n        \"billingCity\": \"San Luis Obispo\",\n        \"billingState\": \"CA\",\n        \"billingPostalCode\": \"93401\"\n    }\n}"

headers = {
    'api-key': "{yourAPIKey}",
    'authorization': "Basic {yourEncodedClientKeyAndClientSecret}",
    'content-type': "application/json"
    }

conn.request("POST", "/affiliate/api/v1/bookings", payload, headers)

res = conn.getresponse()
data = res.read()

print(data.decode("utf-8"))
require 'uri'
require 'net/http'

url = URI("https://mb-api.mindbodyonline.com/affiliate/api/v1/bookings")

http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
http.verify_mode = OpenSSL::SSL::VERIFY_NONE

request = Net::HTTP::Post.new(url)
request["api-key"] = '{yourAPIKey}'
request["authorization"] = 'Basic {yourEncodedClientKeyAndClientSecret}'
request["content-type"] = 'application/json'
request.body = "{\n    \"locationId\": 86784,\n    \"classId\": 5134512,\n    \"bookingReconciliation\":\n    {\n        \"id\": \"153458\",\n        \"type\": \"PricingOption\",\n        \"pricingOptionTotal\": 15.75\n    },\n    \"suppressBookingConfirmationEmail\": true,\n    \"suppressPurchaseReceiptEmail\": true,\n    \"subscriberMarketingOptIn\": false,\n    \"userFirst\": \"Joseph\",\n    \"userLast\": \"Smith\",\n    \"userEmail\": \"[email protected]\",\n    \"userPhone\": \"8055555462\",\n    \"uniqueUserId\": \"aa4d78ad-5fde-40f4-bc15-a392b9643989\",\n    \"paymentDetails\":\n    {\n        \"creditCardNumber\": \"4012888888881881\",\n        \"creditCardExpirationYear\": 2028,\n        \"creditCardExpirationMonth\": 1,\n        \"billingName\": \"Joseph Smith\",\n        \"billingAddressLine1\": \"4051 Broad St\",\n        \"billingAddressLine2\": \"STE 201\",\n        \"billingCity\": \"San Luis Obispo\",\n        \"billingState\": \"CA\",\n        \"billingPostalCode\": \"93401\"\n    }\n}"

response = http.request(request)
puts response.read_body

https://mb-api.mindbodyonline.com/affiliate/api/v1/bookings

This endpoint allows users to book classes.

Retrying Failed Requests

This endpoint supports idempotent requests, meaning that you can safely retry a request without creating a duplicate booking. Idempotent requests create a single booking, no matter how many times you send the request within a 24 hour period. If a booking was successfully created by a previous request using the same idempotency key, you will receive a 200 OK instead of a 201 Created. Idempotent requests are especially useful when dealing with connection time outs and HTTP 500 errors.

If a request fails with an HTTP 400 error, please correct your request and use a new idempotency key, then make your request again. If the same idempotency key is used within a 24 hour time period, you will receive the same cached response that you received the first time; in this case, a 400 error.

Pass a GUID as an Idempotency-Key header to make an idempotent request. Most programming languages come with functions that can create GUID strings for you. For example:

Language Function
C# Guid.NewGuid()
PHP uniqueid
Python uuid
Ruby SecureRandom.uuid

Pagination

This endpoint does not support pagination.

Best Practices

  • Use once a user has selected a class and pricing option they want to purchase.
  • Use once a user has selected a class and a preexisting pass they want to use to book the class.
  • Use after storing the subscriber.creditCardTypesAccepted array returned from GET Locations. If a user tries to make a booking with a pricing option and an unacceptable card type, the call will fail.
  • Use before calling POST LiabilityWaivers so you have a bookingId with which to make that call.

Headers

Name Type Description
API-Key string Your API key.
Authorization string Your encoded client key and client secret.
See Authentication and Security for help creating this string.
Content-Type string Defines the format of the request so the API can correctly process it. application/json is the only accepted value at this time.
Idempotency-Key
Optional
Guid A GUID used as the idempotency key for this booking request. This key expires after 24 hours.max length: 36, min length: 36

Request Body

{
    "locationId": 86784,
    "classId": 5134512,
    "bookingReconciliation":
    {
        "id": "153458",
        "type": "PricingOption",
        "pricingOptionTotal": 15.75
    },
    "suppressBookingConfirmationEmail": true,
    "suppressPurchaseReceiptEmail": true,
    "subscriberMarketingOptIn": false,
    "userFirst": "Joseph",
    "userLast": "Smith",
    "userEmail": "[email protected]",
    "userPhone": "8055555462",
    "uniqueUserId": "aa4d78ad-5fde-40f4-bc15-a392b9643989",
    "paymentDetails":
    {
        "creditCardNumber": "4012888888881881",
        "creditCardExpirationYear": 2028,
        "creditCardExpirationMonth": 1,
        "creditCardCVV": "0123",
        "billingName": "Joseph Smith",
        "billingAddressLine1": "4051 Broad St",
        "billingAddressLine2": "STE 201",
        "billingCity": "San Luis Obispo",
        "billingState": "CA",
        "billingPostalCode": "93401"
    }
}
Name Type Description
locationId number The globally unique ID of the location where the booking is taking place. This is the id property on the location object returned from GET Locations and the location.id property returned from other calls in the API.
classId number The ID of the class where the booking is reserving a space. This is the id property on the class object returned from GET Classes and the class.id property returned from other calls in the API.
bookingReconciliation object Specifies whether a pass or a pricing option is paying for the class.
bookingReconciliation.id string Will be the pass’s id (a GUID) if using a pass to reconcile the booking.

Will be the pricing option’s id if using a pricing option to reconcile the booking.

bookingReconciliation.type string Specifies whether the user is using a pass or pricing option to pay for the booking.

Accepted Values:
  • "Pass" - indicates that a pass is paying for the booking.
  • "PricingOption" - indicates that a pricing option is paying for the booking. User identification and payment information must also be filled out in requests with this value.
bookingReconciliation.pricingOptionTotal
Optional: You must provide this value when bookingReconciliation.type is "PricingOption"
number The expected cost of the pricing option the user is about to purchase. This ensures that the subscriber has not changed the price in the time between selecting and purchasing the pricing option.

Pass null for this value when bookingReconciliation.type is "Pass".
suppressBookingConfirmationEmail
Optional
boolean When true, the subscriber will not send their customized booking confirmation email to the user. Instead, you can send a tailored email that is consistent with the user’s experience within your app.

When false or omitted, the subscriber will send their booking confirmation email to the user.
suppressPurchaseReceiptEmail
Optional
boolean When true, the subscriber will not send the purchase receipt email to the user. Instead, you can send a tailored email that is consistent with the user’s experience within your app.

When false or omitted, the subscriber will send the purchase receipt email to the user.
subscriberMarketingOptIn
Optional
boolean When true, the user’s email address is added to the subscriber’s marketing email list.

When false or omitted, the user’s email is not added to the subscriber’s marketing email list.

userFirst
Optional: You must provide this value when bookingReconciliation.type is "PricingOption"
string The user’s first name.max length: 100 | min length: 1
userLast
Optional: You must provide this value when bookingReconciliation.type is "PricingOption"
string The user’s last name.max length: 100 | min length: 1
userEmail
Optional: You must provide this value when bookingReconciliation.type is "PricingOption"
string The user’s email address.max length: 255 | min length: 1
userPhone
Optional
string The user’s phone number.max: 20
uniqueUserId string The user’s unique identifier within your system. This ID must:
  • Be between 1 and 64 characters in length
  • Contain only:
    • alphanumeric characters (lowercase)
    • _ (underscores)
    • - (hyphens)
    • ~ (tildes)
    • . (periods)
paymentDetails
Optional: Set this value to null when bookingReconciliation.type is "Pass".
object When bookingReconciliation.type is "PricingOption", this object must contain the user’s credit card and billing information to pay for the booking.
paymentDetails.creditCardNumber string The full credit card number being charged for the pricing option.max length: 16 | min length: 15
paymentDetails.creditCardExpirationYear number The 4-digit year when the credit card expires.max: 2100 | min: 2000
paymentDetails.creditCardExpirationMonth number The digit representing the month when the credit card expires. (E.g., 1 indicates January, 10 indicates October.)max: 12 | min: 1
paymentDetails.creditCardCvv
Optional
string The credit card’s 3 or 4 digit CVV codemax length: 4 | min length: 3
paymentDetails.billingName string The billing name on the credit card.max: 200 | min: 1
paymentDetails.billingAddressLine1 string The street portion of the billing address.max length: 255 | min length: 1
paymentDetails.billingAddressLine2 string Additional address information (e.g., the apartment number, suite number, floor number, etc.).max length: 255
paymentDetails.billingCity string The city portion of the billing address.max length: 50 | min length: 1
paymentDetails.billingState string The state code portion of the billing address (e.g. For California in the USA, "CA".).max length: 10 | min length: 1
paymentDetails.billingPostalCode string The postal code portion of the billing address.max length: 15 | min length: 1

Response

HTTP Status Code: 200 OK
The API returns this code and the first request’s response body when you make subsequent requests – using the same Idempotency-Key header value – to this endpoint. A 200 is only returned if the original request resulted in a 201.

HTTP Status Code: 201 Created

{
    "booking": {
        "id": "d2b68b2f-35ca-4eeb-b8ab-babd65058b35",
        "bookingDateTime": "2016-12-16T09:54:41.137",
        "sessionsDeducted": 1
    },
    "pass": {
        "id": "d1e9b2be-655a-4419-b7dd-30aa84f7aa70",
        "type": "DropIn",
        "name": "Single Yoga Class",
        "totalSessions": 1,
        "sessionsRemaining": 0,
        "activationType": "OnPurchaseDate",
        "activationDateTime": "2016-12-15T00:00:00",
        "expirationDateTime": "2017-12-15T00:00:00"
    },
    "location": {
        "id": 12856,
        "name": "ACME Yoga",
        "olsonTimeZone": "America/Los_Angeles",
        "contactInfo": {
            "phone": "8055551234",
            "streetAddress": "4051 Broad St",
            "city": "San Luis Obispo",
            "stateCode": "CA",
            "postalCode": "93405",
            "countryCode": "US",
            "latitude": 35.300495,
            "longitude": -120.657846
        },
        "subscriber": {
            "id": 13548,
            "name": "ACME Yoga",
            "website": "https://yogashala.com",
            "cancellationPolicy": null,
            "refundPolicy": null
        }
    },
    "class": {
        "id": 31034,
        "typeId": 7,
        "name": "Beginning Hatha Yoga",
        "description": "A gentle introduction to the Hatha practice.",
        "registrationNotes": "Bring a yoga mat and a large bottle of water.",
        "startDateTime": "2016-12-15T17:00:00",
        "endDateTime": "2017-12-15T17:00:00",
        "assistantNames": [],
        "roomName": null,
        "cancellationsAllowed": true,
        "cancellationWindowEndTime": "2016-12-15T17:00:00",
        "serviceCategoryIds": [
            25
        ],
        "staff": { 
            "id": 3, 
            "firstName": "Thomas", 
            "lastName": "Jones", 
            "gender": "Male", 
            "bio": null, 
            "staffImageURLs": [ 
                { 
                    "size": "XLarge", 
                    "url": "https://clients.mindbodyonline.com
                    /studios/ACMEYoga/3_xLarge.jpg?v=23" 
                }, 
                { 
                    "size": "Large", 
                    "url": "https://clients.mindbodyonline.com
                    /studios/ACMEYoga/3_large.jpg?v=23" 
                }, 
                { 
                    "size": "Mobile", 
                    "url": "https://clients.mindbodyonline.com
                    /studios/ACMEYoga/3_mobile.jpg?v=23" 
                } 
            ] 
        },
        "classImageURLs": [
            {
                "size": "XLarge",
                "url": "https://clients.mindbodyonline.com
                /studios/ACMEYoga/reservations/7_xLarge.jpg?v=23"
            },
            {
                "size": "Large",
                "url": "https://clients.mindbodyonline.com
                /studios/ACMEYoga/reservations/7_large.jpg?v=23"
            },
            {
                "size": "Unscaled",
                "url": "https://clients.mindbodyonline.com
                /studios/ACMEYoga/reservations/7_.jpg?v=23"
            }
        ]
    },
    "purchase": {
        "id": "6a5682e5-fa55-4db8-b739-b2d942f74177",
        "transactionId": 71300,
        "purchaseDateTime": "2016-12-15T19:32:26.867Z",
        "pricingOption": {
            "id": 5176,
            "type": "DropIn",
            "name": "Single Yoga Class",
            "description": ,
            "subtotal": 15,
            "tax": 0.75,
            "total": 15.75,
            "currencyCode": "USD",
            "userRestrictions": [
                "None"
            ]
        }
    }
}
Name Type Description
booking object Contains information about the booking created by the request.
booking.id string The booking’s globally unique identifier (a GUID).
booking.bookingDateTime string The date and time when the API successfully created the booking; the booking’s creation timestamp (in UTC).

See Dates and Times in Responses for more information.
booking.sessionsDeducted number The number of sessions the booking will deduct from the associated pass.
pass object Contains information about the pass that ispaying for the booking.
pass.id string The pass’s globally unique identifier (a GUID).
pass.type string The type of the pass.

Possible Values:
  • "DropIn"
  • "Series"
  • "Unlimited"
pass.name string The pass’s name.
pass.totalSessions number The number of sessions attached to the pass at the time of purchase. If the pass’s type is "Unlimited", you can ignore this field.
pass.sessionsRemaining number The number of unused sessions on the pass. If the pass’s type is "Unlimited", you can ignore this field.
pass.activationType string Specifies the pass’s activation type.

Possible Values:
  1. "OnPurchaseDate" - Indicates that the pass’s activation date will be the date when the user purchases the pass.
  2. "OnFirstVisitScheduledWithPass" - Indicates that the pass will activate on the same date as the user’s first booking that the pass reconciles. Until it is used to reconcile a booking, the activation date will match the purchase date.
  3. "CustomDate" - Indicates that the pass’s activation date is a specific date (e.g., 12/15/2016) which will not change regardless of purchase or booking dates.
pass.activationDateTime string The date and time after which the pass reconciles bookings (in UTC).

See Dates and Times in Responses for more information.

This value may be null. Read this note for more information.
pass.expirationDateTime string The date and time after which the pass no longer reconciles bookings (in UTC).

See Dates and Times in Responses for more information.

This value may be null. Read this note for more information.
location object Contains information about the location where the booking is taking place.
location.id number The location’s globally unique ID.
location.name string The location’s name.
location.olsonTimeZone string The location’s time zone in Olson format (e.g., "America/Los_Angeles"). Possible time zones.
location.contactInfo object Contains contact information for the location.
location.contactInfo.phone string The location’s phone number.
location.contactInfo.streetAddress string The street address portion of the location’s address.
location.contactInfo.city string The city portion of the location’s address.
location.contactInfo.stateCode string The state code portion of the location’s address (e.g. "CA" for California in the USA.).
location.contactInfo.postalCode string The postal code portion of the location’s address.
location.contactInfo.countryCode string The location’s country (e.g., "US"). This value will always be an ISO ALPHA-2 Code.
location.contactInfo.latitude number The location’s latitude.
location.contactInfo.longitude number The location’s longitude.
location.subscriber object Contains information about the subscriber to whom the location belongs.
location.subscriber.id number The subscriber’s globally unique ID.
location.subscriber.name string The subscriber’s name.
location.subscriber.website string The URL for the subscriber’s main website.
location.subscriber.cancellationPolicy string The subscriber’s cancellation policy text.
location.subscriber.refundPolicy string The subscriber’s refund policy text.
class object Contains information about the class where the booking holds a space.
class.id number The ID for this specific class within the current subscriber; the class’s ID.
class.typeId number The ID for the class’s class type within the current subscriber.
class.name string The name of the class.
class.description string The class’ subscriber-configured description. This string contains HTML.
class.registrationNotes string Special notes or instructions the subscriber wants to relay to users who are booking the class. For example, "Make sure you bring a sweat towel and bottle of water!".
class.startDateTime string The date and time when the class starts (in UTC).

See Dates and Times in Responses for more information.
class.endDateTime string The date and time when the class ends (in UTC).

See Dates and Times in Responses for more information.
class.assistantNames array of strings Contains the names of all assistant teachers assigned to the class.
class.roomName string The name of the room where the class is held (e.g., "Sun Room" or "Studio A"). This value might be null if the subscriber hides their classes’ rooms.
class.cancellationsAllowed boolean When true, indicates that the subscriber allows users to cancel bookings they make in this class, up to the cancellationWindowEndTime.

When false, indicates that the subscriber does not allow users to cancel bookings they make in this class, regardless of the cancellationWindowEndTime.
class.cancellationWindowEndTime string The date and time after which cancellations can no longer be made for bookings in the class (in UTC).

See Dates and Times in Responses for more information.
class.serviceCategoryIds array of numbers The IDs of the service categories whose pricing options can pay for the class.
class.staff object Contains information about the staff member who teaches the class.
class.staff.id number The staff member’s ID within the current subscriber.
class.staff.firstName string The staff member’s first name. This value might be null if the subscriber has hidden staff names.

If the subscriber uses staff nicknames, this value will be the staff’s nickname if they have one configured.
class.staff.lastName string The staff member’s last name. This value will be null if the subscriber has hidden staff names.

If the subscriber uses staff nicknames, this value will be null if the staff member has a nickname configured.
class.staff.gender string The staff member’s gender.

Possible Values:
  • "Male"
  • "Female"
class.staff.bio string The staff member’s biography.
class.staff.staffImageURLs array of objects Contains information about the different sizes of images available for the staff member.
class.staff.staffImageURLs.size string The size of the image.

Possible Values:
  • "XLarge" - The staff’s image with a maximum width and height of 600 pixels.
  • "Large" - The staff’s image with a maximum width and height of 200 pixels.
  • "Mobile" - The staff’s image with a maximum width and height of 128 pixels.
class.staff.staffImageURLs.url string The URL for the image.

class.classImageURLs array of objects Contains information about the different sizes of images available for the class.
class.classImageURLs.size string The size of the image.

Possible Values:
  • "XLarge" - The class’s image with a maximum width and height of 600 pixels.
  • "Large" - The class’s image with a maximum width and height of 200 pixels.
  • "Unscaled" - The class’s image with its original size. Classes cannot have images larger than 4MB.
class.classImageURLs.url string The URL for the image.

purchase object Contains information about the purchase that the booking created. This object will be null if a pass is paying for the booking.
purchase.id string The purchase’s globally unique identifier.
purchase.transactionId number The purchase’s transaction ID, unique within the booking’s subscriber. Subscribers refer to this as the “sale ID” and might need this number to look up a purchase in their data.
purchase.purchaseDateTime string The date and time when the API successfully created the purchase; the purchase’s creation timestamp (in UTC).

See Dates and Times in Responses for more information.
purchase.pricingOption array of objects Contains information about the purchased pricing option.
purchase.pricingOption.id number The pricing option’s ID at the current subscriber.
purchase.pricingOption.type string Describes the type of the pricing option.

Possible Values:
  • "DropIn"
  • "Series"
  • "Unlimited"
purchase.pricingOption.name string The pricing option’s name.
purchase.pricingOption.description string The pricing option’s subscriber-configured description.
purchase.pricingOption.subtotal number The total cost of the pricing option before applying taxes.
purchase.pricingOption.tax number The total cost of taxes for the pricing option.
purchase.pricingOption.total number The total cost of the pricing option, including taxes.
purchase.pricingOption.currencyCode string A currency code based on the ISO 4217 specification (e.g., "USD" represents the US dollar).
purchase.pricingOption.userRestrictions array of strings Specifies whether or not the subscriber restricts the purchasing of this pricing option to users that meet specific criteria.

Possible Values:
  1. "None" - Indicates that all users can purchase this pricing option, regardless of their history at the subscriber.
  2. "IntroductoryOfferFirstTimeCustomerOfPricingOption" - Indicates that only users who have never before purchased this pricing option may purchase it now.
  3. "IntroductoryOfferFirstTimeCustomerAtBusiness" - Indicates that only users who have no previous purchases at this subscriber may purchase this pricing option.

Errors

Example Error:

{
    "error": {
        "errorCode": "14040007",
        "errorType": "pricingOptionNotFound",
        "message": "Pricing option not found."
    }
}

This endpoint may return the errors listed below. We recommend that you catch and handle each error for an optimal, frictionless user experience. We also recommend attempting to reproduce each error during your development and test process in order to ensure that your back-end application is handling them correctly.

HTTP Status Code errorCode errorType Description
400 14000003 missingRequiredProperty Returned when one of the required request properties is null or empty. Check the error’s message property to find the name of the invalid property.
400 14000005 invalidValue Returned when a request body property:
  • Has violated its minimum acceptable value
  • Has violated its maximum acceptable value
  • Is required but is missing
  • Is used with other incompatible request properties
Check the error’s message property to find the name of the invalid property.
400 14000007 invalidFieldCombination Returned when you use two incompatible request body fields together (e.g., passing in bookingReconciliation.pricingOptionTotal when bookingReconciliation.type is "Pass").
400 14000020 reconciliationPOClassMismatch The pricing option specified in the request does not pay for the specified class.
400 14000021 reconciliationPassClassMismatch The pass specified in the request does not pay for the specified class.
400 14000022 reconciliationNotEnoughSessions The pass specified in the request does not have enough sessions remaining to pay for the class.
400 14000023 reconciliationCanNotBeCompletedByUser The user cannot purchase the pricing option due to its userRestrictions. The user should contact the subscriber for more information.
400 14000024 reconciliationPOPriceMismatch Returned when the bookingReconciliation.pricingOptionTotal does not match the actual price of the pricing option.
400 14000030 classNotCurrentlyAvailableForBooking The class cannot be booked at this time.
400 14000031 classOutsideBookingWindow The user cannot book the class because the current time is outside its booking window.
400 14000032 classNoAvailableCapacity The user cannot book the class because it is full.
400 14000033 classCancelled The subscriber cancelled the class; users cannot book it.
400 14000039 classNotBookableByUser The user cannot book the class. They should contact the subscriber for more information.
400 14000080 creditCardTypeNotAccepted The subscriber does not accept the card type specified in the request. If you receive this error, alter your workflow so that you store the creditCardTypesAccepted property returned from GET Locations and use it to validate the card type being sent in this request.
400 14000081 creditCardExpired The user cannot user their credit card because it is expired.
400 14000082 creditCardDeclinedByProcessor The subscriber’s payment processor declined the request’s credit card. The user should contact the subscriber to troubleshoot this issue further.
400 14000083 creditCardProcessingTimeout The credit card processor took too long and the call timed out. The user should contact the subscriber to troubleshoot this issue further.
400 14000089 creditCardProcessingFailure The credit card processor failed to charge the user’s card. They should contact the subscriber to troubleshoot this issue further.
400 14040001 locationNotFound The locationId passed in the request body was not found.
400 14040005 classNotFound The classId passed in the request body was not found.
400 14040007 pricingOptionNotFound The pricing option associated with the bookingReconciliation.id passed in the request body was not found.
400 14040030 passNotFound The pass associated with the bookingReconciliation.id was either not found, or it had no remaining sessions.
401 14010001 missingAPIKeyHeader An API-Key header was not included in the request.
401 14010002 missingAuthorizationHeader An Authorization header was not included in the request.
409 14090020 bookingAlreadyInProgress A previous request with the same Idempotency-Key header is still processing. The API will not complete this request.
415 14150002 unsupportedMediaType A Content-Type header was passed with a value other than application/json. This is the only accepted content type for this endpoint.
429 14290001 tooManyRequests You have exceeded the rate limit for this endpoint.
429 14290002 dailyRequestLimitExceeded You have exceeded the daily request limit for this endpoint.
500 15009999 criticalServerError The user’s booking at the subscriber succeeded and their card was charged (if booking with a pricing option), but something prevented us from tracking this information against your Affiliate account. Please move your integration out of a live environment and contact Mindbody developer support immediately.

DELETE

curl -X DELETE \
-H "API-Key: {yourAPIKey}" \
-H "Authorization: Basic {yourEncodedClientKeyAndClientSecret}" \
-A "{yourAppName}" \
"https://mb-api.mindbodyonline.com/affiliate/api/v1/users/{uniqueUserId}/bookings/{bookingId}"
var client = new RestClient("https://mb-api.mindbodyonline.com/affiliate/api/v1/users/{uniqueUserId}/bookings/{bookingId}");
var request = new RestRequest(Method.DELETE);
request.AddHeader("authorization", "Basic {yourEncodedClientKeyAndClientSecret}");
request.AddHeader("api-key", "{yourAPIKey}");
IRestResponse response = client.Execute(request);
<?php

$request = new HttpRequest();
$request->setUrl('https://mb-api.mindbodyonline.com/affiliate/api/v1/users/{uniqueUserId}/bookings/{bookingId}');
$request->setMethod(HTTP_METH_DELETE);

$request->setHeaders(array(
  'authorization' => 'Basic {yourEncodedClientKeyAndClientSecret}',
  'api-key' => '{yourAPIKey}'
));

try {
  $response = $request->send();

  echo $response->getBody();
} catch (HttpException $ex) {
  echo $ex;
}
?>
import http.client

conn = http.client.HTTPSConnection("mb-api.mindbodyonline.com")

headers = {
    'api-key': "{yourAPIKey}",
    'authorization': "Basic {yourEncodedClientKeyAndClientSecret}"
    }

conn.request("DELETE", "/api/v1/users/{uniqueUserId}/bookings/{bookingId}", headers=headers)

res = conn.getresponse()
data = res.read()

print(data.decode("utf-8"))
require 'uri'
require 'net/http'

url = URI("https://mb-api.mindbodyonline.com/affiliate/api/v1/users/{uniqueUserId}/bookings/{bookingId}")

http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
http.verify_mode = OpenSSL::SSL::VERIFY_NONE

request = Net::HTTP::Delete.new(url)
request["api-key"] = '{yourAPIKey}'
request["authorization"] = 'Basic {yourEncodedClientKeyAndClientSecret}'

response = http.request(request)
puts response.read_body

https://mb-api.mindbodyonline.com/affiliate/api/v1/users/{uniqueUserId}/bookings/{bookingId}

This endpoint allows users to cancel a booking.

Pagination

This endpoint does not support pagination.

Best Practices

  • Use when a user wants to cancel a booking and remove it from their schedule.

Headers

Name Type Description
API-Key string Your API key.
Authorization string Your encoded client key and client secret.
See Authentication and Security for help creating this string.

URL Parameters

Name Type Description
uniqueUserId string The user’s unique identifier within your system. This ID must:
  • Be between 1 and 64 characters in length
  • Contain only:
    • alphanumeric characters (lowercase)
    • _ (underscores)
    • - (hyphens)
    • ~ (tildes)
    • . (periods)
bookingId string The globally unique identifier of the booking your user wants to cancel (a GUID). This is the id property on the booking object return from GET Bookings and the booking.id property on the object returned from POST Booking.

Query Parameters

Name Type Description
suppressCancellationConfirmationEmail
Optional
boolean When true, the subscriber will not send their customized cancellation confirmation email to the user. Instead, you can send a tailored email that is consistent with the user’s experience within your app.

when false or omitted, the subscriber will send their customized cancellation confirmation email to the user.

Response

HTTP Status Code: 200 OK

{
    "message": "Cancellation successful.",
    "pass": {
        "id": "d1e9b2be-655a-4419-b7dd-30aa84f7aa70"
    }
}
Name Type Description
message string A brief message describing the cancellation’s status.

Possible Values:
  1. "Cancellation successful." - Indicates a successful cancellation.
pass object Contains information about the pass that reclaimed a session after the user cancelled this booking.
pass.id string The globally unique identifier of the pass that reclaimed a session.

Errors

Example Error:

{
    "error": {
        "errorCode": "14090013",
        "errorType": "bookingAlreadyCancelled",
        "message": "Booking cancellation failed. Booking already cancelled."
    }
}

This endpoint may return the errors listed below. We recommend that you catch and handle each error for an optimal, frictionless user experience. We also recommend attempting to reproduce each error during your development and test process in order to ensure that your back-end application is handling them correctly.

HTTP Status Code errorCode errorType Description
400 14000004 invalidParameter Returned when a query parameter:
  • Has violated its minimum acceptable value
  • Has violated its maximum acceptable value
  • Is required but is missing
  • Is used with other incompatible query parameters
Check the error’s message property to find the name of the invalid query parameter.
401 14010001 missingAPIKeyHeader An API-Key header was not included in the request.
401 14010002 missingAuthorizationHeader An Authorization header was not included in the request.
404 14040010 userNotFound The uniqueUserId passed as a URL Parameter was not found.
404 14040020 bookingNotFound The bookingId passed as a URL Parameter was not found.
409 14090011 bookingNotCancellable The user cannot cancel the booking at this time.
409 14090012 bookingCancellationOutsideTimeWindow The current time is outside the subscriber’s configured cancellation window.
409 14090013 bookingAlreadyCancelled The booking has already been cancelled.
409 14090014 bookingNotCancellableClassCancelled The subscriber cancelled the booking’s class; the booking cannot be cancelled.
429 14290001 tooManyRequests You have exceeded the rate limit for this endpoint.
429 14290002 dailyRequestLimitExceeded You have exceeded the daily request limit for this endpoint.

Passes

Passes are purchased pricing options on a user’s account that they can use to book classes.

Activation and Expiration Dates

If a user cancels all bookings associated with a pass, and its activationType is OnFirstVisitScheduledWithPass, both its activationDateTime and expirationDateTime will be null. These values will not be populated until the user uses the pass to reconcile at least one booking. A pass in this situation can be used at any point in the future, and will not expire until it is used to reconcile a booking.

GET

curl -X GET \
-H "API-Key: {yourAPIKey}" \
-H "Authorization: Basic {yourEncodedClientKeyAndClientSecret}" \
-A "{yourAppName}" \
"https://mb-api.mindbodyonline.com/affiliate/api/v1/users/{uniqueUserId}/passes"
var client = new RestClient("https://mb-api.mindbodyonline.com/affiliate/api/v1/users/{uniqueUserId}/passes");
var request = new RestRequest(Method.GET);
request.AddHeader("authorization", "Basic {yourEncodedClientKeyAndClientSecret}");
request.AddHeader("api-key", "{yourAPIKey}");
IRestResponse response = client.Execute(request);
<?php

$request = new HttpRequest();
$request->setUrl('https://mb-api.mindbodyonline.com/affiliate/api/v1/users/{uniqueUserId}/passes');
$request->setMethod(HTTP_METH_GET);

$request->setHeaders(array(
  'authorization' => 'Basic {yourEncodedClientKeyAndClientSecret}',
  'api-key' => '{yourAPIKey}'
));

try {
  $response = $request->send();

  echo $response->getBody();
} catch (HttpException $ex) {
  echo $ex;
}
?>
import http.client

conn = http.client.HTTPSConnection("mb-api.mindbodyonline.com")

headers = {
    'api-key': "{yourAPIKey}",
    'authorization': "Basic {yourEncodedClientKeyAndClientSecret}"
    }

conn.request("GET", "/api/v1/users/{uniqueUserId}/passes", headers=headers)

res = conn.getresponse()
data = res.read()

print(data.decode("utf-8"))
require 'uri'
require 'net/http'

url = URI("https://mb-api.mindbodyonline.com/affiliate/api/v1/users/{uniqueUserId}/passes")

http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
http.verify_mode = OpenSSL::SSL::VERIFY_NONE

request = Net::HTTP::Get.new(url)
request["api-key"] = '{yourAPIKey}'
request["authorization"] = 'Basic {yourEncodedClientKeyAndClientSecret}'

response = http.request(request)
puts response.read_body

https://mb-api.mindbodyonline.com/affiliate/api/v1/users/{uniqueUserId}/passes

This endpoint retrieves passes on a user’s account.

You can retrieve a specific pass by calling GET (by ID).

Pagination

The endpoint supports pagination.

Best Practices

  • Make this call at the start of a workflow that does not support “guest” bookings so you have context for what the user already has on their account. The pass information can then be used to:
  • Use before booking to allow users to choose a pass on file instead of purchasing a new pricing option.
  • Use before making a POST Booking call if the user is a not a “guest” user.
  • Use when constructing account status pages to show a user a list of their current and/or expired passes.

Headers

Name Type Description
API-Key string Your API key.
Authorization string Your encoded client key and client secret.
See Authentication and Security for help creating this string.

URL Parameters

Name Type Description
uniqueUserId string The user’s unique identifier within your system. This ID must:
  • Be between 1 and 64 characters in length
  • Contain only:
    • alphanumeric characters (lowercase)
    • _ (underscores)
    • - (hyphens)
    • ~ (tildes)
    • . (periods)

Query Parameters

Name Type Description
subscriberId
Optional
number Filters results down to the user’s passes at the subscriber identified by this ID. This is the subscriber.id property on the location object returned from multiple calls in the API.
limitToUsable
Optional
boolean When true or omitted, filters results down to passes that have remaining sessions and have not yet expired.

When false, returns all passes regardless of their remaining session count or expiration date.default: true
maxResults
Optional
number Sets the maximum number of records returned in the results.default: 10 | max: 100 | min: 0
offset
Optional
number Sets the number of records skipped over to reach the returned results.default: 0 | min: 0
orderBy
Optional
string Designates which field in the response body orders the results.

Accepted Values:
  • subscriberId
  • expiratationDateTime
default: subscriberId
order
Optional
string Orders the results in ascending or descending order based on the field specified by orderBy.

Accepted Values:
  • asc
  • desc
default: asc

Response

HTTP Status Code: 200 OK

{
    "items": [
        {
            "id": "598a6916-7876-406e-9537-db6af825f9a2",
            "pricingOptionId": 5176,
            "purchaseId": "6b93a69e-4547-412d-a00e-700bd3691bd4",
            "subscriber": {
                "id": 135415,
                "name": "ACME Yoga"
            },
            "type": "Series",
            "name": "5 Pack Yoga Classes",
            "totalSessions": 5,
            "sessionsRemaining": 4,
            "activationType": "OnPurchaseDate",
            "activationDateTime": "2016-12-15T00:00:00",
            "expirationDateTime": "2017-12-15T00:00:00",
            "serviceCategoryId": 25,
            "usableState": "Usable"
        }
    ],
    "offset": 0,
    "maxResults": 1,
    "totalResults": 7
}
Name Type Description
id string The pass’s globally unique identifier (a GUID).
pricingOptionId number The ID of the pricing option that generated this pass when purchased.
purchaseId string The globally unique identifier of the purchase that created the pass. This is the id property returned from GET Purchases.
subscriber object Contains information about the subscriber where the user purchased the pass.
subscriber.id number The subscriber’s globally unique ID.
subscriber.name string The subscriber’s name.
type string The type of the pass.

Possible Values:
  • "DropIn"
  • "Series"
  • "Unlimited"
name string The pass’s name.
totalSessions number The number of sessions attached to the pass at the time of purchase. If the pass’s type is "Unlimited", you can ignore this field.
sessionsRemaining number The number of unused sessions on the pass. If the pass’s type is "Unlimited", you can ignore this field.
activationType string Specifies the pricing option’s activation type.

Possible Values:
  1. "OnPurchaseDate" - Indicates that the pricing option’s activation date will be the date when the user purchases the pricing option.
  2. "OnFirstVisitScheduledWithPass" - Indicates that the pricing option will activate on the same date as the user’s first booking that the pricing option reconciles. Until it is used to reconcile a booking, the activation date will match the purchase date.
  3. "CustomDate" - Indicates that the pricing option’s activation date is a specific date (e.g., 12/15/2016) which will not change regardless of purchase or booking dates.
activationDateTime string The date and time after which the pass reconciles bookings (in UTC).

See Dates and Times in Responses for more information.

This value may be null. Read this note for more information.
expirationDateTime string The date and time after which the pass no longer reconciles bookings (in UTC).

See Dates and Times in Responses for more information.

This value may be null. Read this note for more information.
serviceCategoryId number The ID of the service category at the current subscriber to which the pass belongs.
usableState string Specifies whether or not the user can use the pass.

Possible Values:
  1. "Usable" - Indicates that the user can use the pass.
  2. "UnusableZeroSessionsRemaining" - Indicates that the user already used all of the pass’ sessions on previous bookings.
  3. "UnusableExpired" - Indicates that the user cannot use the pass because it has expired.
  4. "UnusablePurchaseReturned" - Indicates that the user cannot use the pass because its associated purchase was returned by the subscriber.
  5. "UnusablePurchaseVoided" - Indicates that the user cannot use the pass because its associated purchase was voided by the subscriber.
  6. "UnusableForcedByBusiness" - Indicates that the subscriber explicitly marked the pass as unusable.
If the user believes a pass’ state is incorrect, they can contact the subscriber for more assistance.

Errors

Example Error:

{
    "error": {
        "errorCode": "14000004",
        "errorType": "invalidParameter",
        "message": "The following parameter is invalid: limitToUsable."
    }
}

This endpoint may return the errors listed below. We recommend that you catch and handle each error for an optimal, frictionless user experience. We also recommend attempting to reproduce each error during your development and test process in order to ensure that your back-end application is handling them correctly.

HTTP Status Code errorCode errorType Description
400 14000004 invalidParameter Returned when a query parameter:
  • Has violated its minimum acceptable value
  • Has violated its maximum acceptable value
  • Is required but is missing
  • Is used with other incompatible query parameters
Check the error’s message property to find the name of the invalid query parameter.
401 14010001 missingAPIKeyHeader An API-Key header was not included in the request.
401 14010002 missingAuthorizationHeader An Authorization header was not included in the request.
404 14040010 userNotFound The uniqueUserId passed as a URL Parameter was not found.
429 14290001 tooManyRequests You have exceeded the rate limit for this endpoint.
429 14290002 dailyRequestLimitExceeded You have exceeded the daily request limit for this endpoint.

GET (by ID)

curl -X GET \
-H "API-Key: {yourAPIKey}" \
-H "Authorization: Basic {yourEncodedClientKeyAndClientSecret}" \
-A "{yourAppName}" \
"https://mb-api.mindbodyonline.com/affiliate/api/v1/users/{uniqueUserId}/passes/{passId}"
var client = new RestClient("https://mb-api.mindbodyonline.com/affiliate/api/v1/users/{uniqueUserId}/passes/{passId}");
var request = new RestRequest(Method.GET);
request.AddHeader("authorization", "Basic {yourEncodedClientKeyAndClientSecret}");
request.AddHeader("api-key", "{yourAPIKey}");
IRestResponse response = client.Execute(request);
<?php

$request = new HttpRequest();
$request->setUrl('https://mb-api.mindbodyonline.com/affiliate/api/v1/users/{uniqueUserId}/passes/{passId}');
$request->setMethod(HTTP_METH_GET);

$request->setHeaders(array(
  'authorization' => 'Basic {yourEncodedClientKeyAndClientSecret}',
  'api-key' => '{yourAPIKey}'
));

try {
  $response = $request->send();

  echo $response->getBody();
} catch (HttpException $ex) {
  echo $ex;
}
?>
import http.client

conn = http.client.HTTPSConnection("mb-api.mindbodyonline.com")

headers = {
    'api-key': "{yourAPIKey}",
    'authorization': "Basic {yourEncodedClientKeyAndClientSecret}"
    }

conn.request("GET", "/api/v1/users/{uniqueUserId}/passes/{passId}", headers=headers)

res = conn.getresponse()
data = res.read()

print(data.decode("utf-8"))
require 'uri'
require 'net/http'

url = URI("https://mb-api.mindbodyonline.com/affiliate/api/v1/users/{uniqueUserId}/passes/{passId}")

http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
http.verify_mode = OpenSSL::SSL::VERIFY_NONE

request = Net::HTTP::Get.new(url)
request["api-key"] = '{yourAPIKey}'
request["authorization"] = 'Basic {yourEncodedClientKeyAndClientSecret}'

response = http.request(request)
puts response.read_body

https://mb-api.mindbodyonline.com/affiliate/api/v1/users/{uniqueUserId}/passes/{passId}

This endpoint finds and returns the single pass associated with the passed ID.

Pagination

This endpoint does not support pagination.

Best Practices

  • Use when fetching pass details for a pass where you already have its ID.

Headers

Name Type Description
API-Key string Your API key.
Authorization string Your encoded client key and client secret.
See Authentication and Security for help creating this string.

URL Parameters

Name Type Description
uniqueUserId string The user’s unique identifier within your system. This ID must:
  • Be between 1 and 64 characters in length
  • Contain only:
    • alphanumeric characters (lowercase)
    • _ (underscores)
    • - (hyphens)
    • ~ (tildes)
    • . (periods)
passId string Returns the single pass associated with this globally unique identifier (a GUID). Do not use query parameters when fetching this resource.

Response

Partial example of response content structure:

{
    "id": "598a6916-7876-406e-9537-db6af825f9a2",
    "purchaseId": "6b93a69e-4547-412d-a00e-700bd3691bd4",
    ...
}

This response object is the same as the objects contained in the items field in the GET Passes response . View that documentation for detailed information about the response object’s fields.

Errors

Example Error:

{
    "error": {
        "errorCode": "14040030",
        "errorType": "passNotFound",
        "message": "Pass not found."
    }
}

This endpoint may return the errors listed below. We recommend that you catch and handle each error for an optimal, frictionless user experience. We also recommend attempting to reproduce each error during your development and test process in order to ensure that your back-end application is handling them correctly.

HTTP Status Code errorCode errorType Description
401 14010001 missingAPIKeyHeader An API-Key header was not included in the request.
401 14010002 missingAuthorizationHeader An Authorization header was not included in the request.
404 14040010 userNotFound The uniqueUserId passed as a URL Parameter was not found.
404 14040030 passNotFound The passId passed as a URL Parameter was not found.
429 14290001 tooManyRequests You have exceeded the rate limit for this endpoint.
429 14290002 dailyRequestLimitExceeded You have exceeded the daily request limit for this endpoint.

Purchases

Purchases

Any call to POST Booking using a bookingReconciliation.type of PricingOption generates a purchase record. Purchases contain information about:

  • the pricing option purchased
  • the pass created as a result of the purchase
  • the location where the user used the pass

Purchases are essentially receipts; they represent a snapshot of a purchase at a specific point in time. Their information does not change as subscribers make alterations to their data. The only field that may change is the purchase’s purchaseState.

Returns and Refunds

If a user wants to return or receive a refund for a pass, they must contact the subscriber and work it out with the business. Currently, no APIs exist to accommodate return or refund workflows.

Use the GET Locations call to retrieve a subscriber’s refund policy text.

GET

curl -X GET \
-H "API-Key: {yourAPIKey}" \
-H "Authorization: Basic {yourEncodedClientKeyAndClientSecret}" \
-A "{yourAppName}" \
"https://mb-api.mindbodyonline.com/affiliate/api/v1/users/{uniqueUserId}/purchases"
var client = new RestClient("https://mb-api.mindbodyonline.com/affiliate/api/v1/users/{uniqueUserId}/purchases");
var request = new RestRequest(Method.GET);
request.AddHeader("authorization", "Basic {yourEncodedClientKeyAndClientSecret}");
request.AddHeader("api-key", "{yourAPIKey}");
IRestResponse response = client.Execute(request);
<?php

$request = new HttpRequest();
$request->setUrl('https://mb-api.mindbodyonline.com/affiliate/api/v1/users/{uniqueUserId}/purchases');
$request->setMethod(HTTP_METH_GET);

$request->setHeaders(array(
  'authorization' => 'Basic {yourEncodedClientKeyAndClientSecret}',
  'api-key' => '{yourAPIKey}'
));

try {
  $response = $request->send();

  echo $response->getBody();
} catch (HttpException $ex) {
  echo $ex;
}
?>
import http.client

conn = http.client.HTTPSConnection("mb-api.mindbodyonline.com")

headers = {
    'api-key': "{yourAPIKey}",
    'authorization': "Basic {yourEncodedClientKeyAndClientSecret}"
    }

conn.request("GET", "/api/v1/users/{uniqueUserId}/purchases", headers=headers)

res = conn.getresponse()
data = res.read()

print(data.decode("utf-8"))
require 'uri'
require 'net/http'

url = URI("https://mb-api.mindbodyonline.com/affiliate/api/v1/users/{uniqueUserId}/purchases")

http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
http.verify_mode = OpenSSL::SSL::VERIFY_NONE

request = Net::HTTP::Get.new(url)
request["api-key"] = '{yourAPIKey}'
request["authorization"] = 'Basic {yourEncodedClientKeyAndClientSecret}'

response = http.request(request)
puts response.read_body

https://mb-api.mindbodyonline.com/affiliate/api/v1/users/{uniqueUserId}/purchases

This endpoint retrieves purchases on a user’s account.

You can retrieve a specific purchase by calling GET (by ID).

Pagination

This endpoint supports pagination.

Best Practices

  • Use when constructing account status pages to show the user a list of their purchases.
  • Use when you need to find the location where a user purchased a pass. This is useful when:
    • Showing a pass’s expiration date in the proper time zone context

Headers

Name Type Description
API-Key string Your API key.
Authorization string Your encoded client key and client secret.
See Authentication and Security for help creating this string.

URL Parameters

Name Type Description
uniqueUserId string The user’s unique identifier within your system. This ID must:
  • Be between 1 and 64 characters in length
  • Contain only:
    • alphanumeric characters (lowercase)
    • _ (underscores)
    • - (hyphens)
    • ~ (tildes)
    • . (periods)

Query Parameters

Name Type Description
locationId
Optional
number Filters the results down to the user’s purchases at the location identified by this ID. This is the id property on the location object returned from the GET Locations call and the location.id property returned from other calls in the API.
subscriberId
Optional
number Filters results down to the user’s purchases at the subscriber identified by this ID. This is the subscriber.id property on the location object returned from multiple calls in the API.
fromPurchaseDateTime
Optional
string The UTC date/time that sets the beginning of the time-frame within which you are searching for purchases. The results contain all purchases made on and after this date/time up through the specified toPurchaseDateTime. If toPurchaseDateTime is omitted, purchases are returned up to the current time.

See Dates and Times in Requests for more information.
toPurchaseDateTime
Optional
string The UTC date/time that sets the end of the time-frame within which you are searching for purchases. The results will contain all purchases made on and before this date/time back through the specified fromPurchaseDateTime. If fromPurchaseDateTime is omitted, purchases are returned up to 365 days in the past.

See Dates and Times in Requests for more information.
maxResults
Optional
number Sets the maximum number of records returned in the results.default: 50 | max: 500 | min: 0
offset
Optional
number Sets the number of records skipped over to reach the returned results.default: 0 | min: 0
orderBy
Optional
string Designates which field in the response body orders the results.

Accepted Values:
  • purchaseDateTime
  • locationId
  • subscriberId
default: purchaseDateTime
order
Optional
string Orders the results in ascending or descending order based on the field specified by orderBy.

Accepted Values:
  • asc
  • desc
default: desc

Response

HTTP Status Code: 200 OK

{
    "items": [
        {
            "id": "6b93a69e-4547-412d-a00e-700b91691bd4",
            "passId": "598a6916-7876-406e-9537-db6e4825f9a2",
            "transactionId": 71300,
            "purchaseState": "Purchased",
            "pricingOption": {
                "id": 5176,
                "serviceCategoryId": 25,
                "name": "Single Yoga Class",
                "description": null,
                "type": "DropIn",
                "subtotal": 15,
                "tax": 0.75,
                "total": 15.75,
                "currencyCode": "USD",
                "activationType": "OnPurchaseDate",
                "expirationTimeUnit": "Months",
                "expirationTimeUnitValue": 12,
                "activationDateTime": "2017-01-15T00:00:00",
                "expirationDateTime": "2018-01-15T00:00:00",
                "userRestrictions": [
                    "None"
                ]
            },
            "location": {
                "id": 12856,
                "name": "ACME Yoga",
                "olsonTimeZone": "America/Los_Angeles",
                "subscriber": {
                    "id": 13548,
                    "name": "ACME Yoga",
                    "website": "https://yogashala.com",
                    "cancellationPolicy": null,
                    "refundPolicy": null
                },
                "contactInfo": {
                    "phone": "8055551234",
                    "streetAddress": "4051 Broad St",
                    "city": "San Luis Obispo",
                    "stateCode": "CA",
                    "postalCode": "93405",
                    "countryCode": "US",
                    "longitude": -120.657846,
                    "latitude": 35.300495
                }
            },
            "purchaseDateTime": "2016-12-15T19:32:26.867Z"
        }
    ],
    "offset": 0,
    "maxResults": 1,
    "totalResults": 20
}
Name Type Description
id string The purchase’s globally unique identifier.
passId string The globally unique identifier of the pass that the purchase created. This is the id property on the pass object returned by GET Passes and the pass.id property returned from other calls in the API.
transactionId number The purchase’s transaction ID, unique within the booking’s subscriber. Subscribers refer to this as the “sale ID” and might need this number to look up a purchase in their data.
purchaseState string The purchase’s current state.

Possible Values:
  1. "Purchased" - Indicates that the purchase is valid and unchanged.
  2. "Returned" - Indicates that the subscriber returned the purchase. All passes associated with the purchase are no longer usable.
  3. "Voided" - Indicates that the subscriber voided the purchase. All passes associated with the purchase are no longer usable.
pricingOption object Contains information about the purchased pricing option.
pricingOption.id number The pricing option’s ID at the current subscriber.
pricingOption.serviceCategoryId number The ID of the service category at the current subscriber to which the pricing option belongs.
pricingOption.name string The pricing option’s name.
pricingOption.description string The pricing option’s subscriber-configured description.
pricingOption.type string Describes the type of the pricing option.

Possible Values:
  • "DropIn"
  • "Series"
  • "Unlimited"
pricingOption.subtotal number The total cost of the pricing option before applying taxes.
pricingOption.tax number The total cost of taxes for the pricing option.
pricingOption.total number The total cost of the pricing option, including taxes.
pricingOption.currencyCode string A currency code based on the ISO 4217 specification (e.g., "USD" represents the US dollar).
pricingOption.activationType string Specifies the pricing option’s activation type.

Possible Values:
  1. "OnPurchaseDate" - Indicates that the pricing option’s activation date will be the date when the user purchases the pricing option.
  2. "OnFirstVisitScheduledWithPass" - Indicates that the pricing option will activate on the same date as the user’s first booking that the pricing option reconciles. Until it is used to reconcile a booking, the activation date will match the purchase date.
  3. "CustomDate" - Indicates that the pricing option’s activation date is a specific date (e.g., 12/15/2016) which will not change regardless of purchase or booking dates.
pricingOption.expirationTimeUnit string The type of unit used to calculate the pricing option’s expiration date (e.g., this is the “months” in a pricing option that isactive for “12 months”).

Possible Values:
  1. "Days" - Indicates that the pricing option’s expiration date is calculated in a number of days from its activation date.
  2. "Months" - Indicates that the pricing option’s expiration date is calculated in a number of months from its activation date.
This is always used with expirationTimeUnitValue.
pricingOption.expirationTimeUnitValue number The number of expirationUnits used to calculate the pricing option’s expiration date (e.g., this is the “12” in a pricing option that isactive for “12 months”).

This is always used with expirationTimeUnit.
pricingOption.activationDateTime string The date and time after which the pricing option reconciles bookings (in UTC).

See Dates and Times in Responses for more information.
pricingOption.expirationDateTime string The date and time after which the pricing option no longer reconciles bookings (in UTC).

See Dates and Times in Responses for more information.
pricingOption.userRestrictions array of strings Specifies whether or not the subscriber restricts the purchasing of this pricing option to users that meet specific criteria.

Possible Values:
  1. "None" - Indicates that all users can purchase this pricing option, regardless of their history at the subscriber.
  2. "IntroductoryOfferFirstTimeCustomerOfPricingOption" - Indicates that only users who have never before purchased this pricing option may purchase it now.
  3. "IntroductoryOfferFirstTimeCustomerAtBusiness" - Indicates that only users who have no previous purchases at this subscriber may purchase this pricing option.
location object Contains information about the location where the user made this purchase.
location.id number The location’s globally unique ID.
location.name string The location’s name.
location.olsonTimeZone string The location’s time zone in Olson format (e.g., "America/Los_Angeles"). Possible time zones.
location.subscriber object Contains information about the subscriber to whom the location belongs.
location.subscriber.id number The subscriber’s globally unique ID.
location.subscriber.name string The subscriber’s name.
location.subscriber.website string The URL for the subscriber’s main website.
location.subscriber.cancellationPolicy string The subscriber’s cancellation policy text.
location.subscriber.refundPolicy string The subscriber’s refund policy text.
location.contactInfo object Contains contact information for the location.
location.contactInfo.phone string The location’s phone number.
location.contactInfo.streetAddress string The street address portion of the location’s address.
location.contactInfo.city string The city portion of the location’s address.
location.contactInfo.stateCode string The state code portion of the location’s address (e.g. "CA" for California in the USA.).
location.contactInfo.postalCode string The postal code portion of the location’s address.
location.contactInfo.countryCode string The location’s country (e.g., "US"). This value will always be an ISO ALPHA-2 Code.
location.contactInfo.longitude number The location’s longitude.
location.contactInfo.latitude number The location’s latitude.
purchaseDateTime string The date and time when the API successfully created the purchase; the purchase’s creation timestamp (in UTC).

See Dates and Times in Responses for more information.

Errors

Example Error:

{
    "error": {
        "errorCode": "14000004",
        "errorType": "invalidParameter",
        "message": "The following parameter is invalid: purchaseDateTime."
    }
}

This endpoint may return the errors listed below. We recommend that you catch and handle each error for an optimal, frictionless user experience. We also recommend attempting to reproduce each error during your development and test process in order to ensure that your back-end application is handling them correctly.

HTTP Status Code errorCode errorType Description
400 14000004 invalidParameter Returned when a query parameter:
  • Has violated its minimum acceptable value
  • Has violated its maximum acceptable value
  • Is required but is missing
  • Is used with other incompatible query parameters
Check the error’s message property to find the name of the invalid query parameter.
401 14010001 missingAPIKeyHeader An API-Key header was not included in the request.
401 14010002 missingAuthorizationHeader An Authorization header was not included in the request.
404 14040010 userNotFound The uniqueUserId passed as a URL Parameter was not found.
429 14290001 tooManyRequests You have exceeded the rate limit for this endpoint.
429 14290002 dailyRequestLimitExceeded You have exceeded the daily request limit for this endpoint.

GET (by ID)

curl -X GET \
-H "API-Key: {yourAPIKey}" \
-H "Authorization: Basic {yourEncodedClientKeyAndClientSecret}" \
-A "{yourAppName}" \
"https://mb-api.mindbodyonline.com/affiliate/api/v1/users/{uniqueUserId}/purchases/{purchaseId}"
var client = new RestClient("https://mb-api.mindbodyonline.com/affiliate/api/v1/users/{uniqueUserId}/purchases/{purchaseId}");
var request = new RestRequest(Method.GET);
request.AddHeader("authorization", "Basic {yourEncodedClientKeyAndClientSecret}");
request.AddHeader("api-key", "{yourAPIKey}");
IRestResponse response = client.Execute(request);
<?php

$request = new HttpRequest();
$request->setUrl('https://mb-api.mindbodyonline.com/affiliate/api/v1/users/{uniqueUserId}/purchases/{purchaseId}');
$request->setMethod(HTTP_METH_GET);

$request->setHeaders(array(
  'authorization' => 'Basic {yourEncodedClientKeyAndClientSecret}',
  'api-key' => '{yourAPIKey}'
));

try {
  $response = $request->send();

  echo $response->getBody();
} catch (HttpException $ex) {
  echo $ex;
}
?>
import http.client

conn = http.client.HTTPSConnection("mb-api.mindbodyonline.com")

headers = {
    'api-key': "{yourAPIKey}",
    'authorization': "Basic {yourEncodedClientKeyAndClientSecret}"
    }

conn.request("GET", "/api/v1/users/{uniqueUserId}/purchases/{purchaseId}", headers=headers)

res = conn.getresponse()
data = res.read()

print(data.decode("utf-8"))
require 'uri'
require 'net/http'

url = URI("https://mb-api.mindbodyonline.com/affiliate/api/v1/users/{uniqueUserId}/purchases/{purchaseId}")

http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
http.verify_mode = OpenSSL::SSL::VERIFY_NONE

request = Net::HTTP::Get.new(url)
request["api-key"] = '{yourAPIKey}'
request["authorization"] = 'Basic {yourEncodedClientKeyAndClientSecret}'

response = http.request(request)
puts response.read_body

https://mb-api.mindbodyonline.com/affiliate/api/v1/users/{uniqueUserId}/purchases/{purchaseId}

This endpoint finds and returns the single purchase associated with the passed ID.

Pagination

This endpoint does not support pagination.

Best Practices

  • Use when you want to get purchase details when you already have the purchase’s ID.

Headers

Name Type Description
API-Key string Your API key.
Authorization string Your encoded client key and client secret.
See Authentication and Security for help creating this string.

URL Parameters

Name Type Description
uniqueUserId string The user’s unique identifier within your system. This ID must:
  • Be between 1 and 64 characters in length
  • Contain only:
    • alphanumeric characters (lowercase)
    • _ (underscores)
    • - (hyphens)
    • ~ (tildes)
    • . (periods)
purchaseId string Returns the single purchase associated with this globally unique identifier (a GUID). Do not use query parameters when fetching this resource.

Response

Partial example of response content structure:

{
    "id": "6b93a69e-4547-412d-a00e-700b91691bd4",
    "passId": "598a6916-7876-406e-9537-db6e4825f9a2",
    ...
}

This response object is the same as the objects contained in the items field in the GET Purchases response . View that documentation for detailed information about the response object’s fields.

Errors

Example Error:

{
    "error": {
        "errorCode": "14040040",
        "errorType": "purchaseNotFound",
        "message": "Purchase not found."
    }
}

This endpoint may return the errors listed below. We recommend that you catch and handle each error for an optimal, frictionless user experience. We also recommend attempting to reproduce each error during your development and test process in order to ensure that your back-end application is handling them correctly.

HTTP Status Code errorCode errorType Description
401 14010001 missingAPIKeyHeader An API-Key header was not included in the request.
401 14010002 missingAuthorizationHeader An Authorization header was not included in the request.
404 14040010 userNotFound The uniqueUserId passed as a URL Parameter was not found.
404 14040040 purchaseNotFound The purchaseId passed as a URL Parameter was not found.
429 14290001 tooManyRequests You have exceeded the rate limit for this endpoint.
429 14290002 dailyRequestLimitExceeded You have exceeded the daily request limit for this endpoint.

LiabilityWaivers

Liability Waivers

Some subscribers require new users to agree to a liability release or liability waiver. If the selected location’s subscriber.hasLiabilityWaiver is true, we recommend that you collect the user’s signature for the subscriber’s configured liability waiver text. This reduces friction in the user’s initial interaction with the business by collecting their signature prior to their arrival at the location.

GET

curl -X GET \
-H "API-Key: {yourAPIKey}" \
-H "Authorization: Basic {yourEncodedClientKeyAndClientSecret}" \
-A "{yourAppName}" \
"https://mb-api.mindbodyonline.com/affiliate/api/v1/locations/{locationId}/liabilitywaivers
var client = new RestClient("https://mb-api.mindbodyonline.com/affiliate/api/v1/locations/{locationId}/liabilitywaivers");
var request = new RestRequest(Method.GET);
request.AddHeader("authorization", "Basic {yourEncodedClientKeyAndClientSecret}");
request.AddHeader("api-key", "{yourAPIKey}");
IRestResponse response = client.Execute(request);
<?php
$request = new HttpRequest();
$request->setUrl('https://mb-api.mindbodyonline.com/affiliate/api/v1/locations/{locationId}/liabilitywaivers');
$request->setMethod(HTTP_METH_GET);

$request->setHeaders(array(
  'authorization' => 'Basic {yourEncodedClientKeyAndClientSecret}',
  'api-key' => '{yourAPIKey}'
));
try {
  $response = $request->send();
  echo $response->getBody();
} catch (HttpException $ex) {
  echo $ex;
}
?>
import http.client
conn = http.client.HTTPSConnection("mb-api.mindbodyonline.com")
headers = {
    'api-key': "{yourAPIKey}",
    'authorization': "Basic {yourEncodedClientKeyAndClientSecret}"
    }
conn.request("GET", "/api/v1/locations/{locationId}/liabilitywaivers", headers=headers)
res = conn.getresponse()
data = res.read()
print(data.decode("utf-8"))
require 'uri'
require 'net/http'
url = URI("https://mb-api.mindbodyonline.com/affiliate/api/v1/locations/{locationId}/liabilitywaivers")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
request = Net::HTTP::Get.new(url)
request["api-key"] = '{yourAPIKey}'
request["authorization"] = 'Basic {yourEncodedClientKeyAndClientSecret}'
response = http.request(request)
puts response.read_body

https://mb-api.mindbodyonline.com/affiliate/api/v1/locations/{locationId}/liabilitywaivers

This endpoint pulls a subscriber’s liability waiver text.

Best Practices

  • Use after calling POST Booking if the location where the user booked has a liability waiver.
  • Use to present a sign-able liability waiver to the end-user.

Headers

Name Type Description
API-Key string Your API key.
Authorization string Your encoded client key and client secret.
See Authentication and Security for help creating this string.

URL Parameters

Name Type Description
locationId number The globally unique ID of a location that belongs to the subscriber from which you are pulling a liability wavier.

Response

HTTP Status Code: 200 OK

{
  "location": {
    "id": 13540,
    "name": "ACME Yoga",
    "subscriber": {
      "id": 1354158,
      "name": "ACME Yoga"
    },
    "olsonTimeZone": "America/Los_Angeles"
  },
  "liabilityWaiverText": "ACME Yoga is not responsible for any damage done to your body on our premises.",
  "liabilityWaiverHashedText": "21A951F270098C71D8C127EC57B31FDA811B37E64ABF28DD1906F84159C73D64"
}
Name Type Description
location object Contains information about the location you passed in the request URL.
location.id integer The location’s globally unique ID.
location.name string The location’s name.
location.subscriber object Contains information about the subscriber to whom the location and liability waiver belong.
location.subscriber.id integer The subscriber’s globally unique ID.
location.subscriber.name string The subscriber’s name.
location.olsonTimeZone string The location’s time zone in Olson format (e.g., "America/Los_Angeles"). Possible time zones.
location.liabilityWaiverText string The liability waiver text for the associated subscriber. This string may contain HTML.
location.liabilityWaiverHashedText string A hash of the liabilityWaiverText. You can compare these values to quickly identify if a change has been made in the liability waiver text.

Errors

Example Error:

{
    "error": {
        "errorCode": "14040003",
        "errorType": "liabilityWaiverNotFound",
        "message": "This business has not yet created a liability waiver that can be signed online."
    }
}

This endpoint may return the errors listed below. We recommend that you catch and handle each error for an optimal, frictionless user experience. We also recommend attempting to reproduce each error during your development and test process in order to ensure that your back-end application is handling them correctly.

HTTP Status Code errorCode errorType Description
401 14010001 missingAPIKeyHeader An API-Key header was not included in the request.
401 14010002 missingAuthorizationHeader An Authorization header was not included in the request.
404 14040001 locationNotFound The locationId passed as a URL Parameter was not found.
404 14040003 liabilityWaiverNotFound The subscriber has not yet configured their liability waiver text.
429 14290001 tooManyRequests You have exceeded the rate limit for this endpoint.
429 14290002 dailyRequestLimitExceeded You have exceeded the daily request limit for this endpoint.

POST

curl -X POST \
  -H 'api-key: {yourAPIKey}' \
  -H 'authorization: Basic {yourEncodedClientKeyAndClientSecret}' \
  -H 'content-type: application/json' \
  -A "{yourAppName}" \
  -d '{
          "bookingId": "f5405d87-46a0-4b48-a384-e26159e130d6",
          "liabilityWaiverHashedText": "21A951F270098C71D8C127EC57B31FDA811B37E64ABF28DD1906F84159C73D64",
          "pngBase64UserSignaturePicture": "{base64EncodedPngImageByteArray}"
      }' \
  "https://mb-api.mindbodyonline.com/affiliate/api/v1/signedliabilitywaivers"
var client = new RestClient("https://mb-api.mindbodyonline.com/affiliate/api/v1/signedliabilitywaivers");
var request = new RestRequest(Method.POST);
request.AddHeader("content-type", "application/json");
request.AddHeader("authorization", "Basic {yourEncodedClientKeyAndClientSecret}");
request.AddHeader("api-key", "{yourAPIKey}");
request.AddParameter("application/json", "{\n\t\"bookingId\": \"f5405d87-46a0-4b48-a384-e26159e130d6\",\n\t\"liabilityWaiverHashedText\": \"21A951F270098C71D8C127EC57B31FDA811B37E64ABF28DD1906F84159C73D64\",\n\t\"pngBase64UserSignaturePicture\": \"{base64EncodedPngImageByteArray}\"\n}", ParameterType.RequestBody);
IRestResponse response = client.Execute(request);
<?php

$request = new HttpRequest();
$request->setUrl('https://mb-api.mindbodyonline.com/affiliate/api/v1/signedliabilitywaivers');
$request->setMethod(HTTP_METH_POST);

$request->setHeaders(array(
  'content-type' => 'application/json',
  'authorization' => 'Basic {yourEncodedClientKeyAndClientSecret}',
  'api-key' => '{yourAPIKey}'
));

$request->setBody('{
  "bookingId": "f5405d87-46a0-4b48-a384-e26159e130d6",
  "liabilityWaiverHashedText": "21A951F270098C71D8C127EC57B31FDA811B37E64ABF28DD1906F84159C73D64",
  "pngBase64UserSignaturePicture": "{base64EncodedPngImageByteArray}"
}');

try {
  $response = $request->send();

  echo $response->getBody();
} catch (HttpException $ex) {
  echo $ex;
}
?>
import http.client

conn = http.client.HTTPSConnection("mb-api.mindbodyonline.com")

payload = "{\n\t\"bookingId\": \"f5405d87-46a0-4b48-a384-e26159e130d6\",\n\t\"liabilityWaiverHashedText\": \"21A951F270098C71D8C127EC57B31FDA811B37E64ABF28DD1906F84159C73D64\",\n\t\"pngBase64UserSignaturePicture\": \"{base64EncodedPngImageByteArray}\"\n}"

headers = {
    'api-key': "{yourAPIKey}",
    'authorization': "Basic {yourEncodedClientKeyAndClientSecret}",
    'content-type': "application/json"
    }

conn.request("POST", "/affiliate/api/v1/signedliabilitywaivers", payload, headers)

res = conn.getresponse()
data = res.read()

print(data.decode("utf-8"))
require 'uri'
require 'net/http'

url = URI("https://mb-api.mindbodyonline.com/affiliate/api/v1/signedliabilitywaivers")

http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
http.verify_mode = OpenSSL::SSL::VERIFY_NONE

request = Net::HTTP::Post.new(url)
request["api-key"] = '{yourAPIKey}'
request["authorization"] = 'Basic {yourEncodedClientKeyAndClientSecret}'
request["content-type"] = 'application/json'
request.body = "{\n\t\"bookingId\": \"f5405d87-46a0-4b48-a384-e26159e130d6\",\n\t\"liabilityWaiverHashedText\": \"21A951F270098C71D8C127EC57B31FDA811B37E64ABF28DD1906F84159C73D64\",\n\t\"pngBase64UserSignaturePicture\": \"{base64EncodedPngImageByteArray}\"\n}"

response = http.request(request)
puts response.read_body

https://mb-api.mindbodyonline.com/affiliate/api/v1/signedliabilitywaivers

This endpoint uploads an image of the user’s signature, verifying that they have signed the location’s liability waiver. Once signed for one location, a waiver is valid for all locations that belong to the same subscriber.

Best Practices

  • Use after completing a booking. Uploading a user’s waiver signature can speed up their front-desk experience at the subscriber.
  • Use after calling POST Booking.
  • Use after calling GET LiabilityWaivers if you collected the user’s signature and need to save it to the subscriber.

Headers

Name Type Description
API-Key string Your API key.
Authorization string Your encoded client key and client secret.
See Authentication and Security for help creating this string.
Content-Type string Defines the format of the request so the API can correctly process it. application/json is the only accepted value at this time.

Request Body

{
    "bookingId": "f5405d87-46a0-4b48-a384-e26159e130d6",
    "liabilityWaiverHashedText": "21A951F270098C71D8C127EC57B31FDA811B37E64ABF28DD1906F84159C73D64",
    "pngBase64UserSignaturePicture": "{base64EncodedPngImageByteArray}"
}
Name Type Description
bookingId Guid The ID of the booking that belongs to the subscriber for which you are submitting a liability waiver signature.
liabilityWaiverHashedText string A hash of the liability waiver’s text.
pngBase64UserSignaturePicture string A PNG image of the user’s signature, converted to bytes and Base64 encoded.

Response

HTTP Status Code: 200 OK

{
    "status": "Liability Waiver has been signed successfully."
}

This is the only success status message currently returned from this endpoint.

Errors

Example Error:

{
    "error": {
        "errorCode": "14000005",
        "errorType": "invalidValue",
        "message": "The following value is invalid: liabilityWaiverHashedText."
    }
}

This endpoint may return the errors listed below. We recommend that you catch and handle each error for an optimal, frictionless user experience. We also recommend attempting to reproduce each error during your development and test process in order to ensure that your back-end application is handling them correctly.

HTTP Status Code errorCode errorType Description
400 14000003 missingRequiredProperty Returned when one of the required request properties is null or empty. Check the error’s message property to find the name of the invalid property.
400 14000005 invalidValue Returned when a request body property:
  • Has violated its minimum acceptable value
  • Has violated its maximum acceptable value
  • Is required but is missing
  • Is used with other incompatible request properties
Check the error’s message property to find the name of the invalid property. This error may be returned if the liability waiver’s text has change since last you retrieved its hash.
400 14040020 bookingNotFound The bookingId passed in the request body was not found.
401 14010001 missingAPIKeyHeader An API-Key header was not included in the request.
401 14010002 missingAuthorizationHeader An Authorization header was not included in the request.
409 14090030 subscriberUserDataMismatch Returned when the user’s account at the subscriber has been altered in a way that prevents actions being taken on that user.
415 14150002 unsupportedMediaType A Content-Type header was passed with a value other than application/json. This is the only accepted content type for this endpoint.
429 14290001 tooManyRequests You have exceeded the rate limit for this endpoint.
429 14290002 dailyRequestLimitExceeded You have exceeded the daily request limit for this endpoint.
500 15009998 criticalServerErrorLiabilityWaivers The user’s signature was successfully stored at the subscriber, but something prevented us from tracking this information against your Affiliate account. Please move your integration out of a live environment and contact Mindbody developer support immediately.
;