---
# System prepended metadata

title: Ativiti API Document

---

# Ativiti API Document

#### Base URL - https://dev.ativiti.ch/
#### Postman Collection - [Ativiti PROD.postman_collection.json](https://drive.google.com/file/d/1irhBeZikuKjFbzUeWahke4kMOnOJqonz/view?usp=sharing)


# Login
- [x]  DONE
## Correct credentials
Request: /api/v1/login_check
Method: GET|POST
Body:

~~~ json
{
	"username": "user@email.com",
	"password": "password"
}
~~~
Response:

~~~ json
{
    "statusCode": 200, //this field can be obtained for response.status.. why to make more data flow ?
    "data": {
        "token": "eyJ0eXAiOiJKV1QiLCJhbG....."
    }
}
~~~
## Bad credentials
Request: /api/v1/login_check
Method: GET|POST
Body:

~~~ json
{
	"username": "user@email.com",
	"password": "WRONGpassword"
}
~~~
Response:

~~~ json
{
    "statusCode": 401,
    "data": {
        "error": "Bad credentials"
    }
}
~~~

## Facebook Login
- [ ]  DONE
Expected Facebook Login Flow:

Request: /api/v1/login_check/facebook
Method: POST
Body
~~~json
{
    "access_token":"............................"
}
~~~
Access token is obtained once user signup with facebook popup and that contain information like firstname, lastname,
email, profile_picture...
This access token should be submitted to facebook graph api to extract information

Response 
For success: 
~~~json
{
    "statusCode": 200,
    "data": {
        "token": "..."
    }
}
~~~
For Facebook Graph not return any information
~~~json
{
    "statusCode": 400,
    "data": {
        "error": "Invalid access token"
    }
}
~~~
For user not registered
~~~json
{
    "statusCode": 400,
    "data": {
        "error": "Information not found in database, please signup"
    }
}
~~~

---

# Sign up
## Sending signup form
- [x]  DONE
### Ex1. Email Signup

#### Step 1:
Request: /api/v1/signup/email
method: POST
Body:

~~~ json
{
    "email": "test@email.com",
    "is_adult": true,
    "subscribe_newsletter": true,
    "first_name": "Alice",
    "last_name": "Bob",
    "password": "******",
    "area": "region.geneva|region.lausanne"
}
~~~
Response:

~~~ json
{
    "statusCode": 201,
    "data": {
        "message": "Check email for 4 digit code"
    }
}
~~~


#### Step 2:
Request: /api/v1/signup/validate
method: POST
Body:

~~~ json
{
    "email": "smth@gmail.com",
    "four_digit_code": 1234
}
~~~
Response:

For Correct Code
~~~ json
{
    "statusCode": 200, //this field can be obtained for response.status..
    "data": {
        "message": "Code verified. User activated and logged in.",
        "token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ...."
    }
}
~~~

For Invalid Code
~~~ json
{
    "statusCode": 400,
    "data": {
        "message": "Invalid code.",
        "attempts_left": 2
    }
}
~~~

~~~ json
{
    "statusCode": 400,
    "data": {
        "message": "You entered the code incorrectly 3 times. The new code has been sent to the email"
    }
}
~~~

For an already active user
~~~ json
{
    "statusCode": 404,
    "data": {
        "error": "User with provided email already activated"
    }
}
~~~



### Ex2. Facebook Signup
- [ ]  DONE
Expected Facebook Signup Flow:

Request: /api/v1/signup/facebook
Method: POST
Body
~~~json
{
    "is_adult": true,
    "subscribe_newsletter": true,
    "access_token":"..........................."
}
~~~
Access token is obtained once user signup with facebook popup and that contain information like firstname, lastname,
email, profile_picture...
This access token should be submitted to facebook graph api to extract information

Response 
For success: 
~~~json
{
    "statusCode": 200,
    "data": {
        "message": "Signup successful"
    }
}
~~~
For Facebook Graph not return any information
~~~json
{
    "statusCode": 400,
    "data": {
        "error": "Invalid access token"
    }
}
~~~
For user already registered
~~~json
{
    "statusCode": 400,
    "data": {
        "error": "Already registered, please login"
    }
}
~~~

---
# Change Password
## Change password from settings page
- [x]  DONE

Request: /api/v1/security/update_password
method: POST
### Headers:
**Authorization**: `Bearer eyJ0eXAiOiJKV1QiLC...`

Body:
~~~ json
{
    "current_password":"44zHHN8!!TSXhU^HDwHV",
    "new_password":"%@*2&ZxeFMFwC&A2Pf^8"
}
~~~
Response:
### Ex1. Successfully changed
~~~ json
{
    "statusCode": 200,
    "data": {
        "message": "Password updated."
    }
}
~~~
### Ex2. Error in changing password
~~~ json
{
    "statusCode": 403,
    "data": {
        "error": "Error message"
    }
}
~~~
# Reset Password
## Sending reset code
- [x]  DONE
### Ex1. Correct email

#### Step 1:
Request: /api/v1/security/reset
method: POST
Body:

~~~ json
{
	"email": "test@email.com"
}
~~~
Response:

~~~ json
{
    "statusCode": 200,
    "data": {
        "message": "Check email for 4 digit code"
    }
}
~~~

#### Step 2:
Request: /api/v1/security/validate
method: POST
Body:

~~~ json
{
	"four_digit_code": "1234"
}
~~~
***Correct Format***
~~~ json
{
    "email": "smth@gmail.com",
	"four_digit_code": 1234
}
~~~

Response:

For Correct Code
~~~ json
{
    "statusCode": 200,
    "data": {
        "message": "Code verified.",
        "change_password_token": "sometoken",
        "token_ttl_seconds": "900"
    }
}
~~~

For Invalid Code
~~~ json
{
    "statusCode": 400,
    "data": {
        "message": "Invalid code."
        "attempts_left": 10
    }
}
~~~

~~~ json
{
    "statusCode": 400,
    "data": {
        "message": "You entered the code incorrectly 10 times. The code has been canceled. Resend the code."
    }
}
~~~

~~~ json
{
    "statusCode": 404,
    "data": {
        "error": "User with provided email not request the token"
    }
}
~~~

~~~ json
{
    "statusCode": 400,
    "data": {
        "message": "The request code is expired. Please request a new one.",
        "token_ttl_seconds": 900
    }
}
~~~

#### Step 3:
Request: /api/v1/security/recover_password
method: POST
Body:

~~~ json
{
    "token": "sometoken",
    "new_password": "******"
}
~~~

Response:

~~~ json
{
    "statusCode": 200,
    "data": {
        "message": "Password updated."
    }
}
~~~
For Invalid Code
~~~ json
{
    "statusCode": 400,
    "data": {
        "message": "The change password token is expired.",
        "token_ttl_seconds": 900
    }
}

{
    "statusCode": 400,
    "data": {
        "message": "Password is too short"
    }
}
~~~

### Ex2. Repeated request when the delay time has not expired:
Request:

~~~ json
{
	"email": "test@email.com"
}
~~~
Response:

~~~ json
{
    "statusCode": 400,
    "data": {
        "message": "The password reset link was sent to the email earlier",
        "seconds_left": 7089
    }
}
~~~
### Ex3. Not valid email:
Request:

~~~ json
{
	"email": "not_valid_email"
}
~~~
Response:

~~~ json
{
    "statusCode": 400,
    "data": {
        "error": "Parameter \"email\" of value \"not_valid_email\" violated a constraint \"Cette valeur n'est pas une adresse email valide.\""
    }
}
~~~
### Ex4. User not found:
Request:

~~~ json
{
	"email": "some_other@email.com"
}
~~~
Response

~~~ json
{
    "statusCode": 404,
    "data": {
        "error": "User with provided email not found"
    }
}
~~~


---

# Home
## Home View
- [x]  DONE
### Default data loaded with homepage 

**all_categories** section in the response shall include all the available categories and sub-categories in the backend for use in the search filter.

Request: /api/v1/home
method: GET
Body:

~~~ json
{
}
~~~
Response:

~~~ json
{
    "statusCode": 200,
    "data": {
        "has_upcoming_events": null,
        "category": [
            {
                "id": 1,
                "title": "Sport",
                "count": 9,
                "icon": "https://dev.ativiti.ch/uploads/category/sport.jpg"
            },
            {
                "id": 6,
                "title": "Dancing",
                "count": 9,
                "icon": "https://dev.ativiti.ch/uploads/category/dancing.jpg"
            },
            {
                "id": 11,
                "title": "Game",
                "count": 21,
                "icon": "https://dev.ativiti.ch/uploads/category/game.jpg"
            },
            {
                "id": 14,
                "title": "Business",
                "count": 9,
                "icon": "https://dev.ativiti.ch/uploads/category/business.jpg"
            }
        ],
        "all_categories": {
            "Sport": [
                "Chessy"
            ],
            "Dancing": [
                "Pasodoble"
            ],
            "Game": [
                "Laser tag"
            ],
            "Business": [
                "Seminar",
                "Conference",
                "Workshop",
                "Chessy",
                "Paintball",
                "Samba",
                "Zumba",
                "Tango",
                "Kicker (Table football)",
                "Darts",
                "Swimming",
                "Judo"
            ]
        },
        "discover": [
            {
                "id": 14,
                "title": "Dance",
                "venue": "1400, Yverdon-les-Bains",
                "address": "Route de Lausanne, Pâquis-Nations, Швейцария, 1400, Yverdon-les-Bains, Швейцария",
                "image": "https://provideradmin-dev.ativiti.ch/uploads/gallery/5f11aa2e52400.png"
            }
        ],
        "keepfit": [
            {
                "id": 14,
                "title": "Dance",
                "venue": "1400, Yverdon-les-Bains",
                "address": "Route de Lausanne, Pâquis-Nations, Швейцария, 1400, Yverdon-les-Bains, Швейцария",
                "image": "https://provideradmin-dev.ativiti.ch/uploads/gallery/5f11aa2e52400.png"
            }
        ],
        "recreational": [
            {
                "id": 14,
                "title": "Dance",
                "venue": "1400, Yverdon-les-Bains",
                "address": "Route de Lausanne, Pâquis-Nations, Швейцария, 1400, Yverdon-les-Bains, Швейцария",
                "image": "https://provideradmin-dev.ativiti.ch/uploads/gallery/5f11aa2e52400.png"
            }
        ],
        "inspiring": [
            {
                "id": 14,
                "title": "Dance",
                "venue": "1400, Yverdon-les-Bains",
                "address": "Route de Lausanne, Pâquis-Nations, Швейцария, 1400, Yverdon-les-Bains, Швейцария",
                "image": "https://provideradmin-dev.ativiti.ch/uploads/gallery/5f11aa2e52400.png"
            }
        ]
    }
}
~~~
___
## Last minute activities (fig no: 8.16)
### Ex1. Get event sessions for listing based on user location for all categories
- [x]  DONE
Here the user is geolocated so the search is performed on a radius of 2km from the current position.

Request: /api/v1/event_list
method: POST
Body:

~~~ json
{
    //"area": "",
    "distance_limit": "2",
    "date": "",
    //"start_time": "",
    //"stop_time": "",
    "current_lat": "27.717245",
    "current_long": "85.323959",
    "type": "sessions",
    "categories": [], 
    "sorting": "time"
}
~~~
Response:

~~~ json
{
    "statusCode": 200,
    "data": {
        "date": "17-06-2019",
        "type": "sessions",
        "sorting": "time",
        "active_booking_count": 3,
        "event_count": 15,
        "events": [
            {
                "id": 1,
                "start_time": "12:00:00",
                "stop_time": "12:45:00",
                "title": "Cardio Sculpt",
                "venue": "Bowland Lausanne-Flon",
                "address": "1003, Lausanne",
                "is_favourite": false,
                "booking_status": "booked", 
                "distance_from_location": "0.3 km",
                "event_lat": "27.717245",
                "event_long": "85.323959"
            },
            {
                "id": 2,
                "start_time": "12:00:00",
                "stop_time": "12:45:00",
                "title": "Bowling",
                "venue": "Bowland Lausanne-Flon",
                "address": "1003, Lausanne",
                "is_favourite": true,
                "booking_status": "waiting list", 
                "distance_from_location": "0.2 km",
                "event_lat": "27.717245",
                "event_long": "85.323959"
            }
        ]
    }
}
~~~

### Ex2. Get free entries for listing based on user location and time
- [x]  DONE
Here we added values to the date and time parameters. This will limit the search to specific date and search for events that begin and within the time range selected by user.

Request: /api/v1/event_list
method: POST
Body:

~~~ json
{
    "area": "",
    "distance_limit": "2",
    "date": "12-06-2019",
    "start_time": "12:00:00 UTC + 5:45",
    "stop_time": "16:00:00 UTC + 5:45",
    "current_lat": "27.717245",
    "current_long": "85.323959",
    "type": "free_entries",
    "categories": [],
    "sorting": "time"
}
~~~
Response:

~~~ json
{
    "statusCode": 200,
    "data": {
        "date": "17-06-2019",
        "type": "free_entries",
        "sorting": "time",
        "active_booking_count": 3,
        "event_count": 15,
        "events": [
            {
                "id": 1,
                "start_time": "12:00:00",
                "stop_time": "12:45:00",
                "title": "Cardio Sculpt",
                "venue": "Bowland Lausanne-Flon",
                "address": "1003, Lausanne",
                "is_favourite": false,
                "booking_status": "booking request", 
                "distance_from_location": "0.3 km",
                "event_lat": "27.717245",
                "event_long": "85.323959"
            },
            {
                "id": 2,
                "start_time": "12:00:00",
                "stop_time": "12:45:00",
                "title": "Bowling",
                "venue": "Bowland Lausanne-Flon",
                "address": "1003, Lausanne",
                "is_favourite": true,
                "booking_status": "booked", 
                "distance_from_location": "0.2 km",
                "event_lat": "27.717245",
                "event_long": "85.323959"
            }
        ]
    }
}
~~~

### Ex3. No events found based on user location and time
- [ ]  DONE
Here distance limit is also set to 10 km. So the event venue should be within 10km from the current location of the user.

Request: /api/v1/event_list
method: POST
Body:

~~~ json
{
    "area": "",
    "distance_limit": 400.0,
    "date": "",
    "start_time": "",
    "stop_time": "",
    "current_lat": "8.539865",
    "current_long": "47.329282",
    "type": "free_entries",
    "categories": [],
    "sorting": "time"
}
~~~
Response:

~~~ json
{
    "statusCode": 200,
    "data": {
        "date": "2020-09-02",
        "type": "free_entries",
        "sorting": "time",
        "active_user_booking_count": 0,
        "event_count": 1,
        "events": [
            {
                "id": 186,
                "event_date": "02-09-2020",
                "start_time": "19:00:00",
                "stop_time": "21:00:00",
                "title": "Tomfoolery",
                "venue": "Route de Lausanne, Pâquis-Nations, Швейцария, 1400, Yverdon-les-Bains, Швейцария",
                "address": "1400, Yverdon-les-Bains",
                "is_favourite": false,
                "booking_status": "",
                "distance_from_location": "136.4 km",
                "event_lat": "6.6468802",
                "event_long": "46.7632507"
            }
        ]
    }
}
~~~
___

## Explore activities (fig no: 8.15)

### Ex1. Get event sessions for listing based on user location
- [x]  DONE
Here the sorting is set to distance instead of time. 

Request: /api/v1/event_list
method: POST
Body:

~~~ json
{
    "area": "",
    "distance_limit": "2",
    "date": "",
    "start_time": "",
    "stop_time": "",
    "current_lat": "27.717245",
    "current_long": "85.323959",
    "type": "sessions",
    "categories": [],
    "sorting": "distance"
}
~~~
Response:

~~~ json
{
    "statusCode": 200,
    "data": {
        "date": "17-06-2019",
        "type": "sessions",
        "sorting": "distance",
        "active_booking_count": 3,
        "event_count": 15,
        "events": [
            {
                "id": 1,
                "start_time": "12:00:00",
                "stop_time": "12:45:00",
                "title": "Cardio Sculpt",
                "venue": "Bowland Lausanne-Flon",
                "address": "1003, Lausanne",
                "is_favourite": false,
                "booking_status": "booked", 
                "distance_from_location": "0.3 km",
                "event_lat": "27.717245",
                "event_long": "85.323959"
            },
            {
                "id": 2,
                "start_time": "12:00:00",
                "stop_time": "12:45:00",
                "title": "Bowling",
                "venue": "Bowland Lausanne-Flon",
                "address": "1003, Lausanne",
                "is_favourite": true,
                "booking_status": "booked", 
                "distance_from_location": "0.2 km",
                "event_lat": "27.717245",
                "event_long": "85.323959"
            }
        ]
    }
}
~~~
* P.S. Also has "type"="free_entries" (Ref: Ex2. of previous section)

___

## Category filter and Search 

### Ex1. Get event sessions for listing based on user location, time and category selection (fig no: 8.18 - 8.22)
- [x]  DONE
Uses the same request pattern as above sections with categories selected. In this example all events in **sports** category that fall under the location and time filters will be selected. Also we consider that the user is **not geo-located** in this session and search by **area**.

Request: /api/v1/event_list
method: POST
Body:

~~~ json
{
	"area": "geneva",
	"distance_limit": "",
	"date": "",
	"start_time": "",
	"stop_time": "",
	"current_lat": "",
	"current_long": "",
	"type": "sessions",
	"categories": [{
		"sports": []
	}],
	"sorting": "time"
}
~~~
Response:

~~~ json
{
    "statusCode": 200,
    "data": {
        "date": "17-06-2019",
        "type": "sessions",
        "sorting": "time",
        "active_booking_count": 3,
        "event_count": 15,
        "events": [
            {
                "id": 1,
                "start_time": "12:00:00",
                "stop_time": "12:45:00",
                "title": "Cardio Sculpt",
                "venue": "Bowland Lausanne-Flon",
                "address": "1003, Lausanne",
                "is_favourite": false,
                "booking_status": "booked", 
                "distance_from_location": "0.3 km",
                "event_lat": "27.717245",
                "event_long": "85.323959"
            },
            {
                "id": 2,
                "start_time": "12:00:00",
                "stop_time": "12:45:00",
                "title": "Bowling",
                "venue": "Bowland Lausanne-Flon",
                "address": "1003, Lausanne",
                "is_favourite": true,
                "booking_status": "declined", 
                "distance_from_location": "0.2 km",
                "event_lat": "27.717245",
                "event_long": "85.323959"
            }
        ]
    }
}
~~~


### Ex2. Get event sessions based on search filter (fig no: 8.07)
- [x]  DONE
In this example all events in **culture** category and **cardio sculpt** or **yoga** events from **sports** category, that fall under the location and time filters will be selected. Here we consider that the user is geo-located and hence search by the distance_limit from current location.

Request: /api/v1/event_list
method: POST
Body:

~~~ json
{
	"area": "geneva",
	"distance_limit": "10",
	"date": "",
	"start_time": "",
	"stop_time": "",
	"current_lat": "27.717245",
	"current_long": "85.323959",
	"type": "sessions",
	"categories": [{
		"sports": [
			"cardio sculpt",
			"yoga"
		],
		"culture": []
	}],
	"sorting": "time"
}
~~~
Response:

~~~ json
{
    "statusCode": 200,
    "data": {
        "date": "17-06-2019",
        "type": "sessions",
        "sorting": "time",
        "active_booking_count": 1,
        "event_count": 15,
        "events": [
            {
                "id": 1,
                "start_time": "12:00:00",
                "stop_time": "12:45:00",
                "title": "Cardio Sculpt",
                "venue": "Bowland Lausanne-Flon",
                "address": "1003, Lausanne",
                "is_favourite": false,
                "booking_status": "booked", 
                "distance_from_location": "0.3 km",
                "event_lat": "27.717245",
                "event_long": "85.323959"
            },
            {
                "id": 2,
                "start_time": "12:00:00",
                "stop_time": "12:45:00",
                "title": "Bowling",
                "venue": "Bowland Lausanne-Flon",
                "address": "1003, Lausanne",
                "is_favourite": true,
                "booking_status": "cancelled", 
                "distance_from_location": "0.2 km",
                "event_lat": "27.717245",
                "event_long": "85.323959"
            }
        ]
    }
}
~~~

___
# Agenda
## Upcoming Events (fig no: 11.01)
- [x]  DONE
![](https://i.imgur.com/1EpOK0V.png)


### Ex1. Get event details for listing based on user booking status
Request: /api/v1/agenda
method: POST
Body:

~~~ json
{
    "type": "upcoming",
    "sorting": "time"
}
~~~
Response:

~~~ json
{
    "statusCode": 200,
    "data": {
        "date": "17-06-2019",
        "type": "upcoming",
        "sorting": "time",
        "active_booking_count": 3,
        "event_count": 15,
        "events": [
            {
                "id": 1,
                "event_date": "21-06-2019"
                "start_time": "12:00:00",
                "stop_time": "12:45:00",
                "title": "Cardio Sculpt",
                "venue": "Bowland Lausanne-Flon",
                "address": "1003, Lausanne",
                "is_favourite": false,
                "booking_status": "booked", 
                "distance_from_location": "0.3 km",
                "event_lat": "27.717245",
                "event_long": "85.323959"
            },
            {
                "id": 2,
                "event_date": "21-06-2019"
                "start_time": "12:00:00",
                "stop_time": "12:45:00",
                "title": "Bowling",
                "venue": "Bowland Lausanne-Flon",
                "address": "1003, Lausanne",
                "is_favourite": true,
                "booking_status": "waiting list", 
                "distance_from_location": "0.2 km",
                "event_lat": "27.717245",
                "event_long": "85.323959"
            }
        ],
        "notifications": []
    }
}
~~~

### Ex2. Notification from provider (fig no: 11.01)
- [x]  DONE
![](https://i.imgur.com/aNbdDVT.png)

In this case, the new event date does not conflict with any other confirmed bookings of the user. The user can either **accept** or **decline** the change in schedule. 

Request: /api/v1/agenda
method: POST
Body:


~~~ json
{
    "type": "upcoming",
    "sorting": "time"
}
~~~
Response:

~~~ json
{
    "statusCode": 200,
    "data": {
        "date": "17-06-2019",
        "type": "upcoming",
        "sorting": "time",
        "active_booking_count": 3,
        "event_count": 15,
        "events": [],
        "notifications": [{
            "events": [{
                "id": 1,
                "old_event_date": "21-06-2019"
                "old_start_time": "12:00:00",
                "old_stop_time": "12:45:00",
                "new_event_date": "23-06-2019"
                "new_start_time": "12:00:00",
                "new_stop_time": "12:45:00",
                "title": "Cardio Sculpt",
                "venue": "Bowland Lausanne-Flon",
                "address": "1003, Lausanne",
                "is_favourite": false,
                "distance_from_location": "0.3 km",
                "event_lat": "27.717245",
                "event_long": "85.323959"
            }]
        }]
    }
}
~~~

#### Case 1: 
- [x]  DONE
**User accepts the new time for the event**

Request: /api/v1/agenda/sessionTimeUpdate
method: POST
Body:


~~~ json
{
    "event_id": 1,
    "booking": "accept",
    "new_event_date": "02-09-2020",
    "new_start_time": "12:00:00"
}
~~~
Response:

~~~ json
{
    "statusCode": 200,
    "data": {
        "date": "17-06-2019",
        "type": "upcoming",
        "sorting": "time",
        "event_count": 15,
        "events": [{
                "id": 1,
                "event_date": "21-06-2019"
                "start_time": "12:00:00",
                "stop_time": "12:45:00",
                "title": "Cardio Sculpt",
                "venue": "Bowland Lausanne-Flon",
                "address": "1003, Lausanne",
                "is_favourite": false,
                "booking_status": "booked", 
                "distance_from_location": "0.3 km",
                "event_lat": "27.717245",
                "event_long": "85.323959"
            }],
        
    }
}
~~~
Error:
~~~ json
{
    "statusCode": 400,
    "data": {
        "error": "The requested event does not
        exist"
    }
}
{
    "statusCode": 400,
    "data": {
        "error": "The requested bookingRequest does
        not exist"
    }
}
{
"statusCode": 200,
    "data": {
        "error": "changes are out of date, refresh
        page"
    }
}
~~~




#### Case 2: 
- [x]  DONE
**User declines the new time for the event**

Request: /api/v1/agenda/sessionTimeUpdate
method: POST
Body:


~~~ json
{
    "event_id": 1,
    "booking": "decline",
    "new_event_date": "23-06-2019",
    "new_start_time": "12:00:00"
}
~~~
Response:

~~~ json
{
    "statusCode": 200,
    "data": {
        "message": "Confirm to remove session"
    }
}
~~~

**On user confirmation**

Request: /api/v1/agenda/sessionTimeUpdate
method: POST
Body:


~~~ json
{
    "event_id": 1,
    "booking": "decline",
    "confirmation": true
}
~~~
Response:

~~~ json

{
    "statusCode": 200,
    "data": {
        "message": "Your session has been cancelled successfully."
    }
}
~~~

### Ex3. Cancelling session by client (fig no: 11.02,11.03)
- [x] DONE
![](http://i.imgur.com/NTY1sSH.png)
When a client wants to cancel a request and confirms, the
system itself will determine which status to assign and
whether cancellation is possible and return type of
cancellation in “reason” field (“сanceled” with a regular
cancellation and “late” with a late cancellation).

Request: /api/v1/agenda/cancel_session
method: POST
Body:
~~~ json 
{
    "requestId": 1
}
~~~
Response:
~~~ json 
{
    "statusCode": 200,
    "data": {
        "reason": "canceled"
    }
}
~~~
Error:

~~~ json
{
    "statusCode": 400,
    "data": {
        "message": "This request cannot be cancelled"
    }
}
~~~

### Ex4. History
- [x]  DONE
![](https://i.imgur.com/k3ePGZZ.png)




Request: /api/v1/agenda/cancel_reasons
method: POST
Body:

~~~ json
{
    "event_id": 1
}
~~~
Response:

~~~ json
If provider cancels the event
{
    "statusCode": 200,
    "data": {
        "cancellation_type": "cancelled_by_provider",
        "message": "Your session was cancelled by provider",
        "message_from_provider": "Here is message from provider"
    }
}

If Ativiti was forced to cancel the event
{
    "statusCode": 200,
    "data": {
        "cancellation_type": "force_cancellation",
        "message": "Your session was cancelled by Ativiti",
    }
}


If event date changed and conflicts with existing booking
{
    "statusCode": 200,
    "data": {
        "cancellation_type": "new_schedule_conflict",
        "message": "New session time conflicts with existing booking",
    }
}
~~~

## History Events (fig no: 11.13)
### Get event details for listing based on user history
- [x]  DONE
Request: /api/v1/agenda
method: POST
Body:

~~~ json
{
    "type": "history",
    "sorting": "time"
}
~~~
> Response:

~~~ json
{
    "statusCode": 200,
    "data": {
        "date": "17-06-2019",
        "type": "history",
        "sorting": "time",
        "event_count": 15,
        "events": [
            {
                "id": 1,
                "event_date": "21-06-2019"
                "start_time": "12:00:00",
                "stop_time": "12:45:00",
                "title": "Cardio Sculpt",
                "venue": "Bowland Lausanne-Flon",
                "address": "1003, Lausanne",
                "is_favourite": false,
                "booking_status": "completed", 
                "distance_from_location": "0.3 km",
                "event_lat": "27.717245",
                "event_long": "85.323959"
            },
            {
                "id": 2,
                "event_date": "21-06-2019"
                "start_time": "12:00:00",
                "stop_time": "12:45:00",
                "title": "Bowling",
                "venue": "Bowland Lausanne-Flon",
                "address": "1003, Lausanne",
                "is_favourite": true,
                "booking_status": "completed", 
                "distance_from_location": "0.2 km",
                "event_lat": "27.717245",
                "event_long": "85.323959"
            }
        ]
    }
}
~~~
### Remove history event (fir. 11.13)
- [x]  DONE
DONE
Request: /api/v1/agenda/remove_history_event
method: POST
Body:
~~~ json
{
    "eventId": 100,
}
~~~
Response:
~~~ json
{
    "statusCode": 200,
    "data": {
        "succeed": true,
        "message": "The event has been hidden",
        "errors": [reference link]
    }
}
~~~
Bad Response:
~~~ json
{
    "statusCode": 200,
    "data": {
        "succeed": false,
        "message": "",
        "errors": [
        "An error occurred during hiding the
        event"
        ]
    }
}
~~~

# ID Register
## User ID registration required for booking events. (fig no: 6.03, 7.01)
- [x]  DONE
### User Detail Submission

Here the the user adds name as in their ID and selects a picture fit for ID. The image data will be **base64 encoded** and the payload will be **json multipart/form-data**. After successful registration the user will get a **referral code** that can be shared with friends. Along with referral code the **number of times the referral has been redeemed** is also returned.

Request: /api/v1/id_register
method: POST
Body:

~~~ json
{
    "id_first_name": "upcoming",
    "id_last_name": "time",
    "acknowledge_is_true": true,
    "id_image": "c2Zhc2ZzYWRmc2RmYWFzZGY="
}
~~~
> Response:

~~~ json
{
    "statusCode": 200,
    "data": {
        "message": "Your ID information has been successfully saved.",
        "referral_code": "HG345JADE",
        "redeem_count": 0
    }
}
~~~
> Bad Response:

~~~ json
{
    "statusCode": 403,
    "error": "Error You did not give consent"
}
~~~
### State Get Request:
- [x]  DONE
Request: /api/v1/id_register/get_state
method: POST
Body:
~~~ json
{
}
~~~
Response:
~~~ json
{
    "statusCode": 200,
    "data": {
        "id_first_name": "OL1",
        "id_last_name": "SH2",
        "id_image": "c2Zhc2ZzYWRmc2RmYWFzZGY=",
        "acknowledge_is_true": true
    }
}
~~~

# Activity Page (fig no: 12.04)
## Get activity detail and user booking status with all information
- [x]  DONE

Request: /api/v1/activity_detail
method: POST
### Headers:
**Authorization**: `Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJ...`

Body:
~~~ json
{
    "activity_id":10, //Primary Key of the event_id
}
~~~
> Response:
### Ex1. Successfully fetched activity detail and booking status
~~~ json
{
    "statusCode": 200,
    "data": {
        "activity_id": 2,
        "event_date": "02-09-2020",
        "start_time": "08:00:00",
        "stop_time": "09:00:00",
        "title": "wfdsgdfg",
        "image_urls": [
            "/uploads/gallery/5f1a89ba6b38a.png"
        ],
        "venue": "Route de Lausanne, Pâquis-Nations, Швейцария, 1400, Yverdon-les-Bains, Швейцария",
        "address": "1400, Yverdon-les-Bains",
        "is_favourite": false,
        "booking_status": "reservation_period_expired",
        "is_free_entry": false,
        "distance_from_location": "0.0 km",
        "event_lat": "6.6468802",
        "event_long": "46.7632507",
        "social_share_link": "http://this-is-event-link.com",
        "description": "dfgdsfgsac aSCSac aC",
        "attendees_count": 0,
        "cancellation_deadline": "time expired",
        "difficulty_level": "For everyone",
        "conditions": "Min 0 people coming",
        "other_info": "",
        "other_sessions": [
            {
                "id": 18,
                "event_date": "02-09-2020",
                "start_time": "08:00:00",
                "booking_status": "available"
            },
            {
                "id": 3,
                "event_date": "03-09-2020",
                "start_time": "08:00:00",
                "booking_status": "available"
            },
            {
                "id": 4,
                "event_date": "04-09-2020",
                "start_time": "08:00:00",
                "booking_status": "available"
            },
            {
                "id": 19,
                "event_date": "04-09-2020",
                "start_time": "08:00:00",
                "booking_status": "available"
            },
            {
                "id": 5,
                "event_date": "05-09-2020",
                "start_time": "08:00:00",
                "booking_status": "available"
            },
            {
                "id": 6,
                "event_date": "06-09-2020",
                "start_time": "08:00:00",
                "booking_status": "available"
            },
            {
                "id": 7,
                "event_date": "07-09-2020",
                "start_time": "08:00:00",
                "booking_status": "available"
            },
            {
                "id": 20,
                "event_date": "07-09-2020",
                "start_time": "08:00:00",
                "booking_status": "available"
            },
            {
                "id": 8,
                "event_date": "08-09-2020",
                "start_time": "08:00:00",
                "booking_status": "available"
            },
            {
                "id": 9,
                "event_date": "09-09-2020",
                "start_time": "08:00:00",
                "booking_status": "available"
            },
            {
                "id": 21,
                "event_date": "09-09-2020",
                "start_time": "08:00:00",
                "booking_status": "available"
            },
            {
                "id": 10,
                "event_date": "11-09-2020",
                "start_time": "08:00:00",
                "booking_status": "available"
            },
            {
                "id": 22,
                "event_date": "11-09-2020",
                "start_time": "08:00:00",
                "booking_status": "available"
            }
        ],
        "amenities": []
    }
}
~~~
### Ex2. Error in fetching activity detail and user booking status
~~~ json
{
    "statusCode": 403,
    "data": {
        "error": "Error message"
    }
}
~~~

# Book Activity
## Book an activity when status is available

- [x]  DONE

Request: /api/v1/activity_book
method: POST
### Headers:
**Authorization**: `Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJ...`

Body:
~~~ json
{
    "activity_id":10, //Primary Key of the activity
    "number_of_friends":4
}
~~~
> Response:
### Ex1. Successfully booked activity. Returns attendees_list and all hidden data if any
~~~ json
{
    "statusCode": 200,
    "data": {
        "id": 10,
        "event_date": "21-06-2019"
        "start_time": "12:00:00",
        "stop_time": "12:45:00",
        "title": "Cardio Sculpt",
        "venue": "Bowland Lausanne-Flon",
        "address": "1003, Lausanne",
        "is_favourite": false,
        "booking_status": "booked",
        "is_free_entry": true
        "distance_from_location": "0.3 km",
        "event_lat": 27.717245,
        "event_long": 85.323959,
        "social_share_link": "http://this-is-event-link.com",
        "description": "This is description",
        "attendees_count": 32,
        "attendees_list": [
            {
                "profile_name": "Tom H.", // Firstname L. ; lastname initial only 
                "preview_img": "http://link-to-user-thumb.com"
            },
            {
                ...
            }
        ],
        "cancellation_deadline": "34 minutes", //Prepared string in backend
        "difficulty_level": "Intermediate",
        "conditions": "Min 3 people coming",
        "other_info": "This is something additional",
        "other_sessions": [ //list of 10 days including today
            {
                "id": 1,
                "event_date": "21-06-2019"
                "start_time": "12:00:00",
                "booking_status": "available", 
            
            },
            {
                "id": 2,
                "event_date": "21-07-2019"
                "start_time": "12:00:00",
                "booking_status": "waiting list", 
            
            }
        ],
        "amenities": [
            {
                "name": "Shower",
                "is_paid": true
            },
            {
                "name": "Changing room",
                "is_paid": false
            },
            {
                "name": "Coffee",
                "is_paid": true
            },
        ]       
        
    }
}
~~~

### Ex2. Booking failed due to user subscription status or session conflict
~~~ json
{
    "statusCode": 403,
    "data": {
        "failure_code": "session_coflict" // subscription_paused / no_pass / subscription_canceled
    }
}
~~~
# Membership
- [x] Done

## list of existing membership plans
- [x] Done
**Description**: Returns common information about
membership actions
* list of allowed actions;
* active subscription of current user (if exist);
* list of existing membership plans.
All actions require authorization header - see Login
block
### Headers:
**Authorization**: `Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJ...`
**Request**: /api/v1/membership
**method**: GET
**Body**: none

**Response**:
~~~ json
{
    "statusCode": 200,
    "data": {
        "succeed": true,
        "allowedActions": [
            "pause",
            "unsubscribe",
            "unpause",
            "re-subscribe"
        ],
        "activeSubscription": {
            "planId": 1,
            "active": true,
            "expireDate": {
                "date": "2020-05-26 14:18:51.000000",
                "timezone_type": 3,
                "timezone": "UTC"
            },
            "isPaused": false,
            "isCanceled": false
        },
        "planList": [
            {
                "planId": 1,
                "name": "Trial",
                "price_per_month": 7900,
                "currency": "chf"
            },
            {
                "planId": 3,
                "name": "Adventure",
                "price_per_month": 19900,
                "currency": "chf"
            }
        ]
    }
}
~~~

**Bad Response**: none

## Subscription Plan Info
### Headers:
**Authorization**: `Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJ...`
**Request**: /api/v1/membership/plan_info
**method**: POST
Params:
1. subscriptionPlan
required: required
type: integer
description: Membership plan ID to subscribe. Check
Membership section to see available plans
2. couponId
required: optional
type: string
default: null
description: Discount coupon that has to apply on
subscription. Use this param to get actual amount of
subscription plan
**Body**: example with existing card:
~~~ json
{
    "subscriptionPlan": 3
}
~~~
## Subscribe (fig. 5.07, 5.18)
- [x] Done

Description: Subscribe user to provided membership
plan
Request: api/v1/membership/subscribe
method: POST
Params:
1. subscriptionPlan
required: required
type: integer
description: Membership plan ID to subscribe. Check
Membership section to see available plans
2. stripeToken
required: optional
type: string
default: null
description: Provide this token if you need to add card
during susbcribing
3. cardId
required: optional
type: integer
default: null
description: Use this parameter if you need to pass
existing card as payment tool. See card list action to
get card IDs
4. couponId
required: optional
type: string
default: null
description: Discount coupon that has to apply on
subscription
5. agree
required: optional
type: boolean
values: true or false.
default: false
description: This flag means that an user accept with
T&C rules on subcription page

**Body**:
~~~ json
Body, example with existing card:
{
    "subscriptionPlan": 1,
    "cardId": 12
}
Body, example with stripe card token:
{
    "subscriptionPlan": 1,
    "stripeToken": "asdasfdajassda"
}
Success Response:
{
    "statusCode": 200,
    "data": {
        "succeed": true,
        "errors": [],
        "message": "Subscribed"
    }
}
Response without agree flag:
{
    "statusCode": 200,
    "data": {
        "succeed": false,
        "errors": [
        "You did not accept the agreement"
        ],
        "message": "You did not accept the
        agreement"
    }
}
Response without cardID or Stripe token:
{
    "statusCode": 403,
    "data": {
        "succeed": false,
        "message": "Payment info is required -
        provide stripe token of card ID"
        "errors": [
        "Payment info is required - provide
        stripe token of card ID"
        ]
    }
}
Response with incorrect membership plan ID:
{
    "statusCode": 403,
    "data": {
        "succeed": false,
        "message": "Plan does not exist"
        "errors": [
        "Plan does not exist"
        ]
    }
}
~~~
## Pause (fig. 18.73)
- [x] Done

Description: Sets the user’s active membership plan
on pause.
**Request**: api/v1/membership/pause
method: POST
**Params**:
1. confirm
required: optional
type: boolean
values: true or false.
default: false
description: Uses to get some data from the backend
to display it on confirm popup (see. Response for
confirm block). Skip this parameter to pause
membership

**Body**:
~~~ json
Body, example with “confirm” param:
{
    "confirm": "true"
}
Body, to pause membership
empty
Response for confirm: this example shows how to get an
amount of penalty fee
{
    "statusCode": 200,
    "data": {
        "succeed": true,
        "errors": [],
        "confirm": {
            "penaltyFee": 15
        },
        "message": "Info for confirm dialog"
    }
}
Response:
{
    "statusCode": 200,
    "data": {
        "succeed": true,
        "errors": [],
        "message": "Membership has been paused"
    }
}
Bad Response:
{
    "statusCode": 200,
    "data": {
        "succeed": false,
        "errors": [
        "An error occurred during activating membership"
        ],
        "message": "An error occurred during pausing membership"
    }
}
Bad Response 2:
{
    "statusCode": 403,
    "data": {
        "succeed": false,
        "errors": [
        "User does not exist or security token
        is not valid",
        "User does have active subscription"
        ]
    }
}
~~~
## UnPause (fig. 18.33)
- [x] Done
**Description**: Takes off the user’s membership plan from the pause.
**Request**: /api/v1/membership/unpause
**method**: POST
**Params**:
1. confirm
required: optional
type: boolean
values: true or false.
default: false
description: Uses to get some data from the backend
to display it on confirm popup (see. Response for
confirm block). Skip this parameter to unpause
membership
**Body**:
~~~ json
example with “confirm” param:
{
    "confirm": "true"
}

Body, to unpause membership
empty
Response for confirm:
there is no additional data for confirmation popup.
Response:
{
    "statusCode": 200,
    "data": {
        "succeed": true,
        "errors": [],
        "message": "Membership has been activated"
    }
}
Bad Response:
{
    "statusCode": 200,
    "data": {
        "succeed": false,
        "errors": [
        "An error occurred during activating
        membership"
        ],
        "message": "An error occurred during
        activating membership"
    }
}
Bad Response 2:
{
    "statusCode": 403,
    "data": {
        "succeed": false,
        "errors": [
        "User does not exist or security token
        is not valid",
        "User does have active subscription"
        ]
    }
}
~~~
## UnSubscribe (fig. 18.34, 18.35)
- [x] Done
**Description**: Cancel active membership.
**Request**: /api/v1/membership/unsubscribe
**method**: POST
**Params**:
1. confirm
required: optional
type: boolean
values: true or false.
default: false
description: Uses to get some data from the backend
to display it on confirmation popup (see. Response for
confirm block). Skip this parameter to cancel
membership
2. cancel_reason
required: optional
type: string
description: Reason of cancel subscription.
3. cancel_message
required: optional
type: string
description: Message of subscription canceling.

~~~ json
Body, example with “confirm” param:
{
    "confirm": "true"
}

Body, to cancel membership
empty
Response for confirm: this example shows how to get the
end date of current subscription
{
    "statusCode": 200,
    "data": {
        "succeed": true,
        "errors": [],
        "confirm": {
            "membershipExpireDate": "May 8, 2020"
        },
        "message": "Info for confirm dialog"
    }
}
Response:
{
    "statusCode": 200,
    "data": {
    "succeed": true,
    "errors": [],
    "message": "Membership has been canceled"
    }
}
Response 3 (we cannot cancel the “Trial” plan):
{
    "statusCode": 403,
    "data": {
        "succeed": false,
        "errors": [
        "This plan can not be canceled"
        ],
        "message": "This plan can not be canceled"
    }
}
Bad Response:
{
    "statusCode": 200,
    "data": {
        "succeed": false,
        "errors": [
        "An error occurred during canceling
        membership"
        ],
        "message": "An error occurred during
        canceling membership"
    }
}
Bad Response 2:
{
    "statusCode": 403,
    "data": {
        "succeed": false,
        "errors": [
        "User does not exist or security token
        is not valid",
        "User does have active subscription"
        ]
    }
}
~~~
## ReSubscribe (fig. 18.37
- [x] Done

**Description**: Re-activate canceled membership.
**Request**: /api/v1/membership/resubscribe
**method**: POST
**Params**:
1. confirm
required: optional
type: boolean
values: true or false.
default: false
description: Uses to get some data from the backend
to display it on confirmation popup (see. Response for
confirm block). Skip this parameter to re-activate
membership

~~~ json
Body, example with “confirm” param:
{
"confirm": "true",
}
Body, to cancel membership
empty
Response for confirm:
there is no additional data for confirmation popup.
Response:
{
    "statusCode": 200,
    "data": {
        "succeed": true,
        "errors": [],
        "message": "Membership has been activated"
    }
}
Response 2 (the current date is more than the expiration
date of subscription - an user needs to buy a new
subscription):
{
    "statusCode": 200,
    "data": {
        "succeed": false,
        "errors": [
        "Your membership is expired and you need to subscribe it again"
        ],
        "message": "Your membership is expired and you need to subscribe it again"
    }
}
Response 3 (we cannot cancel the “Trial” plan):
{
    "statusCode": 403,
    "data": {
        "succeed": false,
        "errors": [
        "This plan can not be re-activated"
        ],
        "message": "This plan can not be re-activated"
    }
}
Bad Response:
{
    "statusCode": 200,
    "data": {
        "succeed": false,
        "errors": [
        "An error occurred during activating membership"
        ],
        "message": "An error occurred during activating membership"
    }
}
Bad Response 2:
{
    "statusCode": 403,
    "data": {
        "succeed": false,
        "errors": [
        "User does not exist or security token
        is not valid",
        "User does have active subscription"
        ]
    }
}
~~~
# Coupons
- [x] Done
**Description**: Displays information about referral
coupon of user.
All actions require authorization header - see Login
block
**Request**: /api/v1/coupon
**method**: GET
**Params**: none
**Body**: empty
~~~ json
Success Response:
{
    "statusCode": 200,
    "data": {
        "succeed": true,
        "couponId": "ASDASDA",
        "redeemed": 4,
        "status": true // TRUE if coupon is redeemed
        less than 6 times else FALSE
    }
}
Bad Response: none
~~~
## Coupon check
- [x] Done
Description: Displays list of user cards
Request: /api/v1/coupon/check
method: POST
Params:
1. couponId
required: required
type: string
description: coupon
2. subscriptionPlan
required: required
type: integer
description: Membership plan ID to apply coupon.
Check Membership section to see available plans
**Body**: 
~~~ json
{
    "couponId": "7eoT1W31",
    "subscriptionPlan": 2
}
~~~
~~~ json
Success Response:
{
    "statusCode": 200,
    "data": {
    "valid": true,
    "coupon": {
    "id": "BMAjTqmD",
    "current_amount": 19900,
    "new_amount": 15920,
    "currency": "chf"
    }
    }
}
Bad Response:
{
    "statusCode": 200,
    "data": {
    "valid": false,
    "coupon": []
    }
}
Bad Response 2:
{
    "statusCode": 400,
    "data": {
        "succeed": false,
        "errors": [
        "Coupon ID or subscription plan ID is
        not correct"
        ]
    }
}
~~~
# Cards
- [x] Done
**Description**: Displays common information about payment card 
actions: allowed card actions, default card of user
All actions require authorization header - see Login
block
**Request**: /api/v1/card
**method**: GET
**Params**: none
**Body**: empty
Success Response:
~~~ json
{
    "statusCode": 200,
    "data": {
        "succeed": true,
        "allowedActions": [
        "card/list",
        "card/add",
        "card/delete",
        "card/set_default"
        ],
        "defaultCard": {
            "cardId": 12,
            "cardBand": "Visa",
            "lastFour": "4242"
        }
    }
}
Bad Response: none
~~~
## Card List (fig. 18.17)
- [x] Done
**Description**: Displays list of user cards
**Request**: /api/v1/card/list
**method**: GET
**Params**: none
**Body**: empty
**Success Response**:
~~~ json
{
    "statusCode": 200,
    "data": {
        "succeed": true,
        "cards": [
        {
            "cardId": 11,
            "cardBand": "Visa",
            "lastFour": "4242",
            "default": false
        },
        {
            "cardId": 12,
            "cardBand": "Visa",
            "lastFour": "4242",
            "default": true
        }
        ],
        "errors": [reference link]
    }
}
Bad Response:
none
~~~
## Card Add (fig. 18.13, 18.20)
- [x] Done
**Description**: Add new card in Stripe and the database
**Request**: /api/v1/card/add
**method**: POST
**Params**:
1. stripe_token
required: required
type: string
description: Stripe card token that comes from Stripe
side
2. set_card_default
required: optional
type: boolean
default: true
description: Makes a new card as default payment
card
**Body**:
~~~ json
{
    "stripe_token": "adsdasdasd",
    "set_card_default": true
}
~~~
**Success Response**:
~~~ json
{
    "statusCode": 200,
    "data": {
        "succeed": true,
        "message": "The card has been added",
        "card": [
        "cardId": 11,
        "cardBand": "Visa",
        "lastFour": "4242",
        "default": true
        ],
        "errors": [reference link]
    }
}
~~~
**Bad Response**:
~~~ json
{
    "statusCode": 200,
    "data": {
        "succeed": false,
        "message": "An error occurred during adding
        the card",
        "errors": [
        "An error occurred during adding the
        card"
        ]
    }
}
~~~
## Card Delete (fig. 18.26)
- [x] Done
Description: Delete card from Stripe and the
database
Request: /api/v1/card/delete
method: POST
Params:
1. cardId
required: required
type: integer
description: Card ID in the database - see card list
action
Body:
~~~ json
{
    "cardId": 11
}
Success Response:
{
    "statusCode": 200,
    "data": {
        "succeed": true,
        "message": "The card has been deleted",
        "errors": [reference link]
    }
}
Bad Response:
{
    "statusCode": 200,
    "data": {
        "succeed": false,
        "message": "An error occurred on card
        delete",
        "errors": [
        "An error occurred on card delete"
        ]
    }
}
Bad Response 2:
{
    "statusCode": 200,
    "data": {
        "succeed": false,
        "message": "The card was not found",
        "errors": [
        "The card was not found"
        ]
    }
}
Bad Response 3:
{
    "statusCode": 400,
    "data": {
        "succeed": false,
        "message": "Card ID is not valid",
        "errors": [
        "Card ID is not valid"
        ]
    }
}
~~~
## Set default (fig. 18.23)
- [x] Done
Description: Makes a card as default payment tool.
Request: /api/v1/card/set_default
method: POST
Params:
1. cardId
required: required
type: integer
description: Card ID in the database - see card list
action
~~~ json
Body:
{
    "cardId": 11
}
Success Response:
{
    "statusCode": 200,
    "data": {
        "succeed": true,
        "message": "The card has been updated",
        "errors": [reference link]
    }
}
Bad Response:
{
    "statusCode": 200,
    "data": {
        "succeed": false,
        "message": "An error occurred on card
        update",
        "errors": [
        "An error occurred on card update"
        ]
    }
}
Bad Response 2:
{
    "statusCode": 200,
    "data": {
        "succeed": false,
        "message": "The card was not found",
        "errors": [
        "The card was not found"
        ]
    }
}
Bad Response 3:
{
    "statusCode": 400,
    "data": {
        "succeed": false,
        "message": "Card ID is not valid",
        "errors": [
        "Card ID is not valid"
        ]
    }
}
~~~
# BUYING A PASS
- [x]  DONE
diagram Customer App wireframes_CLEAN VERSION v11 (fig no: 5.00)
![](http://i.imgur.com/1Og4eDN.png)

## Apply Coupon (fig no: 5.02)
- [x]  DONE
Request: /api/v1/subscribe/check_coupon
method: POST
Body:

~~~ json
{
	"couponId": "BMAjTqmD",
	"subscription_plan": "1" //PLAN_FREE = 0; PLAN_TRIAL = 1; PLAN_ADVENTURE = 3; PLAN_PENALTY = 99;
}
~~~
> Response:

~~~ json
{
    "statusCode": 200,
    "data": {
        "valid": true,
        "coupon": {
            "id": "BMAjTqmD",
            "current_amount": 19900,
            "new_amount": 15920,
            "currency": "chf"
        }
    }
}
~~~
> Bad Response:

~~~ json
{
    "statusCode": 200,
    "data": {
        "valid": false,
        "coupon": []
    }
}
~~~
## Edit my profiles (fig no: 5.04)
- [x]  DONE
Request: /api/v1/subscribe/edit_my_profile
method: POST
Body:

~~~ json
{
    "first_name": "Marco",
    "last_name": "Tamburrino",
    "email": "marco.t@gmail.com",
    "sex": "1",//1 = Male, 0 = female
    "date_of_birth": "1980-12-02",
    "address": "Dents de morci",
    "street": "Tambarrino",
    "city": "Munich",
    "zip_code": "007889",
    "country": "CH"
}
~~~
> Response:

~~~ json
{
    "statusCode": 200,
    "data": {
        "message": "Profiler updated successfully"
    }
}
~~~
> Bad Response:

~~~ json
{
    "statusCode": 400,
    "data": {
        "error": "Data is not valid"
    }
}
~~~
## Current subscription method (fig no: 5.18)
- [x]  DONE
Request: /api/v1/subscribe/current_subscription_method
method: POST

### Show default card
Body:

~~~ json
{
    "couponId": "BMAjTqmD",
    "subscription_plan": "1"
}
~~~
> Response:

~~~ json
{
    "statusCode": 200,
    "data": {
        "card": {
            "card_last_four": "4444",
            "card_band": "MasterCard",
            "card_expire_month": 4,
            "card_expire_year": 2022,
            "card_reference": "card_1GL3ofIyGRXowT46fF2EGJEV",
            "is_default_card": true
        },
        "subscription_start_date": "10/03/2020",
        "cancellation_period": "10 Days",
        "price_per_month": 19900,
        "discounted_price_per_month": 15920,
        "currency": "chf"
    }
}
~~~
> Bad Response:

~~~ json
{
    "statusCode": 403,
    "data": {
        "message": "Default card is absent"
    }
}
~~~
### Selected plan
Body:

~~~ json
{
    "couponId": "BMAjTqmD",
    "subscription_plan": "1",
    "agree": "true"
}
~~~
> Response:

~~~ json
{
    "statusCode": 200,
    "data": {
        "message": "Subscribed"
    }
}
~~~
> Bad Response:

~~~ json
{
    "statusCode": 400,
    "data": {
        "error": "The problem with the selected plan or with the stripe token"
    }
}
~~~

## Add subscription card (fig no: 5.07)
- [x]  DONE
Request: /api/v1/subscribe/add_subscription_card
method: POST

### The strip token is not transferred, and the coupon is optional
Body:

~~~ json
{
    "couponId": "BMAjTqmD",
    "subscription_plan": "1"
}
~~~
> Response:

~~~ json
{
    "statusCode": 200,
    "data": {
        "subscription_start_date": "10/03/2020",
        "cancellation_period": "10 Days",
        "price_per_month": 7900,
        "discounted_price_per_month": 6320,
        "currency": "chf"
    }
}
~~~
> Bad Response:

~~~ json
{
    "statusCode": 400,
    "data": {
        "error": "Notice: Undefined index"
    }
}
~~~
### The strip token, agree and subscription plan are transferred, and the coupon is optional
Body:

~~~ json
{
    "couponId": "BMAjTqmD",
    "subscription_plan": "1",
    "stripe_token": "tok_1GLBlBIyGRXowT46niPwn6L6",
    "agree": "true"
}
~~~
> Response:

~~~ json
{
    "statusCode": 200,
    "data": {
        "message": "Subscribed",
    }
}
~~~
> Bad Response 1:

~~~ json
{
    "statusCode": 400,
    "data": {
        "error": "The problem with the selected plan or with the stripe token"
    }
}
~~~
> Bad Response 2:

~~~ json
{
    "statusCode": 403,
    "data": {
        "error": "The problem with the selected plan or with the stripe token"
    }
}
~~~
# QR Code & Access Validation
- [x] Done
Request: /api/v1/qr_code/access_validation
Method: POST
Headers:
Authorization: Bearer eyJ0eXAiOiJKV1QiLC...
~~~ json
Body:
{
    "provider_id": "CH-59676"
}
Response:
{
    "statusCode": 200,
    "data": {
    "booking_id": 2,
    "ev_id": 370,
    "activity_name": "Activity 1 P1",
    "start_date": {
        "date": "2020-03-25 19:00:00.000000",
        "timezone_type": 3,
        "timezone": "Europe/Helsinki"
    },
    "start_time": {
        "date": "1970-01-01 19:00:00.000000",
        "timezone_type": 3,
        "timezone": "Europe/Helsinki"
    },
    "end_time": {
            "date": "1970-01-01 20:00:00.000000",
            "timezone_type": 3,
            "timezone": "Europe/Helsinki"
        },
        "venue_address": "Venue 1, 4, Sity, Country
        region",
        "attendance_validation": "2020-03-25
        18:18:34",
        "userId": 2,
        "first_name": "Marco",
        "last_name": "Tamburrino",
        "avatar": null,
        "provider_id": "CH-59676"
    }
}
~~~
# Favorites (diagram 9.0)
- [x] Done
## Favoritees Add
- [x] Done
Request: /api/v1/favourite/add
Method: POST
Headers:
Authorization: Bearer eyJ0eXAiOiJKV1QiLC...

~~~ json
Body:
{
    "favorite_id":432
}
Response:
{
    "statusCode": 200,
    "message": "Event - 432 added successfully."
}
Bad Response:
{
    "statusCode": 400,
    "data": {
        "error": "An exception occurred while"
    }
}
~~~

## Favoritees Remove
- [x] Done
Request: /api/v1/favourite/remove
Method: POST
Headers:
Authorization: Bearer eyJ0eXAiOiJKV1QiLC...
~~~ json
Body:
{
    "favorite_id":432
}
Response:
{
    "statusCode": 200,
    "message": "Event - 432 removed successfully."
}
Bad Response:
{
    "statusCode": 400,
    "data": {
        "error": "The requested favorite not found"
    }
}
~~~
## Favoritees List
- [x] Done
Request: /api/v1/favourite/list
Method: POST
Headers:
Authorization: Bearer eyJ0eXAiOiJKV1QiLC...
~~~ json
Body:
{
}
Response:
{
    "statusCode": 200,
    "data": [
    {
        "id": 420,
        "title": "Activity 1 P1",
        "venue": "Delphinstrasse, 12, 8008,Zürich, Switzerland",
        "address": "8008, Zürich",
        "image": [
            "https://website.ativiti.loc/uploads/gallery/5e4bd15133c32.jpg"
        ],
        "status": "active",
        "event_date": "28-05-2020",
        "start_time": "08:00:00",
        "stop_time": "09:00:00"
    }
    ]
}
Bad Response:
{
    "statusCode": 200,
    "message" => "Look like you don\'t have any
    favorite activities yet"
}
~~~
# Attendees (diagram 14.0)
- [x] Done
Request: /api/v1/attendance_list
Method: POST
Headers:
Authorization: Bearer eyJ0eXAiOiJKV1QiLC...
~~~ json
Body:
{
    "event_id": 426
}
Response:
{
    "statusCode": 200,
    "data": {
        "attendees": [
        {
        "avatar": "https://
        website.ativiti.loc/uploads/avatars/
        paintball_5f292b2d807a9.jpg",
        "full_name": "FirstShkurik L."
        },
        {
        "avatar": "https://
        website.ativiti.loc/uploads/avatars/
        samba_5f292bc8a2568.jpg",
        "full_name": "test a."
        }
        ],
        "attendeesCount": 2
    }
}
Response without subscription:
{
    "statusCode": 200,
    "data": {
        "message": [
        "Ativiti Members will join this session.",
        "Only subscribers can see attendees
        profiles"
        ],
        "attendeesCount": 2
    }
}
Response without bookings:
{
    "statusCode": 200,
    "data": {
        "message": [
        "Hu ho .. No attendees so far",
        "Be the first to join this session"
        ]
    }
}
~~~