Introduction

This is the API used by Lodge application for interacting with external APIs and with the database. It is a RESTful API containing routes for create/read/update/delete operations, as well as fetching data from APIs for currency and geolocation.

Unauthenticated routes:

Authenticated routes (JWT):

External APIs:


Authentication

Unauthenticated routes to check if user exists by email, log in or sign up.

Check if user exists

POST /auth/exists

{
	"email": "abc@domain.com"
}

Response

{
	"userExists": true
}

Log in

POST /auth/login

{
	"email": "abc@domain.com",
	"password": "pass"
}

Response

400 Bad Request
{
	"message": "Authentication failed",
	"user": false
}

{
	"token": "xxxxx.yyyyy.zzzzz"
}

Sign up

POST /auth/signup

{
	"email": "abc@domain.com",
	"password": "pass",
	"first_name": "John",
	"last_name": "Doe"
}

Response

HTTP status 200
{
	message: "Sign up successful"
}

Property

Unauthenticated routes to retrieve multiple properties, detailed properties, etc.

Fetch properties for landing page

Returns 8 (max) properties with prices converted to site currency (EUR).

GET /property/home

Response

[
    {
        "id": 1,
        "title": "Sea Voyager Villa",
        "geo": {
            "x": 40.62617383681707,
            "y": 14.498273742410621
        },
        "city": "Arienzo",
        "country": "IT",
        "rating": 5,
        "reviews_no": 1,
        "images_url_array": [
            "7cda38e2-1755945364513.jpg",
            "e3966213-1755945364898.jpg",
            "1d674704-1755945365041.jpg",
            "38f3d38c-1755945365202.jpg",
            "795b74b9-1755945365356.jpg"
        ],
        "price_night_local": "80.00",
        "local_currency": "EUR",
        "price_night_site": "80.00"
    },
    ...
]

Fetch property by id

Fetches all data available about property.

GET /property/id/1

Response

{
	"id": 47,
	"title": "The Great White Whale",
	"geo": {
		"x": 65.68361227990968,
		"y": -18.09346204916715
	},
	"city": "Akureyri",
	"country": "IS",
	"is_listed": true,
	"street": "Hafnarstræti",
	"street_no": "87",
	"description": "Soundproof rooms in the bay overlooking the ocean.",
	"guests": 2,
	"beds": 1,
	...
}

Fetch booked dates for year and month given property id

Fetches an array of pairs representing check-in and check-out for a given property id, month and year.

GET /property/booked?id=1&date=2025-08-01

Response

[
	{
		"check_in": "2025-09-18T21:00:00.000Z",
		"check_out": "2025-09-19T21:00:00.000Z"
	},
	...
]

Check availability of a property given check-in and check-out

GET /property/availability?id=1&check_in=2025-08-01&check_out=2025-08-05

Response

{
	"available": false
}

Fetch all reviews for property with id

GET /property/reviews/1

Response

[
	{
		"property_id": 1,
		"user_id": 1,
		"title": "Great stay! Will be back next year Edit 2",
		"body": "Staying at the Sea Voyager villa was a great experience for us. Edit 2",
		"rating": 5,
		"created_at": "2025-07-21T21:00:00.000Z",
		"id": 8,
		"booking_id": 19
	}
]

Fetch all properties that match criteria

POST /property/query

{
	"country": "IS",
	"city": "",
	"check_in": "2025-09-26",
	"check_out": "2025-09-28",
	"guests": 1,
	"property_type": null,
	"rental_type": null,
	"beds": null,
	"bedrooms": null,
	"bathrooms": null,
	"features": null,
	"experiences": null,
	"distance": null
}

Response

[
	{
		"property_id": 1,
		"user_id": 1,
		"title": "Great stay! Will be back next year Edit 2",
		"body": "Staying at the Sea Voyager villa was a great experience for us. Edit 2",
		"rating": 5,
		"created_at": "2025-07-21T21:00:00.000Z",
		"id": 8,
		"booking_id": 19
	}
]

Booking

Unauthenticated routes for fetching, creating, cancelling and authorizing access go booking data.

Fetch a booking

GET /booking/?id=13&pin=1234

Response

{
    "id": 26,
    "email": "abc@abc.com",
    "property_id": 59,
    "first_name": "John",
    "last_name": "Doe",
    "guest_address": "Some address for legal reasons",
    "guest_city": "Reykjavík",
    "guest_country": "IS",
    "guest_phone_no": "+41234567891",
    "check_in": "2025-09-18T21:00:00.000Z",
    "check_out": "2025-09-19T21:00:00.000Z",
    "guests": 1,
    "booking_status_id": 2,
    "pin_code": "1878",
    "amount": "17000.00",
    "currency": "ISK",
    "host_email": "abc@abc.com",
    "booking_status": "confirmed"
}

Create a new booking

POST /booking/new

{
	"email": "abc@domain.com",
	"property_id": 1,
	"first_name": "John",
	"last_name": "Doe",
	"address": "Street, 10",
	"city": "London",
	"country": "UK",
	"phone_number": "+1234567890",
	"check_in": "2025-10-05",
	"check_out": "2025-10-07",
	"guests": 3
}

Response

{
	"id": 10,
	"pin_code": 1234
}

Authorize access to view booking

POST /booking/authorize

{
	"confirmation_number": 13,
	"pin_code": 1234
		  	}

Response

{
	"authorized": true
}

Cancel a booking

POST /booking/cancel

{
	"confirmation_number": 13,
	"pin_code": 1234
}

Response

{
	"message": "Successfully cancelled a booking."
}

Miscellaneous

Unauthenticated routes for: exchange rate, geolocation and fetching avatar and user first name.

Fetch exchange rate given a target currency

Fetches data from https://api.freecurrencyapi.com if it was not found in a map for the current date. Data is stored in a map for fewer calls to external API.

GET /misc/exchange-rate?target=EUR

{
	"rate": 0.932
	"target": "EUR"
}

Response

{
	"userExists": true
}

Get user name and avatar

Fetches a user's first and last name and avatar given a user id. Used for reviews.

GET /misc/user/1

Response

{
	"first_name": "John",
	"last_name": "Doe",
	"img_url": "fdecab64-1755611308465.jpg"
}

Get geolocation from address

Fetches data from https://geocode.maps.co for a given address in format street+city+country (any can be omitted).

GET /misc/geo/Varmahlíð+Iceland

Response

[
	{
		"place_id": 242396444,
		"licence": "Data © OpenStreetMap contributors, ODbL 1.0. https://osm.org/copyright",
		"osm_type": "node",
		"osm_id": 244149690,
		"boundingbox": [
		  "65.5332363",
		  "65.5732363",
		  "-19.4674848",
		  "-19.4274848"
		],
		"lat": "65.5532363",
		"lon": "-19.4474848",
		"display_name": "Varmahlíð, Skagafjörður, Northwestern Region, 560, Iceland",
		"class": "place",
		"type": "village",
		"importance": 0.5006663592762519
		},
	...
]

Types

Unauthenticated routes to get types from the database: property, rental, feature and experience.

Fetch property types

GET /types/property

Response

[
	{
		"id": 1,
		"name": "hotel",
		"img_url": "hotel.jpg"
	},
	{
		"id": 2,
		"name": "apartment",
		"img_url": "apartment.jpg"
	},
	...
]

Fetch rental types

GET /types/rental

Response

[
	{
		"id": 1,
		"name": "room"
	},
	{
		"id": 2,
		"name": "entire place"
	},
	...
]

Fetch feature types

GET /types/feature

Response

[
	{
		"id": 1,
		"name": "free WiFi"
	},
	{
		"id": 2,
		"name": "free parking"
	},
	...
]

Fetch experience types

GET /types/experience

Response

[
	{
		"id": 1,
		"name": "adventure"
	},
	{
		"id": 2,
		"name": "beach"
	},
	...
]

Admin

Authenticated routes for admin operations: authorize admin, list all properties and delete property.

Authorize admin access

GET /admin/authorize

Response

{
	"authorized": true
}

Fetch all listed properties

Fetch all listed properties ordered by id desc.

GET /admin/properties

Response

HTTP status 200
[
	{
		"id": 1
		"host_email": "host@lodge.com",
		"title": "Property title",
		...
	},
	...
]

Delete property with id

DELETE /admin/property/10

Response

HTTP status 200
{
	message: "Property with id 10 successfully deleted"
}

User

Authenticated routes ...

Fetch user account configurations

Returns user settings in case the user exists.

Returns status 404 with message "User not found" if the user does not exist.

GET /user/config

Response

{
	"email": "abc@abc.com",
	"first_name": "John",
	"last_name": "Doe",
	"country_code": "IS",
	"language": null,
	"currency": "ISK",
	"experiences_ids": [
		8
	],
	"img_url": "d388915e-1758367395800.jpg"
}

Fetch all bookings for user

Fetch all bookings partitioned into categories: current, upcoming, completed and cancelled.

GET /user/booking/all

Response

{
	"current": [
		...
	],
	"upcoming": [],
	"completed": [
	{
		"booking_id": 27,
		"property_id": 59,
		"check_in": "2025-09-18T21:00:00.000Z",
		"check_out": "2025-09-19T21:00:00.000Z",
		"booking_status_id": 2,
		"pin_code": "9493",
		"title": "Lake House",
		"city": "Laugarvatn",
		"country": "IS",
		"geo": {
			"x": 64.211638290357,
			"y": -20.73186488488267
		},
		"images_url_array": [
			"f8b4b77f-1757520335408.jpg",
			"779f3352-1757520335563.jpg",
			"0cc99907-1757520335694.jpg",
			"25ac48bd-1757520335768.jpg",
			"e47f499a-1757520336015.jpg"
		],
		"street": "Laugarbraut",
		"street_no": "840",
		"booking_status": "confirmed"
		},
		...
	],
	"cancelled": [
		...
	]
}

Check if a property is wishlisted by user

GET /user/wishlist/property-id/1

Response

{
	"is_wishlisted": true
}

Toggle wishlist for property for user

If a property is in the user's wishlist, remove it. Otherwise, add the property to user's wishlist.

POST /user/wishlist/toggle/property-id/1

Response

{
	"is_wishlisted": false
}

Fetch wishlisted properties for user

GET /user/wishlist/all

Response

[
	{
		"id": 2,
		"title": "Aurora Cottage",
		"geo": {
			"x": 65.54850691798407,
			"y": -19.436812415122823
		},
		"city": "Varmahlíð",
		"country": "IS",
		"rating": null,
		"images_url_array": [
			"00000002_1.jpg",
			"00000002_2.jpg",
			"00000002_3.jpg",
			"00000002_4.jpg",
			"00000002_5.jpg"
		],
		"price_night_local": "21300.00",
		"local_currency": "ISK",
		"price_night_site": "148.57"
	}
]

Authorize booking for user

For an authenticated user, authorize if he can view a booking without using the PIN code. He can view a booking if the booking matches the email.

GET /user/authorize/booking

Response

{
	"authorized": false
}

Update user settings

Update user settings: email, first and last name, avatar, country, language, currency or experiences. The response can contain errors in case the new value does not match criteria.

PATCH /user

Response

HTTP status 200
{
	"message": "User updated successfully"
}

Update user password

The response can contain errors if the new password does not match criteria or if the old password does not match. In case of failure, the response has status 400.

PATCH /user/password

{
	"old_password": "oldpass",
	"new_password": "newpass"
}

Response

HTTP status 200
{
	"message": "Password changed successfully"
}

Delete user account

Deletes user account if no property is associated with the account. Response can return with HTTP status 400 if unsuccessful.

DELETE /user

Response

HTTP status 200
{
	"message": "Account deleted successfully"
}


Host

Authenticated routes for viewing, creating, updating and fetching hosted properties.

Fetch all properties by host user

GET /host/properties

Response

[
  {
    "id": 1,
    "title": "Sea Voyager Villa",
    "city": "Arienzo",
    "country": "IT",
    "is_listed": true,
    "price_night_local": "80.00",
    "local_currency": "EUR",
    "images_url_array": [
      "7cda38e2-1755945364513.jpg",
      "e3966213-1755945364898.jpg",
      "1d674704-1755945365041.jpg",
      "38f3d38c-1755945365202.jpg",
      "795b74b9-1755945365356.jpg"
    ]
  },
  ...
]

Create a new property

POST /host/property/new

{
  "title": "Test",
  "geo": {
    "x": 64.1422807,
    "y": -21.906605711293757
  },
  "city": "Reykjavík",
  "country": "IS",
  "street": "Laugavegur",
  "street_no": "1",
  "building_type_id": 1,
  "rental_type_id": 1,
  "local_currency": "ISK"
}

Response

{
	"id": 1
}

Update a property

PATCH /host/property/1

{
	"title: "New property name",
	"city": "City",
	"guests": 5,
	...
}

Response

HTTP status 200
{
	"message": "OK"
}

Fetch all bookings for hosted properties

Result properties are partitioned into 4 categories: arriving, checking out, current, upcoming.

GET /host/bookings/partitioned

Response

{
  "arriving": [
    {
      "id": 27,
      "first_name": "John",
      "last_name": "Doe",
      "guests": 2,
      "check_in": "2025-09-18T21:00:00.000Z",
      "check_out": "2025-09-19T21:00:00.000Z",
      "pin_code": "9493",
      "title": "Lake House"
    },
    ...
  ],
  "checkingOut": [],
  "current": [],
  "upcoming": []
}

Fetch bookings for property by id

GET /host/bookings/calendar/property/1

Response

[
  {
    "id": 1,
    "email": "abc@abc.com",
    "property_id": 1,
    "first_name": "John",
    "last_name": "Doe",
    "guest_address": "Some address for legal reasons",
    "guest_city": "Reykjavík",
    "guest_country": "IS",
    "guest_phone_no": "+410712345678",
    "check_in": "2025-09-12T21:00:00.000Z",
    "check_out": "2025-09-13T21:00:00.000Z",
    "guests": 1,
    "booking_status_id": 2,
    "pin_code": "5857",
    "amount": "17000.00",
    "currency": "ISK"
  },
  ...
]

Delete a property

DELETE /host/property/1

Response

HTTP status 200
{
	"message": "Success"
}

Upload

Authenticated routes to upload single photos as avatars and multiple photos for properties.

Upload avatar

POST /upload/avatar

Form Data with single file field "avatar"

Response

{
	"message": "File uploaded successfully",
	"filename": "d388915e-1758367395800.jpg"
}

Upload photos

Upload photos for properties (max 12).

POST /upload/photos

Form Data with multiple files field "photos"

Response

{
	"message": "Files uploaded successfully",
	"filenames": ["d388915e-1758367395800.jpg", ...]
}

Review

Authenticated routes for fetching, creating and deleting reviews.

Fetch all reviews by user

GET /review/all

Response

[
	{
		"property_id": 1,
		"user_id": 1,
		"title": "Great stay!",
		"body": "This place was awesome",
		"rating": 5,
		"created_at": "2025-07-21T21:00:00.000Z",
		"id": 8,
		"booking_id": 2
	},
	...
]

Authorize access to write a review

GET /review/authorize/booking/1

Response

HTTP status 200
{
	"isAuthorized": true,
	"property_id": 3
}

Check if user has reviewed a booking

GET /review/exists/booking/1

Response

{
	"exists": false
}

Post a review

POST /review/booking/1

{
	"property_id": 14,
	"rating": 5,
	"title": null,
	"body": "Secluded place in the middle of nature"
}

Response

HTTP status 200
{
	"message": "OK"
}

Delete a review

DELETE /review/20

Response

HTTP status 200
{
	"message": "OK"
}