The API uses PostgreSQL database named 'property_db' hosted on Azure.
A Flask-based REST API for managing property listings.
Get a list of all properties
Example:
# Get all properties
curl https://maison-api.jollybush-a62cec71.uksouth.azurecontainerapps.io/api/properties
# Get all properties including sold and under offer
curl https://maison-api.jollybush-a62cec71.uksouth.azurecontainerapps.io/api/properties?include_all=true
# Filter properties
curl https://maison-api.jollybush-a62cec71.uksouth.azurecontainerapps.io/api/properties?min_price=350000
curl https://maison-api.jollybush-a62cec71.uksouth.azurecontainerapps.io/api/properties?property_type=semi-detached
curl https://maison-api.jollybush-a62cec71.uksouth.azurecontainerapps.io/api/properties?min_bedrooms=3
curl https://maison-api.jollybush-a62cec71.uksouth.azurecontainerapps.io/api/properties?postcode=SW1
Response:
[
{
"property_id": "123e4567-e89b-12d3-a456-426614174000",
"price": 350000,
"bedrooms": 3,
"bathrooms": 2,
"main_image_url": "https://example.com/image.jpg",
"created_at": "2024-02-22T12:00:00Z",
"seller_id": "3613c096-f41f-479f-a09f-7e0ab53b4eda",
"status": "for_sale",
"address": {
"street": "Sample Street",
"city": "London",
"postcode": "SW1 1AA"
},
"specs": {
"property_type": "semi-detached",
"square_footage": 1200.0
}
},
// ... more properties
]
Get details of a specific property
Example:
curl https://maison-api.jollybush-a62cec71.uksouth.azurecontainerapps.io/api/properties/123e4567-e89b-12d3-a456-426614174000
Response:
{
"property_id": "123e4567-e89b-12d3-a456-426614174000",
"price": 350000,
"bedrooms": 3,
"bathrooms": 2,
"main_image_url": "https://example.com/main.jpg",
"image_urls": ["https://example.com/img1.jpg", "https://example.com/img2.jpg"],
"floorplan_url": "https://example.com/floorplan.jpg",
"created_at": "2024-02-22T12:00:00Z",
"last_updated": "2024-02-22T12:00:00Z",
"seller_id": "3613c096-f41f-479f-a09f-7e0ab53b4eda",
"status": "for_sale",
"address": {
"house_number": "123",
"street": "Sample Street",
"city": "London",
"postcode": "SW1 1AA",
"latitude": 51.5074,
"longitude": -0.1278
},
"specs": {
"bedrooms": 3,
"bathrooms": 2,
"reception_rooms": 2,
"square_footage": 1200.5,
"property_type": "semi-detached",
"epc_rating": "B"
},
"details": {
"description": "Beautiful family home",
"property_type": "residential",
"construction_year": 1990,
"parking_spaces": 2,
"heating_type": "gas central"
},
"features": {
"has_garden": true,
"garden_size": 100.5,
"has_garage": true,
"parking_spaces": 2
}
}
Error Response:
{
"error": "Property not found"
}
Get all properties for a specific user
Example:
curl https://maison-api.jollybush-a62cec71.uksouth.azurecontainerapps.io/api/properties/user/1
Response:
[
{
"property_id": "123e4567-e89b-12d3-a456-426614174000",
"price": 350000,
"bedrooms": 3,
"bathrooms": 2,
"main_image_url": "https://example.com/image.jpg",
"created_at": "2024-02-22T12:00:00Z",
"seller_id": 1,
"status": "for_sale",
"address": {
"street": "Sample Street",
"city": "London",
"postcode": "SW1 1AA"
},
"specs": {
"property_type": "semi-detached",
"square_footage": 1200.0
}
},
// ... more properties owned by user 1
]
Error Response (User not found):
{
"error": "User not found"
}
Create a new property listing
Required fields:
- price (integer)
- user_id (integer)
- address (object with house_number, street, city, postcode)
- specs (object with bedrooms, bathrooms, reception_rooms, square_footage, property_type, epc_rating)
Optional fields:
- main_image_url (string)
- images (array of image files, max 5MB each, formats: JPG, JPEG, PNG, GIF)
- details (object with description, property_type, construction_year, parking_spaces, heating_type)
- features (object with has_garden, garden_size, has_garage, parking_spaces)
- media (array of objects with image_url, image_type, display_order)
Example with JSON:
curl -X POST https://maison-api.jollybush-a62cec71.uksouth.azurecontainerapps.io/api/properties \
-H "Content-Type: application/json" \
-d '{
"price": 350000,
"seller_id": "3613c096-f41f-479f-a09f-7e0ab53b4eda",
"address": {
"house_number": "123",
"street": "Sample Street",
"city": "London",
"postcode": "SW1 1AA"
},
"specs": {
"bedrooms": 3,
"bathrooms": 2,
"reception_rooms": 2,
"square_footage": 1200.5,
"property_type": "semi-detached",
"epc_rating": "B"
},
"details": {
"description": "Beautiful family home",
"property_type": "residential",
"construction_year": 1990,
"parking_spaces": 2,
"heating_type": "gas central"
},
"features": {
"has_garden": true,
"garden_size": 100.5,
"has_garage": true,
"parking_spaces": 2
}
}'
Example with images (multipart form data):
curl -X POST https://maison-api.jollybush-a62cec71.uksouth.azurecontainerapps.io/api/properties \
-F 'data={
"price": 350000,
"seller_id": "3613c096-f41f-479f-a09f-7e0ab53b4eda",
"address": {
"house_number": "180",
"street": "Queen'\''s Gate",
"city": "London",
"postcode": "SW72AZ"
},
"specs": {
"bedrooms": 5,
"bathrooms": 3,
"reception_rooms": 2,
"square_footage": 2300,
"property_type": "semi-detached",
"epc_rating": "A"
},
"details": {
"description": "Beautiful family home",
"construction_year": 1990,
"heating_type": "gas central"
},
"features": {
"has_garden": true,
"garden_size": 100,
"has_garage": true,
"parking_spaces": 2
}
}' \
-F "main_image=@/Users/roblovegrove/Documents/maison/properties_api/Image Examples/HouseTwo/Brittany-Jones-Personal-01.webp" \
-F "additional_image=@/Users/roblovegrove/Documents/maison/properties_api/Image Examples/HouseTwo/istockphoto-1494221275-612x612.jpg" \
-F "additional_image=@/Users/roblovegrove/Documents/maison/properties_api/Image Examples/HouseTwo/Blog-Post-1-1024x684.jpg" \
-F "additional_image=@/Users/roblovegrove/Documents/maison/properties_api/Image Examples/HouseTwo/Cap-dAntibes-beautiful-bedroom.jpeg"
Response with images:
{
"id": "123e4567-e89b-12d3-a456-426614174000",
"message": "Property created successfully",
"warnings": [],
"image_urls": [
"https://maisonblobstorage.blob.core.windows.net/property-images/abc123.jpg",
"https://maisonblobstorage.blob.core.windows.net/property-images/def456.jpg"
]
}
Error Response:
{
"errors": [
"Price must be a positive number",
"Address street is required"
]
}
Update an existing property
Example:
curl -X PUT https://maison-api.jollybush-a62cec71.uksouth.azurecontainerapps.io/api/properties/123e4567-e89b-12d3-a456-426614174000 \
-H "Content-Type: application/json" \
-H "Authorization: Bearer ${FIREBASE_ID_TOKEN}" \
-d '{
"price": 375000,
"specs": {
"bedrooms": 4,
"bathrooms": 2,
"reception_rooms": 2,
"square_footage": 1500.0,
"property_type": "semi-detached",
"epc_rating": "A"
}
}'
Response:
{
"message": "Property updated successfully"
}
Error Response:
{
"error": "Property not found"
}
Delete a property (Protected - Requires authentication)
Example:
curl -X DELETE https://maison-api.jollybush-a62cec71.uksouth.azurecontainerapps.io/api/properties/123e4567-e89b-12d3-a456-426614174000 \
-H "Authorization: Bearer ${FIREBASE_ID_TOKEN}"
Response:
{
"message": "Property deleted successfully"
}
Error Response:
{
"error": "Property not found"
}
Create a new user account
Required fields:
- user_id (UUID): User's Firebase UUID
- first_name (string): User's first name
- last_name (string): User's last name
- email (string): User's email address
Optional fields:
- phone_number (string): User's phone number
- roles (array): User roles (defaults to ["buyer"] if not specified)
Example:
curl -X POST https://maison-api.jollybush-a62cec71.uksouth.azurecontainerapps.io/api/users \
-H "Content-Type: application/json" \
-d '{
"user_id": "RY34xpmeKTWHXstoZKdX4JrKchL2",
"first_name": "Teej",
"last_name": "Amosu",
"email": "Teej@maisonai.co.uk",
"phone_number": "07700900000",
"roles": [
{"role_type": "buyer"},
{"role_type": "seller"}
]
}'
Response:
{
"message": "User created successfully",
"user": {
"user_id": "bd70f994-5834-45b9-a6f0-8731e51ff0e6",
"first_name": "John",
"last_name": "Smith",
"email": "john.smith@example.com",
"phone_number": "07700900000",
"roles": [
{"role_type": "buyer"},
{"role_type": "seller"}
]
}
}
Error Responses:
{
"error": "Email already registered"
}
{
"error": {
"email": ["Not a valid email address"],
"first_name": ["Length must be between 1 and 50"]
}
}
Update a user account
All fields are optional
Partial Updates are allowed
Returns both success message and updated user data
Example:
curl -X PUT https://maison-api.jollybush-a62cec71.uksouth.azurecontainerapps.io/api/users/3613c096-f41f-479f-a09f-7e0ab53b4eda \
-H "Content-Type: application/json" \
-d '{
"first_name": "Updated First Name",
"last_name": "Updated Last Name",
"email": "newemail@example.com",
"phone_number": "07700900001"
}'
Response:
{
"message": "User updated successfully",
"user": {
"id": "3613c096-f41f-479f-a09f-7e0ab53b4eda",
"first_name": "Updated First Name",
"last_name": "Updated Last Name",
"email": "newemail@example.com",
"phone_number": "07700900001"
}
}
Error Response:
{
"error": "User not found"
}
Error Response:
{
"error": "Email already registered"
}
Get a user's dashboard data including their properties, offers, and saved listings.
Example:
curl https://maison-api.jollybush-a62cec71.uksouth.azurecontainerapps.io/api/users/3613c096-f41f-479f-a09f-7e0ab53b4eda/dashboard
Response:
{
"listed_properties": [],
"negotiations_as_buyer": [
{
"awaiting_response_from": "buyer",
"buyer_id": "bd70f994-5834-45b9-a6f0-8731e51ff0e6",
"created_at": "2025-03-02T14:40:59.226953+00:00",
"current_offer": 360000,
"last_offer_by": "3613c096-f41f-479f-a09f-7e0ab53b4eda",
"negotiation_id": "98de7487-c36f-4111-ba80-388f48a1f614",
"property_id": "fe08df1c-d24e-4f18-9c7b-cfbe842175f1",
"status": "active",
"transaction_history": [
{
"created_at": "2025-03-02T14:40:59.240797+00:00",
"made_by": "bd70f994-5834-45b9-a6f0-8731e51ff0e6",
"offer_amount": 350000
},
{
"created_at": "2025-03-02T14:45:34.356241+00:00",
"made_by": "3613c096-f41f-479f-a09f-7e0ab53b4eda",
"offer_amount": 360000
}
],
"updated_at": "2025-03-02T14:45:34.345590+00:00"
}
],
"negotiations_as_seller": [],
"offered_properties": [
{
"property_id": "fe08df1c-d24e-4f18-9c7b-cfbe842175f1",
"price": 425000,
"bedrooms": 4,
"bathrooms": 2,
"main_image_url": "https://maisonblobstorage.blob.core.windows.net/property-images/2ea1d64a-18da-4752-9b1e-fa40dccd8da9.jpg",
"created_at": "2025-03-02T13:56:00.576177+00:00",
"seller_id": "3613c096-f41f-479f-a09f-7e0ab53b4eda",
"status": "for_sale",
"address": {
"house_number": "123",
"street": "Oak Avenue",
"city": "Manchester",
"postcode": "M20 3PS"
},
"specs": {
"property_type": "detached",
"square_footage": 2100.5
},
"latest_offer": {
"amount": 360000,
"status": "active",
"last_updated": "2025-03-02T14:45:34.345590+00:00"
}
}
],
"roles": [
{
"role_type": "buyer"
}
],
"saved_properties": [
{
"address": {
"city": "London",
"postcode": "SW1 1AA",
"street": "Sample Street"
},
"main_image_url": "https://maisonblobstorage.blob.core.windows.net/property-images/2ea1d64a-18da-4752-9b1e-fa40dccd8da9.jpg",
"notes": "Great location, need to book viewing",
"price": 350000,
"property_id": "5ea12e39-bff9-48e2-b593-eb13b5908959",
"saved_at": "2025-03-02T12:45:25.214553+00:00",
"specs": {
"bathrooms": 2,
"bedrooms": 3,
"property_type": "semi-detached"
},
"status": "for_sale"
},
{
"address": {
"city": "Manchester",
"postcode": "M20 3PS",
"street": "Oak Avenue"
},
"main_image_url": "https://maisonblobstorage.blob.core.windows.net/property-images/2ea1d64a-18da-4752-9b1e-fa40dccd8da9.jpg",
"notes": "Great location, need to book viewing",
"price": 425000,
"property_id": "fe08df1c-d24e-4f18-9c7b-cfbe842175f1",
"saved_at": "2025-03-02T13:56:00.576177+00:00",
"specs": {
"bathrooms": 2,
"bedrooms": 4,
"property_type": "detached"
},
"status": "for_sale"
}
],
"total_properties_listed": 0,
"total_saved_properties": 2,
"user": {
"email": "misty16@example.org",
"first_name": "Wesley",
"last_name": "Watson",
"phone_number": "+446479882571",
"id": "bd70f994-5834-45b9-a6f0-8731e51ff0e6"
}
}
Error Response:
{
"error": "User not found"
}
Get a list of all users with their roles and counts
Example:
curl https://maison-api.jollybush-a62cec71.uksouth.azurecontainerapps.io/api/users
Response:
{
"sellers": [
"3613c096-f41f-479f-a09f-7e0ab53b4eda",
"4723d197-g52f-580f-b10f-8e0ab53b5fdb"
],
"buyers": [
"3613c096-f41f-479f-a09f-7e0ab53b4eda",
"5834e298-h63g-691g-c21g-9f1bc64c6gec",
"6945f399-i74h-702h-d32h-0g2cd75d7hfd"
],
"counts": {
"total_buyers": 3,
"total_sellers": 2
}
}
Note: Some users may appear in both sellers and buyers lists if they have both roles.
Error Response:
{
"error": "Failed to fetch users"
}
Save a property for a buyer
Required fields:
- property_id (UUID): The ID of the property to save
Optional fields:
- notes (string): Any notes about the saved property
Example:
# Save property with notes
curl -X POST https://maison-api.jollybush-a62cec71.uksouth.azurecontainerapps.io/api/users/bd70f994-5834-45b9-a6f0-8731e51ff0e6/saved-properties \
-H "Content-Type: application/json" \
-d '{
"property_id": "fe08df1c-d24e-4f18-9c7b-cfbe842175f1",
"notes": "Great location, need to book viewing"
}'
# Save property without notes
curl -X POST https://maison-api.jollybush-a62cec71.uksouth.azurecontainerapps.io/api/users/bd70f994-5834-45b9-a6f0-8731e51ff0e6/saved-properties \
-H "Content-Type: application/json" \
-d '{
"property_id": "fe08df1c-d24e-4f18-9c7b-cfbe842175f1"
}'
Response:
{
"message": "Property saved successfully",
"saved_property": {
"user_id": "bd70f994-5834-45b9-a6f0-8731e51ff0e6",
"property_id": "fe08df1c-d24e-4f18-9c7b-cfbe842175f1",
"notes": "Great location, need to book viewing", // Will be null if not provided
"created_at": "2024-02-25T15:30:00Z"
}
}
Error Responses:
{
"error": "User must be a buyer to save properties"
}
{
"error": "Property already saved"
}
{
"error": "Property not found"
}
{
"error": "property_id is required"
}
Remove a property from a buyer's saved properties
Example:
curl -X DELETE https://maison-api.jollybush-a62cec71.uksouth.azurecontainerapps.io/api/users/bd70f994-5834-45b9-a6f0-8731e51ff0e6/saved-properties/fe08df1c-d24e-4f18-9c7b-cfbe842175f1
Response:
{
"message": "Property removed from saved properties",
"removed_property": {
"user_id": "bd70f994-5834-45b9-a6f0-8731e51ff0e6",
"property_id": "fe08df1c-d24e-4f18-9c7b-cfbe842175f1"
}
}
Error Responses:
{
"error": "User must be a buyer to manage saved properties"
}
{
"error": "Property not found in saved properties"
}
Update notes for a saved property
Required fields:
- notes (string): The new notes for the saved property
Example:
curl -X PATCH https://maison-api.jollybush-a62cec71.uksouth.azurecontainerapps.io/api/users/bd70f994-5834-45b9-a6f0-8731e51ff0e6/saved-properties/fe08df1c-d24e-4f18-9c7b-cfbe842175f1/notes \
-H "Content-Type: application/json" \
-d '{
"notes": "Great location, close to schools. Viewing scheduled for next week."
}'
Response:
{
"message": "Notes updated successfully",
"saved_property": {
"user_id": "bd70f994-5834-45b9-a6f0-8731e51ff0e6",
"property_id": "fe08df1c-d24e-4f18-9c7b-cfbe842175f1",
"notes": "Great location, close to schools. Viewing scheduled for next week.",
"updated_at": "2024-02-25T16:30:00Z"
}
}
Error Responses:
{
"error": "User must be a buyer to update saved properties"
}
{
"error": "Property not found in saved properties"
}
{
"error": "notes field is required"
}
Create a new offer or counter-offer on a property
Required fields:
- property_id (UUID): The ID of the property
- offer_amount (integer): The amount being offered
Optional fields for counter-offers:
- negotiation_id (UUID): Required when making a counter-offer
Example - New Offer:
curl -X POST https://maison-api.jollybush-a62cec71.uksouth.azurecontainerapps.io/api/users/bd70f994-5834-45b9-a6f0-8731e51ff0e6/offers \
-H "Content-Type: application/json" \
-d '{
"property_id": "fe08df1c-d24e-4f18-9c7b-cfbe842175f1",
"offer_amount": 350000
}'
Example - Counter Offer:
curl -X POST https://maison-api.jollybush-a62cec71.uksouth.azurecontainerapps.io/api/users/3613c096-f41f-479f-a09f-7e0ab53b4eda/offers \
-H "Content-Type: application/json" \
-d '{
"property_id": "fe08df1c-d24e-4f18-9c7b-cfbe842175f1",
"offer_amount": 360000,
"negotiation_id": "98de7487-c36f-4111-ba80-388f48a1f614"
}'
Response:
{
"message": "Offer submitted successfully",
"negotiation": {
"negotiation_id": "789fcdeb-51a2-4bc1-9e8d-326417400000",
"property_id": "fe08df1c-d24e-4f18-9c7b-cfbe842175f1",
"buyer_id": "bd70f994-5834-45b9-a6f0-8731e51ff0e6",
"current_offer": 350000,
"status": "active",
"created_at": "2024-02-25T15:30:00Z",
"last_offer_by": "bd70f994-5834-45b9-a6f0-8731e51ff0e6",
"awaiting_response_from": "seller"
}
}
Error Responses:
{
"error": "User must be a buyer to make offers"
}
{
"error": "Cannot make offer on your own property"
}
{
"error": "Active negotiation already exists"
}
{
"error": "Property not found"
}
{
"error": "Unauthorized to make counter-offer"
}
Update an offer's status (accept/reject/cancel)
Required fields:
- action (string): Must be one of: "accept", "reject", "cancel"
Rules:
- Only the buyer or seller involved in the negotiation can update its status
- Can only accept/reject offers made by the other party
- Can only cancel your own most recent offer
- If buyer cancels their first offer, the entire negotiation is cancelled
- If cancelling a counter-offer, reverts to the previous offer from the other party
Examples:
# Accept an offer
curl -X PUT https://maison-api.jollybush-a62cec71.uksouth.azurecontainerapps.io/api/users/seller_id/offers/negotiation_id \
-H "Content-Type: application/json" \
-d '{
"action": "accept"
}'
# Reject an offer
curl -X PUT https://maison-api.jollybush-a62cec71.uksouth.azurecontainerapps.io/api/users/seller_id/offers/negotiation_id \
-H "Content-Type: application/json" \
-d '{
"action": "reject"
}'
# Cancel your offer/counter-offer
curl -X PUT https://maison-api.jollybush-a62cec71.uksouth.azurecontainerapps.io/api/users/user_id/offers/negotiation_id \
-H "Content-Type: application/json" \
-d '{
"action": "cancel"
}'
Response:
{
"message": "Counter-offer cancelled, reverted to previous offer",
"negotiation": {
"negotiation_id": "123e4567-e89b-12d3-a456-426614174000",
"property_id": "123e4567-e89b-12d3-a456-426614174001",
"buyer_id": "123e4567-e89b-12d3-a456-426614174002",
"seller_id": "123e4567-e89b-12d3-a456-426614174003",
"current_offer_amount": 350000,
"status": "active",
"updated_at": "2024-02-22T12:00:00Z",
"action_by": "123e4567-e89b-12d3-a456-426614174002",
"property_status": "for_sale",
"last_offer_by": "123e4567-e89b-12d3-a456-426614174002"
}
}
Error Responses:
{
"error": "Cannot accept/reject your own offer. Waiting for buyer response"
}
{
"error": "Can only cancel your own most recent offer"
}
{
"error": "Cannot update: negotiation is already accepted"
}
Parameter | Type | Description | Example |
---|---|---|---|
include_all | bool | Include all properties regardless of status | ?include_all=true |
min_price | int | Minimum price | ?min_price=200000 |
max_price | int | Maximum price | ?max_price=500000 |
bedrooms | int | Number of bedrooms | ?bedrooms=3 |
bathrooms | int | Number of bathrooms | ?bathrooms=2 |
city | string | City location | ?city=London |
property_type | string | Type of property | ?property_type=semi-detached |
has_garden | bool | Has garden | ?has_garden=true |
parking_spaces | int | Minimum parking spaces | ?parking_spaces=2 |
status | string | Property status | ?status=for_sale |
Properties can have one of three statuses: for_sale
, under_offer
, or sold
. Status transitions follow these rules:
for_sale
: Can transition to under_offer
or sold
under_offer
: Can transition back to for_sale
or to sold
sold
: Cannot transition to any other status# Mark property as under offer
curl -X PUT https://maison-api.jollybush-a62cec71.uksouth.azurecontainerapps.io/api/properties/123e4567-e89b-12d3-a456-426614174000 \
-H "Content-Type: application/json" \
-d '{
"status": "under_offer"
}'
# Mark property as sold
curl -X PUT https://maison-api.jollybush-a62cec71.uksouth.azurecontainerapps.io/api/properties/123e4567-e89b-12d3-a456-426614174000 \
-H "Content-Type: application/json" \
-d '{
"status": "sold"
}'
# Return property to for_sale (only valid from under_offer)
curl -X PUT https://maison-api.jollybush-a62cec71.uksouth.azurecontainerapps.io/api/properties/123e4567-e89b-12d3-a456-426614174000 \
-H "Content-Type: application/json" \
-d '{
"status": "for_sale"
}'
Response:
{
"message": "Property updated successfully",
"status": "under_offer"
}
Error Response (Invalid Status):
{
"error": "Invalid status transition from for_sale to sold"
}
Error Response (Updating Sold Property):
{
"error": "Cannot update status of sold property"
}
# Get only properties for sale (default behavior)
curl https://maison-api.jollybush-a62cec71.uksouth.azurecontainerapps.io/api/properties
# Get properties under offer
curl https://maison-api.jollybush-a62cec71.uksouth.azurecontainerapps.io/api/properties?status=under_offer
# Get sold properties
curl https://maison-api.jollybush-a62cec71.uksouth.azurecontainerapps.io/api/properties?status=sold
# Get all properties regardless of status
curl https://maison-api.jollybush-a62cec71.uksouth.azurecontainerapps.io/api/properties?include_all=true
UUID Implementation
Enhanced Validation
Geocoding Support
Required User Association
Error Handling
Azure Blob Storage Integration
# Create virtual environment
python -m venv .venv
source .venv/bin/activate # Linux/Mac
.venv\Scripts\activate # Windows
# Install dependencies
pip install -r requirements.txt
# Set up environment variables
cp .env.example .env
# Edit .env with your database credentials
# Initialize database
flask db upgrade
pytest tests/
The database consists of several related tables:
- properties
: Core property information
- addresses
: Property location details
- property_specs
: Property specifications
- property_features
: Additional property features
- property_details
: Detailed property information
- property_media
: Property images and floorplans
The API returns standard HTTP status codes:
200 OK
: Request successful201 Created
: Resource created successfully400 Bad Request
: Invalid input provided404 Not Found
: Resource not found500 Internal Server Error
: Server errorError responses include a message:
{
"error": "Detailed error message"
}
docker build -t maison_property_api .
docker run -d \
-p 8000:8080 \
-e DATABASE_URL="your_database_url" \
-e FLASK_APP="wsgi.py" \
-e FLASK_ENV="production" \
--name maison_api \
maison_property_api
curl https://maison-api.jollybush-a62cec71.uksouth.azurecontainerapps.io/health
az containerapp update -n maison-api -g maison-rg \
--set-env-vars \
DATABASE_URL="postgresql://maisondbadmin:password@maison-db.postgres.database.azure.com/property_db?sslmode=require" \
FLASK_APP="wsgi.py" \
FLASK_ENV="production"
az containerapp secret set -n maison-api -g maison-rg \
--secrets azure-storage-connection="your-connection-string"