Yoplanning API

Introduction

The Yoplanning API is organized around REST. Our API has predictable, resource-oriented URLs, and uses HTTP response codes to indicate API errors and success.
We use built-in HTTP features, like HTTP authentication and HTTP verbs, which are understood by off-the-shelf HTTP clients.
JSON is returned by all API methods.

Authentication

First of all, you must request an API token to be able to query the Yoplanning API. To do so, please contact us.
Once you have your token in hands, you can start working with the API. All API methods requires authentication.
We use standard token-based authentication system. To authenticate, just provide your API token on the header of each request like so:
Authorization: Token 4804c2cb4d87a13146d4de029f407c82149f2ada
Be carefull : the space between "Token" and the token is important.

Here is a full exemple using curl
curl -H "Content-Type: application/json" https://yoplanning.pro/api/v3/teams/5a90332e-568f-4980-9859-88a984844a4d/clients/8d23503e-041e-4180-98d1-641183bc5ead -H 'Authorization: Token 4804c2cb4d87a13146d4de029f407c82149f2ada'

If you don't provide a token or if the token is invalid, the API will respond with a 401 HTTP code (Unauthorized) and will give you a "details" field in the response JSON to help you understand the problem.
{"detail":"Invalid token."} or {"detail":"Authentication credentials were not provided."}

Permissions

When you have requested your API token, you have been granted specific permissions on a certain set of teams.
This means you probably cannot use all the API methods listed below.
If you call the Yoplanning API without permissions (for instance, you don't have permission to create session-groups on the team), the API will respond with a 403 HTTP code (Forbidden) with the following details.
{"detail":"You do not have permission to perform this action."}

Overview

The team is the most fondamental concept in yoplanning (which is a collaborative tool).
Almost all methods takes a teamId parameter in the url. That means all the actions are relative to a team.
Lots of methods requires a "pk" parameter in the url. This is the unique identifier for the resource you are trying to retrieve / create / update / delete.
Yoplanning uses UUID (version 4) as unique identifier for all resources.
Each time you want to create a resource, you will give the resource ID in the url. We will use this ID as the unique identifier of the resource.
That means you don't have to retrieve anything from the response.

For many methods, you can use PUT and PATCH. Both of them will create a resource or update it if it exists.
Using PUT, you have to give at least all the required fields.
Using PATCH, you can provide only the fields you want to update. If the resource already exist, only those fields will be updated. Like for PUT, if the resource doesn't exist, we will try to create it.
In that case, we will need all the required fields to do so. Otherwise, an error will occurs.
PATCH doesn't use internal validation so you will probably get a 500 http code (Internal server error) if you give wrong data.

Some methods use nested resources. For exemple, when you create a session, you can give a list of clients (participants).
For PUT and PATCH : You can ommit the nested resources (meaning don't give the field at all). That means you don't want to change anything on that field.
For exemple : when updating a sesssion, if you don't give the JSON property "clients", nothing will change on the session's clients.
However, if you give that field, we will update it with the given value.
That means, for exemple, if you give "clients" : [] in the sessions API method, all the clients will be removed from the session.
If you don't give "clients" property at all, nothing will change on the session's clients.

Pagination

For all API methods that provides a large list of resources, pagination is used.
That means all the results will not be given in a single request. You will have to perform several request to get the full list of resources.
You can see that as "pages in a book".
For each request, you can use query parameters (query string) in the url to navigate through the result.
Two query parameters can be provided : "offset" and "limit". offset => the starting point where you want to retrieve data (you can see this as a cursor). Default : 0 limit => the number of result you want to retrieve per request. Default : 100 (which is also the maximum value) Exemple : curl -H "Content-Type: application/json" -L "https://yoplanning.pro/api/v3/teams/5a90332e-568f-4980-9859-88a984844a4d/clients?offset=20&limit=2" -H 'Authorization: Token 4804c2cb4d87a13146d4de029f407c82149f2ada'


Here is an example of response for methods using pagination: { "count":53, "next":"https://yoplanning.pro/api/v3/teams/5a90332e-568f-4980-9859-88a984844a4d/clients?limit=2&offset=22", "previous":"https://yoplanning.pro/api/v3/teams/5a90332e-568f-4980-9859-88a984844a4d/clients?limit=2&offset=18", "results":[ { "first_name" : "Jack", "last_name" : "Ichan", "email" : "jack.ichan@gmail.com", "phone_number" : "+32684952685", "birth_date" : "1975-05-22", "language" : "fr", "note" : "Pretty cool client :)", "street" : "rue du phare", "city" : "Brest", "postal_code" : "29200", "state" : null, "country" : "FR" "id":"7db70b5c-5175-4ba8-b471-78006940b79c" }, { "first_name":"Loic", "last_name":"Lepoivre", "email":null, "phone_number":null, "birth_date":null, "language":null, "note":null, "street":null, "city":null, "postal_code":null, "state":null, "country":null, "id":"669763dd-3bad-47a9-ac37-02d915a90bbe" } ] } count => the total number of resources next => the url to use to retrieve the next page. If there is no next page, the value will be null. previous => the url to use to retrieve the previous page. If there is no previous page, the value will be null. results => the list of resources

Filters

In most cases, you can also filter the results by adding query parameters to the request.
The following request will give you only the clients with first name "Norbert". https://yoplanning.pro/api/v3/teams/5a90332e-568f-4980-9859-88a984844a4d/clients?offset=20&limit=2&first_name=Norbert
For date fields, you can filter using __lt (lowet than), __gt (greater than), __lte (lowet than equal), __gte (greater than equal).
The following request will give you only the clients with birth date greater than 1995-01-25. https://yoplanning.pro/api/v3/teams/5a90332e-568f-4980-9859-88a984844a4d/clients?offset=20&limit=2&birh_date__gt=1995-01-25
Please see the endpoint documentation to know which fields can be used as filters

Webhooks

Webhooks are also called "web callback" or "HTTP push API". It is a notification system.
You can subscribe to webhooks in order to be notified when a particular event occurs (for exemple, each time a client is created).
In order to subscribe, please contact us.

How does it work?
When subscribing to weekhooks, you will give us a callback url and tell us on which event and for which team you want to be notified.
When this event is fired on this team, we will send a POST request on the callback url with data formated like this : { "resource": { "id": "8d23503e-041e-4180-98d1-641183bc5ead", "type": "client" }, "link": "https://yoplanning.pro/api/v3/teams/5a90332e-568f-4980-9859-88a984844a4d/clients/8d23503e-041e-4180-98d1-641183bc5ead", "event": "updated" }
resource.id => the resource that have been created / modified / deleted resource.type => the type of resource (client / session / member, etc...) link => the url to use to retrieve the resource. event => the event fired
When you receive a POST request on the callback url, you will be able to send a GET request to the Yoplanning API using the "link" field to retrieve the corresponding ressource.
Don't forget to add authentication information when calling the API!

api/v3

Retrieve all the teams for which you have permissions. This method uses pagination (see Pagination section of this documentation)

Team object

{
    "id" : "9b8ffa11-cd17-4896-9656-d9e458191fed", 
    "name" : "Awesome ski school",
    "currency" : "EUR",
    "email" : "info@awesome-ski-school.com",
    "address" : "229 Route de Thônes, 74230 Manigod, France", 
    "phone_number" : "0450809040", 
    "country" : "FR",
    "language" : "fr"
}

The Team is the most fondamental concept in Yoplanning (collaborative tool).
A team is an organisation which have its own staffs, clients, sessions, orders, etc...
A team id is basically required for all other API call.

{
    "name" : "Awesome ski school", [R]
    "currency" : "EUR", [R]
    "email" : "info@awesome-ski-school.com",
    "address" : "229 Route de Thônes, 74230 Manigod, France", 
    "phone_number" : "0450809040", 
    "country" : "FR",
    "language" : "fr"
}

A staff is a person who is responsible for activities (instructor). This API allows you to add a staff to the team.
You cannot give any staff id in the url. You will have to retrieve the Id in the JSON returned.
This API is used only to add staff (POST only). Adding a new staff will trigger an invitation email to be sent. The new staff will be able to login to Yoplanning.

{
    "person" :  
        {
            "first_name" : "Mark", [R]
            "last_name" : "Knopfler", [R]
            "birth_date" : "1955-02-27",
            "phone_number" : "+4155489867",
            "lang" : "en", 
            "email" : "mark.knopfler@gmail.com", 
        },
    "role" : "ADMIN" [R]
}

roles : "ADMIN", "PLANNER", "VIEWER" or "NORIGHTS"

This API allows you to update a staff in the team.
The ID is given in the url (as for most of API method). This API is used only to update staff.

{
    "person" :  
        {
            "first_name" : "Mark", [R]
            "last_name" : "Knopfler", [R]
            "birth_date" : "1955-02-27",
            "phone_number" : "+4155489867",
            "lang" : "en", 
            "email" : "mark.knopfler@gmail.com", 
        },
    "role" : "ADMIN" [R]
}


Retrieve all the team clients. This method uses pagination (see Pagination section of this documentation)

Filters allowed :

first_name, last_name, email, phone_number, birth_date, language, note, street, city, postal_code, country, 
last_update (date)

Client object

{  
   "id":"7db70b5c-5175-4ba8-b471-78006940b79c",
   "first_name" : "Jack",
   "last_name" : "Ichan", 
   "email" : "jack.ichan@gmail.com",
   "phone_number" : "+32684952685", 
   "birth_date" : "1975-05-22", 
   "language" : "fr",
   "note" : "Pretty cool client :)",
   "street" : "rue du phare",
   "city" : "Brest", 
   "postal_code" : "29200",
   "state" : null,
   "country" : "FR"
   "last_update":"2018-02-23T12:53:03.455"
}

A client is an person that can participate to some sessions.

{
    "first_name" : "Jack", [R]
    "last_name" : "Ichan", [R]
    "email" : "jack.ichan@gmail.com",
    "phone_number" : "+32684952685", 
    "birth_date" : "1975-05-22", 
    "language" : "fr",
    "note" : "Pretty cool client :)",
    "street" : "rue du phare",
    "city" : "Brest", 
    "postal_code" : "29200",
    "state" : null,
    "country" : "FR",
}

A session group represent sessions that are sold together. Exemple : a week of ski course, a 3 days trail, etc... Note that participants are still assign in each session indepedently.


{
    "price" : 155.45, [R]
    "sessions" : [
        {
            "activity_place" : "229 Route de Thônes, 74230 Manigod, France",
            "meeting_point_en" : "On the slopes", 
            "meeting_point_fr" : "Sur les pistes",
            "start_date" : "2018-05-21 14:00", [R]
            "end_date" : "2018-05-21 17:00", [R]
            "max_participant" : 5, 
            "note" : "hard one",
            "timezone" : "Europe/Paris",
            "title_fr" : "Cours de snowboard", [R title_fr or title_en must be given]
            "title_en" : "Snowboard lesson",
            "description_fr" : "pistes rouges et noires",
            "description_en" : "Red and black slopes",
            "staffs": ["d111a1e0-9126-4e5c-adcb-bbc5e7bbe729", "350b14f3-2cd7-4587-b4d2-ba340e489e21"],
            "clients: [
                {
                    "id" : "c54fd942-a8cc-45db-ac5c-34a05fb5e37b",
                    "first_name" : "Jack",
                    "last_name" : "Ichan", 
                    "email" : "jack.ichan@gmail.com",
                    "phone_number" : "+32684952685", 
                    "birth_date" : "1975-05-22", 
                    "language" : "fr",
                    "note" : "Pretty cool client :)",
                    "street" : "rue du phare",
                    "city" : "Brest", 
                    "postal_code" : "29200",
                    "state" : null,
                    "country" : "FR"
                },
                {
                    "id" : "2a70887f-ff4c-4c7d-829e-3c8cb12d9127",
                    "first_name" : "Sam",
                    "last_name" : "Gamji", 
                },
                {
                    "id" : "ef544375-56bd-45ad-990c-185fb5c1ef42",
                }
            ]
        },
        {
            "activity_place" : "229 Route de Thônes, 74230 Manigod, France",
            "meeting_point_en" : "On the slopes", 
            "meeting_point_fr" : "Sur les pistes",
            "start_date" : "2018-06-21 08:00",
            "end_date" : "2018-06-21 10:00", 
            "max_participant" : 5, 
            "note" : "hard one",
            "timezone" : "Europe/Paris",
            "title_fr" : "Cours de snowboard",
            "title_en" : "Snowboard lesson",
            "description_fr" : "pistes rouges et noires",
            "description_en" : "Red and black slopes",
            "staffs": ["d111a1e0-9126-4e5c-adcb-bbc5e7bbe729"],
            "clients: [
                {
                    "id" : "c54fd942-a8cc-45db-ac5c-34a05fb5e37b",
                    "first_name" : "Jack",
                    "last_name" : "Ichan", 
                    "email" : "jack.ichan@gmail.com",
                    "phone_number" : "+32684952685", 
                    "birth_date" : "1975-05-22", 
                    "language" : "fr",
                    "note" : "Pretty cool client :)",
                    "street" : "rue du phare",
                    "city" : "Brest", 
                    "postal_code" : "29200",
                    "state" : null,
                    "country" : "FR"
                },
                {
                    "id" : "ef544375-56bd-45ad-990c-185fb5c1ef42",
                }
            ]
        }
    ]

}


A session is an activity scheduled at a precise date and time.
Some staffs and clients will meet to enjoy the activity. Note : the session start and end must occur on the the same day. If you want to schedule an activity lasting for several days, see session-groups

{
    "activity_place" : "229 Route de Thônes, 74230 Manigod, France",
    "meeting_point_en" : "On the slopes", 
    "meeting_point_fr" : "Sur les pistes",
    "start_date" : "2018-05-21 14:00", [R]
    "end_date" : "2018-05-21 17:00", [R]
    "max_participant" : 5, 
    "note" : "hard one",
    "timezone" : "Europe/Paris",
    "title_fr" : "Cours de snowboard", [R title_fr or title_en must be given]
    "title_en" : "Snowboard lesson",
    "description_fr" : "pistes rouges et noires",
    "description_en" : "Red and black slopes",
    "staffs": ["d111a1e0-9126-4e5c-adcb-bbc5e7bbe729", "350b14f3-2cd7-4587-b4d2-ba340e489e21"],
    "clients: [
        {
            "id" : "c54fd942-a8cc-45db-ac5c-34a05fb5e37b", [R]
            "first_name" : "Jack", [R]
            "last_name" : "Ichan", [R]
            "email" : "jack.ichan@gmail.com",
            "phone_number" : "+32684952685", 
            "birth_date" : "1975-05-22", 
            "language" : "fr",
            "note" : "Pretty cool client :)",
            "street" : "rue du phare",
            "city" : "Brest", 
            "postal_code" : "29200",
            "state" : null,
            "country" : "FR"
        },
        {
            "id" : "2a70887f-ff4c-4c7d-829e-3c8cb12d9127",
            "first_name" : "Sam",
            "last_name" : "Gamji", 
        },
        {
            "id" : "ef544375-56bd-45ad-990c-185fb5c1ef42",
        }
    ]
}

An unavailability is a period of time where a staff cannot be assign to any session.
Nobody will be able to book this staff (including other teams he or she may have)

{
    'start_date' : "2018-04-12 11:30", [R]
    'end_date' : "2018-06-12 18:00", [R]
    'reason' : "Holidays", 
    'teacher_id' : "b572098c-9280-46b4-a9f8-ede575241427" [R]
}

Retrieve all the team orders. This method uses pagination (see Pagination section of this documentation)

Filters allowed :

last_update (date)

Order object

{
    "creation_date" : "2018-01-23",
    "external_reference" : "MY-ID-501861",  // 
    "note" : "This order is a bit special, it is for my brother ;)",
    "global_price" : 48.20,  // This is the order price
    "items" : [
        {
            "label" : "Ski one hour, children price",
            "price" : {
                "amount" : 51.20,
                "label" : "Children price"
            },
            "client" : {
                "id" : "c54fd942-a8cc-45db-ac5c-34a05fb5e37b",
                "first_name" : "Jack",
                "last_name" : "Ichan",
                "email" : "jack.ichan@gmail.com",
                "phone_number" : "+32684952685", 
                "birth_date" : "1975-05-22", 
                "language" : "fr",
                "note" : "Pretty cool client :)",
                "street" : "rue du phare",
                "city" : "Brest", 
                "postal_code" : "29200",
                "state" : null,
                "country" : "FR"
            },
            "session_group_id" : {
                "id" : "25fdeb4b-8f0e-4c4c-aaaa-bdb580f76691"
                "sessions":[  
                  {  
                     "activity_place":"229 Route de Thônes, 74230 Manigod, France",
                     "meeting_point_en":"On the slopes",
                     "meeting_point_fr":"Sur les pistes",
                     "start_date":"2018-05-21 14:00",
                     "end_date":"2018-05-21 17:00",
                     "max_participant":5,
                     "note":"hard one",
                     "timezone":"Europe/Paris",
                     "title_fr":"Cours de snowboard",
                     "title_en":"Snowboard lesson",
                     "description_fr":"pistes rouges et noires",
                     "description_en":"Red and black slopes",
                     "staffs":[  
                        {  
                            "first_name":"Alain",
                            "last_name":"Deloin",
                            "id":"a7164c68-8d6c-4362-807d-cda27b94a41b"
                        }
                      ]
                  },
                  {  
                     "activity_place":"229 Route de Thônes, 74230 Manigod, France",
                     "meeting_point_en":"On the slopes",
                     "meeting_point_fr":"Sur les pistes",
                     "start_date":"2018-06-21 08:00",
                     "end_date":"2018-06-21 10:00",
                     "max_participant":5,
                     "note":"hard one",
                     "timezone":"Europe/Paris",
                     "title_fr":"Cours de snowboard",
                     "title_en":"Snowboard lesson",
                     "description_fr":"pistes rouges et noires",
                     "description_en":"Red and black slopes",
                     "staffs":[]
                  }
               ]
            }
        }
    ],
    "payments" : [
        {
            "id" : "3c01bf53-9656-458d-8c50-33a117f23f83",
            "client" : {
                "id" : "b61c053c-2bc1-46ec-bc55-59e72038a2ac",
                "first_name" : "Jack",
                "last_name" : "Ichan",
                "email" : "jack.ichan@gmail.com",
                "phone_number" : "+32684952685", 
                "birth_date" : "1975-05-22", 
                "language" : "fr",
                "note" : "Pretty cool client :)",
                "street" : "rue du phare",
                "city" : "Brest", 
                "postal_code" : "29200",
                "state" : null,
                "country" : "FR"
            },
            "amount" : 40.15,
            "method" : "credit_card",  // credit_card, cash...
            "card_brand" : "visa",  // mastercard, visa...
            "status" : "payed",  // payed or pending
            "source" : "widget",  // office, payment_link, widget...
            "plateform" : "payline",  // stripe, paypal, payline, postfinance...
            "operator_id" : "77875548-7b93-47be-a773-ee9c581bb3ad"  // the staff who receive the paiement in case of office payment


        }
    ]
}

An order is a set of items bought by someone at a given price.

{
    "creation_date" : "2011-05-26 16:00",
    "external_reference" : "MY-ID-501861",
    "note" : "This order is a bit special, it is for my brother ;)",
    "global_price" : 48.20, // This is the order price
    "items" : [
        {
            "label" : "Ski one hour, children price",
            "price" : {
                "amount" : 51.20, [R]
                "label" : "Children price"
            },
            "client" : {
                "id" : "c54fd942-a8cc-45db-ac5c-34a05fb5e37b", [R]
                "first_name" : "Jack", [R]
                "last_name" : "Ichan", [R]
                "email" : "jack.ichan@gmail.com",
                "phone_number" : "+32684952685", 
                "birth_date" : "1975-05-22", 
                "language" : "fr",
                "note" : "Pretty cool client :)",
                "street" : "rue du phare",
                "city" : "Brest", 
                "postal_code" : "29200",
                "state" : null,
                "country" : "FR"
            },
            "session_group_id" : {
                "id" : "25fdeb4b-8f0e-4c4c-aaaa-bdb580f76691" [R]
            }
        }

    ],
    "payments" : [
        {
            "id" : "3c01bf53-9656-458d-8c50-33a117f23f83", [R]
            "creation_date" : "2011-05-05 16:00",
            "client" : {
                "id" : "b61c053c-2bc1-46ec-bc55-59e72038a2ac", [R]
                "first_name" : "Jack", [R]
                "last_name" : "Ichan", [R]
                "email" : "jack.ichan@gmail.com",
                "phone_number" : "+32684952685", 
                "birth_date" : "1975-05-22", 
                "language" : "fr",
                "note" : "Pretty cool client :)",
                "street" : "rue du phare",
                "city" : "Brest", 
                "postal_code" : "29200",
                "state" : null,
                "country" : "FR"
            },
            "amount" : 40.15, [R]
            "method" : "credit_card",
            "card_brand" : "visa",
            "status" : "payed",
            "source" : "widget",
            "plateform" : "payline",
            "operator_id" : "77875548-7b93-47be-a773-ee9c581bb3ad"


        }
    ]
}

An item is a something (most commonly a session-group ) bought for a particular client at a given price. An item is linked to an order.

{
    "price" : {
        "amount" : 51.20, [R]
        "label" : "Children price",
    },
    "client" : {
        "id" : "7db70b5c-5175-4ba8-b471-78006940b79c", [R]
        "first_name" : "Jack", [R]
        "last_name" : "Ichan", [R]
        "email" : "jack.ichan@gmail.com",
        "phone_number" : "+32684952685", 
        "birth_date" : "1975-05-22", 
        "language" : "fr",
        "note" : "Pretty cool client :)",
        "street" : "rue du phare",
        "city" : "Brest", 
        "postal_code" : "29200",
        "state" : null,
        "country" : "FR"
    },
    "session_group_id" : "25fdeb4b-8f0e-4c4c-aaaa-bdb580f76691"
}