Leasey.AI API Documentation
The Leasey External API allows authorized partners to read reporting data and manage property listings programmatically. Built on REST principles โ standard HTTP methods, resource-based URLs, and JSON responses.
Version 2.0
Protocol HTTPS
Format JSON
Last updated: June 01, 2026
What changed in v2.0
Version 2.0 is a full REST redesign. If you integrated with v1, update your requests according to the tables below.
Reports API
| v1 (old) | v2 (current) | What changed |
POST /reports + "report_type":"showings" | GET /reports/showings | Each report type is its own URL. Use GET, not POST. |
POST /reports + "report_type":"leads" | GET /reports/leads | Dedicated URL per resource. |
POST /reports + "report_type":"properties" | GET /reports/properties | Dedicated URL per resource. |
password in JSON body | X-Company-Password header | Passwords no longer go in request bodies for read ops. |
company_id in JSON body | company_id query parameter | Filters are query params on GET requests. |
Properties API
| v1 (old) | v2 (current) | What changed |
POST /properties + "action":"create" | POST /properties | The action field is removed. POST always means create. |
PUT /properties + "property_id" in body | PUT /properties/{property_id} | Property ID moves to the URL path. |
1. Getting Started
To use the Leasey External API you need three credentials:
| Credential | Description | How to obtain |
| API Token | Application-level bearer token | Contact Leasey support |
| Company ID | Your company's numeric identifier | Leasey dashboard โ Settings |
| Company Password | Your company's API password | Leasey dashboard โ Settings โ API |
bash โ first request
curl -X GET "https://<base-url>/reports/showings?company_id=123" \
-H "Authorization: Bearer <your-api-token>" \
-H "X-Company-Password: <your-company-password>"
2. Authentication
Every request requires two levels of authentication.
Level 1 โ API Token
Authorization: Bearer <api_token>
โน๏ธThe Bearer prefix is required. As a fallback you may pass the token as ?token=<api_token> for debugging only โ query strings appear in server logs and should not be used in production.
Level 2 โ Company Credentials
| Request type | company_id | password |
GET (reports, leads read) | Query parameter | X-Company-Password header |
POST / PUT (property write) | JSON body field | JSON body field "password" |
๐Using X-Company-Password on GET requests keeps the password out of server logs, CDN caches, and browser history.
Authentication errors
| Scenario | Status | Message |
| Token missing | 401 | Authentication token required |
| Token incorrect | 401 | Invalid authentication token |
| Token length mismatch | 401 | The provided token does not match the expected token โ verify you are copying the full token (expected length: 48 characters) |
| Password missing | 401 | X-Company-Password header is required |
| Password incorrect | 401 | Invalid company password |
| Company not found | 401 | Company {id} not found |
| No admin for company | 400 | No admin user found for company {id}. Contact support. |
3. Environments & Base URL
Production: https://uvciw58bnh.execute-api.ca-central-1.amazonaws.com/production
Staging: https://hs52apwqwh.execute-api.ca-central-1.amazonaws.com/staging
๐กRun serverless info --stage production from reports-api-service/ to get the exact URL for your stage. All examples use {base_url} as a placeholder.
4. Reports API
GET/reports/showings
Returns all property showing and viewing activity for a company.
Headers
| Header | Required | Description |
Authorization | Yes | Bearer <api_token> |
X-Company-Password | Yes | Your company API password |
Query Parameters
| Parameter | Type | Required | Default | Description |
company_id | integer | Yes | โ | Your company identifier |
start_date | ISO-8601 | No | Jan 1 current year | Filter showings on or after โ format: YYYY-MM-DDTHH:MM:SS |
end_date | ISO-8601 | No | None | Filter showings on or before |
bash
curl -X GET "{base_url}/reports/showings?company_id=123&start_date=2024-11-01T00:00:00&end_date=2024-11-30T23:59:59" \
-H "Authorization: Bearer <api_token>" \
-H "X-Company-Password: <company_password>"
Response Fields
| Field | Type | Description |
Property_Name | string | Building or complex name |
Unit_Name | string | Unit identifier |
Unit_Address | string | Street address |
Unit_ID | integer | Internal unit ID |
Property_ID | integer | Internal property ID |
Unit_Type | string | Property type |
Unit_status | string | Active or Archived |
Unit_publish_status | string | Published or Unpublished |
Vacancy_Status | string | Vacant or Occupied |
Rental_Space | string | Entire place, Partial place |
Lease_Term | string | Fixed term, Month to month, etc. |
Suite_Number | string | Suite / unit number |
Rent_Amount | number | Monthly rent |
Parking_Stalls | integer | Number of parking stalls |
Bedrooms | number | Number of bedrooms |
Bathrooms | number | Number of bathrooms |
Square_Footage | integer | Unit size in sq ft |
Max_Occupancy | integer | Maximum occupants |
Furnishing | string | Furnished / Unfurnished / Partially furnished |
Country | string | Country |
Days_listed | integer | Days on market |
Storage | string | Yes or No |
Date_start | datetime | Showing start time |
Date_end | datetime | Showing end time |
Showing_Status | string | Scheduled, Confirmed, Cancelledโฆ |
TeamMember | string | Assigned team member name |
TeamMemberRol | string | Team member role |
Lead_source | string | Origin of lead (Website, Zillowโฆ) |
Showing_Feedback | string | null | Post-showing feedback |
Person_ID | integer | null | Lead's person ID |
Application_ID | integer | null | Application ID |
Lead_Name | string | null | Full name |
Lead_First_Name | string | null | First name |
Lead_Last_Name | string | null | Last name |
Lead_Email | string | null | Email address |
Lead_Phone | string | null | Phone with dial code |
Application_Status | string | null | Lead, Application In Progressโฆ |
Applicant_Rating | integer | null | Rating 0โ5 |
Tenancy_Application_Status | string | null | Document review status |
Lead_Approval_Status | string | null | Approval status |
Lead_Note | string | null | Internal notes |
GET/reports/leads
Returns prospect and applicant data for a company.
Query Parameters
| Parameter | Type | Required | Default | Description |
company_id | integer | Yes | โ | Your company identifier |
start_date | ISO-8601 | No | Jan 1 current year | Filter by lead creation date (on or after) |
end_date | ISO-8601 | No | None | Filter by lead creation date (on or before) |
bash
curl -X GET "{base_url}/reports/leads?company_id=123&start_date=2024-01-01T00:00:00" \
-H "Authorization: Bearer <api_token>" \
-H "X-Company-Password: <company_password>"
Response Fields
| Field | Type | Description |
Application_ID | integer | Application identifier |
Applicant_ID | integer | Applicant record identifier |
Person_ID | integer | Person identifier |
Lead_Name | string | Full name |
Lead_First_Name | string | First name |
Lead_Last_Name | string | Last name |
Lead_Email | string | Email address |
Lead_Phone | string | Phone with dial code |
Application_Status | string | Lead, Incomplete Application, Application Received, Application Under Review, Lease Signed, Archived |
Applicant_Rating | number | Rating 0โ5 |
Tenancy_Application_Status | string | Document review status |
Lead_Approval_Status | string | Approval status |
Unit_Name | string | Property of interest |
Property_Name | string | Building name |
Unit_Address | string | Street address |
Full_Address | string | Concatenated full address |
Unit_City | string | City |
Unit_Province | string | Province / state |
Unit_Publish_Status | string | Published or Unpublished |
Vacancy_Status | string | Vacant or Occupied |
Rent_Amount | number | Monthly rent |
Rent_Payment_Frequency | string | Payment frequency |
Lease_Type | string | Fixed term, Month to month, etc. |
Bedrooms | number | Bedrooms |
Bathrooms | number | Bathrooms |
Furnishing | string | Furnished, Unfurnished, Partially furnished |
Lead_Source | string | Origin of lead |
Lead_Note | string | null | Internal notes |
Lead_Date_Created | datetime | When lead was created |
Application_Sent_Date | datetime | null | When application was sent |
Application_Received_Date | datetime | null | When application was received back |
GET/reports/properties
Returns the full property portfolio. Always returns all properties โ date parameters are not applicable.
Query Parameters
| Parameter | Type | Required | Description |
company_id | integer | Yes | Your company identifier |
bash
curl -X GET "{base_url}/reports/properties?company_id=123" \
-H "Authorization: Bearer <api_token>" \
-H "X-Company-Password: <company_password>"
Response Fields
| Field | Type | Description |
Property_ID | integer | Unique property identifier |
Property_URL_Slug | string | URL-safe slug |
Property_Name | string | Building name |
Unit_Name | string | Unit identifier |
Unit_Address | string | Street address |
Unit_Type | string | Apartment, House, Townhouseโฆ |
Unit_Status | string | Active or Archived |
Unit_Publish_Status | string | Published or Unpublished |
Rental_Space | string | Entire place, Partial place |
Lease_Term | string | Fixed term, Month to monthโฆ |
Suite_Number | string | Suite / unit number |
City | string | City |
Province_State | string | Province or state |
Postal_Code | string | Postal / ZIP code |
Country | string | Country |
Days_Listed | integer | Days since marketing start |
Marketing_Start | date | null | Date listed for marketing |
Marketing_End | date | null | Date taken off market (null = still active) |
Date_Available | date | null | Move-in available date |
Rent_Amount | number | Monthly asking rent |
Rent_Market | number | null | Market rent (only if feature enabled) |
Parking_Stalls | integer | Number of parking stalls |
Bedrooms | number | Bedrooms |
Bathrooms | number | Bathrooms |
Square_Footage | integer | Unit size in sq ft |
Max_Occupancy | integer | Maximum occupants |
Furnishing | string | Furnished / Unfurnished / Partially furnished |
Storage | string | Yes or No |
Vacancy_Status | string | Vacant or Occupied |
Description | string | null | Property description |
Latitude | number | null | GPS latitude |
Longitude | number | null | GPS longitude |
Lead_Status | string | No Leads, 1-5 Leads, 6-10 Leads, 10+ Leads |
Lead_Count | integer | Total lead count |
Applicant_Status | string | Bucketed label for applicant count |
Applicant_Count | integer | Total applicant count |
Lease_Status | string | No Active Leases, 1 Active Lease, Multiple Leases |
Lease_Count | integer | Active lease count |
Total_Applications | integer | All-time applications |
Showings_Disqualified | integer | Disqualified showings |
Showings_Scheduled | integer | Pending showings |
Showings_Confirmed | integer | Confirmed showings |
Showings_Cancelled | integer | Cancelled showings |
Showings_Total | integer | Total showings |
Contact_Name | string | null | Assigned contact person |
Contact_Email | string | Routed inbox for this listing |
Contact_Phone | string | null | Contact phone |
Images | array | Image URLs (up to 10, ordered) |
Unit_Amenities | array | Unit-level amenity names |
Unit_Amenities_Count | integer | Count of unit amenities |
Building_Amenities | array | Building-level amenity names |
Building_Amenities_Count | integer | Count of building amenities |
Listing_URL | string | null | Public listing page on Leasey |
5. Properties API
POST/properties
Creates a new property listing. Returns property_id โ store it for future updates.
Required Body Fields
| Field | Type | Description |
company_id | integer | Your company identifier |
password | string | Your company API password |
property.name | string | Unit or property name |
property.address | string | Street address |
property.city | string | City name |
property.province_state | string | Province or state (e.g. ON, BC) |
property.country | string | Country name |
json โ example request body
{
"company_id": 123,
"password": "<company_password>",
"property": {
"name": "Unit 2B",
"address": "456 Oak Ave",
"city": "Toronto",
"province_state": "ON",
"country": "Canada",
"postal_code": "M5V 2T6",
"unit_type": "apartment",
"rental_space": "entire place",
"rent_amount": "2100",
"rent_payment_frequency": "monthly",
"renewal_frequency": "month to month",
"bedrooms": 2,
"bathrooms": 1,
"size_sqft": 850,
"furnishing": 2,
"parking_stalls": 1,
"date_available": "2025-02-01",
"building_name": "Oak Ave Apartments",
"features": [
{ "id": 1, "value": 1 },
{ "id": 13, "value": 1 }
],
"building_amenities": [
{ "id": 4, "value": 1 }
],
"restrictions": [1, 2],
"marketplaces": [
{ "name": "zillow", "enabled": true }
]
}
}
Response 201 Created
{
"success": true,
"message": "Property created successfully.",
"property_id": "a3f7b2d1-e894-4c1a-b5f0-1234567890ab",
"url_slug": "unit-2b",
"building_id": 55,
"floorplan_id": 12,
"building_amenities": {
"building_id": 55,
"inserted": 1,
"skipped": []
},
"team_members": {
"assigned": [45, 101],
"created": [
{
"team_member_id": 101,
"user_id": 305,
"person_id": 488,
"email": "sara.white@mycompany.com",
"already_existed": false
}
],
"skipped": []
}
}
โ ๏ธSave the property_id. It is the only way to update this property later via PUT /properties/{property_id}.
Response Fields
| Field | Always present | Description |
property_id | Yes | UUID of the created property. Store this โ required for future updates. |
url_slug | Yes | URL-safe slug generated from name + suite_unit |
building_id | Only if building linked | ID of the building the property was linked to |
floorplan_id | Only if floorplan set | ID of the floorplan assigned |
building_amenities.inserted | Only if building_amenities sent | Count of amenity records inserted |
building_amenities.skipped | Only if building_amenities sent | Array of error strings for items that could not be saved |
team_members.assigned | Only if team_members sent | Array of team_member_id integers successfully assigned |
team_members.created | Only if team_members sent | Array of objects for newly created team members |
team_members.skipped | Only if team_members sent | Array of error strings for items that could not be processed |
PUT/properties/{property_id}
Updates an existing property. Only fields in the property object are modified.
json โ example request body
{
"company_id": 123,
"password": "<company_password>",
"property": {
"rent_amount": "2200",
"date_available": "2025-03-01"
}
}
๐Partial update behavior: photos, features, building_amenities, restrictions replace all existing values when included. team_members is additive only โ existing assignments are never removed. marketplaces updates only the listed entries; others retain their current state.
GET/properties/leads
Simplified, paginated lead list. Lighter than GET /reports/leads.
Query Parameters
| Parameter | Type | Required | Default | Description |
company_id | integer | Yes | โ | Your company identifier |
password | string | Yes | โ | Your company API password |
start_date | ISO-8601 | No | None | Filter leads created on or after |
end_date | ISO-8601 | No | None | Filter leads created on or before |
property_id | UUID | No | None | Filter by a specific property |
limit | integer | No | 100 (max 500) | Maximum records returned |
6. Property Object Reference
All fields accepted in the property object for create and update requests.
Core Fields
| Field | Type | Required | Description |
name | string | Yes | Unit or property name |
address | string | Yes | Street address |
city | string | Yes | City name |
province_state | string | Yes | Province or state code or full name (e.g. ON, Ontario) |
country | string | Yes | Country name |
postal_code | string | No | Postal or ZIP code |
suite_unit | string | No | Suite number. Used to generate the URL slug: {name}-{suite_unit} |
description | string | No | Property description text |
date_available | date | No | Move-in available date (YYYY-MM-DD) |
Pricing & Lease Fields
| Field | Type | Default | Description |
rent_amount | string or number | 0 | Monthly asking rent |
security_deposit | number | 0 | Security deposit amount |
rent_payment_frequency | string | monthly | Payment frequency โ see Enum Values |
renewal_frequency | string | month to month | Lease renewal type โ see Enum Values |
Physical Fields
| Field | Type | Default | Description |
unit_type | string | apartment | Property type โ see Enum Values |
rental_space | string | entire place | Rental space type โ see Enum Values |
bedrooms | number | 0 | Bedrooms (0.5 for bachelors) |
bathrooms | number | 0 | Bathrooms (e.g. 1, 1.5, 2) |
size_sqft | integer | 0 | Unit size in square feet |
max_occupancy | integer | bedrooms ร 2 | Maximum permitted occupants |
parking_stalls | integer | null | Number of parking stalls |
furnishing | integer | 2 | 1 Furnished ยท 2 Unfurnished ยท 3 Partially furnished |
storage_available | integer | 2 | 1 Available ยท 2 Not available ยท 3 Available (extra cost) |
rental_application_url | string (URL) | null | Custom external application URL |
owner_user_id | integer | null | Override the internal Leasey platform user assigned as property owner. Must be a users.id that belongs to your company. If invalid, silently falls back to the company's primary admin. |
โ ๏ธuse_custom_application_link is a company-level setting. Setting this to true routes all applicants across all properties in your company to the rental_application_url instead of the built-in Leasey form โ not just the property you are creating or updating.
Features (Unit Amenities)
The features array controls unit-level amenity and utility availability. Each entry has an id and a value: 1 = Included in rent ยท 2 = Available, not included ยท 3 = Not available. Only include features you want to set โ unspecified features default to not available.
"features": [
{ "id": 1, "value": 1 },
{ "id": 13, "value": 1 },
{ "id": 20, "value": 2 }
]
Unit feature IDs โ complete list
| ID | Feature | Category |
1 | Air conditioning | Amenity |
2 | Balcony / patio | Amenity |
3 | Basement | Amenity |
4 | Bike storage | Amenity |
5 | Concierge | Amenity |
6 | Dishwasher | Amenity |
7 | Electrical car charging station | Amenity |
8 | Fireplace | Amenity |
9 | Fitness center / gym | Amenity |
10 | Furnished | Amenity |
11 | Heating | Amenity |
12 | Hot tub | Amenity |
13 | In-suite washer | Amenity |
14 | Parking | Amenity |
15 | Sauna | Amenity |
16 | Steam room | Amenity |
17 | Storage locker | Amenity |
18 | Swimming pool | Amenity |
19 | Cable | Utility |
20 | Electricity | Utility |
21 | Internet | Utility |
22 | Natural gas | Utility |
23 | Water | Utility |
24 | Common areas | Amenity |
25 | Community laundry | Amenity |
26 | Elevator | Amenity |
27 | On-site manager | Amenity |
28 | In-suite dryer | Amenity |
29 | Food waste disposal | Amenity |
30 | Freezer | Amenity |
31 | Microwave | Amenity |
32 | Oven | Amenity |
33 | Refrigerator | Amenity |
34 | Stove | Amenity |
35 | Garbage disposal | Utility |
36 | Satellite TV | Utility |
37 | Sewage | Utility |
Building Fields
| Field | Type | Description |
building_name | string | Name of the building. If a building with this name already exists for your company, the property is linked to it; otherwise a new building is created. |
building_id | integer | Link to an existing building by ID (from prior create responses). Takes precedence over building_name. |
number_of_units | integer | Total units in the building. Required to auto-create a building without an explicit building_id. |
Building Amenities
The building_amenities array controls building-level amenities shared across all units. Each entry has an id and a value: 1 = Active/included ยท 2 = Available, not included ยท 3 = Not available. Providing this field replaces all existing building amenities. Requires building_id, building_name, or number_of_units to be set.
"building_amenities": [
{ "id": 4, "value": 1 },
{ "id": 11, "value": 1 }
]
Building amenity IDs โ complete list
| ID | Building Amenity |
1 | Bike storage |
2 | Concierge |
3 | Electrical car charging station |
4 | Fitness center / gym |
5 | Hot tub |
6 | Sauna |
7 | Steam room |
8 | Swimming pool |
9 | Common areas |
10 | Community laundry |
11 | Elevator |
12 | On-site manager |
Owner Contact
Override the contact information shown on the listing.
| Field | Type | Description |
first_name | string | Contact first name |
last_name | string | Contact last name |
email | string | Contact email |
phone | string | Phone number (digits only, without dial code) |
dial_code | string | Country dial code (e.g. "+1") |
notify_email | boolean | Send email notifications to this contact |
notify_sms | boolean | Send SMS notifications to this contact |
Team Members
Assign team members to the property. Three styles can be mixed in the same array:
json
"team_members": [
{ "team_member_id": 45 },
{ "email": "agent@mycompany.com" },
{
"email": "sara.white@mycompany.com",
"first_name": "Sara",
"last_name": "White",
"role_id": 12,
"is_admin": false,
"timezone": "America/Vancouver"
}
]
โน๏ธOn PUT (update), team member assignments are additive only โ existing assignments are never removed. To remove a member, use the Leasey admin panel. If a new member creation fails, the error appears in team_members.skipped and the property creation itself is not rolled back.
Restrictions
Providing this field replaces all existing restrictions.
| ID | Restriction |
1 | No dogs |
2 | No smoking |
3 | No short-term rentals |
4 | No subletting |
5 | No cats |
Photos
Providing this field replaces all existing photos. Photos are displayed in the order provided; the first photo is used as the main listing image. URLs must start with https://.
"photos": [
{ "url": "https://cdn.example.com/unit2b-main.jpg" },
{ "url": "https://cdn.example.com/unit2b-kitchen.jpg" }
]
Marketplaces
Setting enabled: false unpublishes the listing. Only explicitly listed entries are affected; others retain their current state.
| Name | Platform | Paid |
zillow | Zillow | Free |
zillowMulti | Zillow Multi | Free |
facebook | Facebook Marketplace | Free |
apartmentsStandard | Apartments.com Standard | Free |
apartmentsPremium | Apartments.com Premium | Free |
rentPanda | Rent Panda | Free |
rentalBeast | Rental Beast | Free |
realtor | Realtor.ca | Free |
rentFaster | Rent Faster | Free |
rentSeeker | Rent Seeker | Free |
rew | REW | Free |
lq | LQ | Free |
listanza | Listanza | Free |
rentalSource | Rental Source | Free |
lespac | LesPAC | Free |
zumperPremium | Zumper Premium | Paid |
zumperStandard | Zumper Standard | Paid |
kijiji | Kijiji | Paid |
viewit | View it | Paid |
livRent | Liv Rent | Paid |
craigslist | Craigslist | Paid |
๐ณWhen you enable a paid marketplace, Leasey creates a billing item based on the daily rate configured for your company. Re-sending the same state is safe โ the API is idempotent and will not create duplicate billing entries.
9. Enum Value Reference
โ ๏ธUse only the exact values listed below. Sending an unlisted value (e.g. "condo", "studio", "shared room") will return a 422 validation error.
Unit Type
| Value | Description |
apartment | Apartment (default) |
house | House |
townhouse | Townhouse |
duplex/triplex | Duplex or triplex |
basement suite | Basement suite |
room only | Room only |
other | Other |
Rental Space
| Value | Description |
entire place | Entire place (default) |
partial place | Partial place |
Rent Payment Frequency
| Value | Description |
daily | Daily |
weekly | Weekly |
bi-weekly | Bi-weekly |
monthly | Monthly (default) |
yearly | Yearly |
one-time | One-time |
Renewal Frequency
| Value | Description |
month to month | Month to month (default) |
fixed term | Fixed term lease |
fixed term, renewing month-to-month | Fixed term that renews monthly |
11. Error Reference
| Status | When it occurs |
| 200 | Request processed successfully |
| 201 | Property created successfully |
| 400 | Missing required parameter, malformed JSON, invalid type |
| 401 | Missing or invalid API token or company password |
| 404 | Property not found or does not belong to your company |
| 405 | Wrong HTTP method (e.g. POST on a GET-only endpoint) |
| 422 | Valid JSON but field-level validation failed (e.g. invalid enum value) |
| 500 | Database error or unexpected exception |
Validation Error Format (422)
{
"error": "Unprocessable Entity",
"message": "Validation failed. See 'details' for field-level errors.",
"details": [
"\"name\" is required.",
"\"unit_type\" invalid: \"studio\". Valid values: [\"apartment\", \"house\", ...]"
]
}
12. Code Examples
JavaScript (fetch)
javascript
const authHeaders = {
"Authorization": `Bearer ${API_TOKEN}`,
"X-Company-Password": COMPANY_PASSWORD,
};
// Get showings report
const params = new URLSearchParams({ company_id: COMPANY_ID, start_date: "2024-01-01T00:00:00" });
const res = await fetch(`${BASE_URL}/reports/showings?${params}`, { headers: authHeaders });
const showings = await res.json();
// Create a property
const createRes = await fetch(`${BASE_URL}/properties`, {
method: "POST",
headers: { ...authHeaders, "Content-Type": "application/json" },
body: JSON.stringify({
company_id: COMPANY_ID,
password: COMPANY_PASSWORD,
property: { name: "Unit 2B", address: "456 Oak Ave", city: "Toronto",
province_state: "ON", country: "Canada", rent_amount: "2100", bedrooms: 2, bathrooms: 1 }
}),
});
const { property_id } = await createRes.json(); // Save this!
Python
python
import requests
auth_headers = {
"Authorization": f"Bearer {API_TOKEN}",
"X-Company-Password": COMPANY_PASSWORD,
}
# Get leads report
response = requests.get(f"{BASE_URL}/reports/leads",
headers=auth_headers,
params={"company_id": COMPANY_ID, "start_date": "2024-01-01T00:00:00"})
leads = response.json()
# Create a property
response = requests.post(f"{BASE_URL}/properties",
headers={**auth_headers, "Content-Type": "application/json"},
json={
"company_id": COMPANY_ID, "password": COMPANY_PASSWORD,
"property": { "name": "Unit 2B", "address": "456 Oak Ave", "city": "Toronto",
"province_state": "ON", "country": "Canada", "rent_amount": "2100" }
})
property_id = response.json()["property_id"]
PHP
php
// Get properties report
$ch = curl_init($BASE_URL . "/reports/properties?company_id=" . $COMPANY_ID);
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
"Authorization: Bearer $API_TOKEN",
"X-Company-Password: $COMPANY_PASSWORD",
],
]);
$data = json_decode(curl_exec($ch), true);
curl_close($ch);
// Create a property
$payload = json_encode(["company_id" => $COMPANY_ID, "password" => $COMPANY_PASSWORD,
"property" => ["name" => "Unit 2B", "address" => "456 Oak Ave",
"city" => "Toronto", "province_state" => "ON", "country" => "Canada"]]);
$ch = curl_init($BASE_URL . "/properties");
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true, CURLOPT_POST => true,
CURLOPT_POSTFIELDS => $payload,
CURLOPT_HTTPHEADER => ["Authorization: Bearer $API_TOKEN", "Content-Type: application/json"],
]);
$result = json_decode(curl_exec($ch), true);
curl_close($ch);
13. Testing with Postman
Step 1 โ Get the endpoint URL
cd reports-api-service
serverless info --stage production
Look for the endpoints section. The URL will look like: https://uvciw58bnh.execute-api.ca-central-1.amazonaws.com/production
Step 2 โ Create an environment
| Variable | Value |
base_url | https://uvciw58bnh.execute-api.ca-central-1.amazonaws.com/production |
api_token | Your API token |
company_id | Your company ID (integer, no quotes) |
company_password | Your company API password |
Step 3 โ GET showings
- Method:
GET ยท URL: {{base_url}}/reports/showings
- Params:
company_id โ {{company_id}} ยท start_date โ 2024-01-01T00:00:00
- Headers:
Authorization โ Bearer {{api_token}}
- Headers:
X-Company-Password โ {{company_password}}
- Click Send
Step 4 โ POST property
- Method:
POST ยท URL: {{base_url}}/properties
- Headers:
Authorization โ Bearer {{api_token}} ยท Content-Type โ application/json
- Body โ raw โ JSON: paste your create property payload
- Click Send
14. Troubleshooting
401 โ Token length mismatch
If you see "The provided token does not match the expected token" with a debug field showing token_received_length: 32 and token_expected_length: 48, your token is being truncated. Verify you are copying the full 48-character token โ check for line breaks or truncation in your environment variable or config file.
401 โ Token not working
- Verify
Content-Type: application/json is set.
- Ensure you are using the correct token for the right stage (dev and production tokens are different).
- Check CloudWatch logs:
serverless logs -f reportsApi --stage production --tail
401 โ Company password not working
Confirm the passwordapi field is set in Leasey dashboard โ Settings โ API Access.
400 โ company_id must be an integer
Send as a number: ?company_id=123 โ
?company_id="123" โ. In Postman query params, type the value without quotes.
422 โ Invalid enum value
You sent a value not in the allowed enum list. Common mistakes: "condo", "studio", "loft", "shared room", "private room", "semi-monthly" โ none of these exist. Check the Enum Values section for the exact accepted values.
CORS errors in browser
The API allows all origins. CORS errors are almost always caused by a missing Authorization header triggering a 401 before CORS preflight headers are sent. Check auth headers first.
500 โ Internal Server Error
Check CloudWatch logs for the specific stack trace: serverless logs -f reportsApi --stage production --tail. Common causes: database connection timeout (Lambda cold start), invalid SQL from a malformed date parameter.
15. Best Practices
๐ Security
- Never expose credentials in client-side code
- Use
X-Company-Password header on GET requests - Store token in environment variables
- Rotate your company password periodically
โก Performance
- Use date filters to limit large reports
- Cache properties report for 5โ15 minutes
- Design with a 60-second timeout on the client
๐ Reliability
- Exponential backoff for 5xx (2s, 4s, 8s)
- Handle
null fields โ many are nullable - Store
property_id immediately after creation
๐ Data Consistency
- Photos, features, restrictions replace on update
team_members on PUT is additive only- Dates must be ISO-8601:
YYYY-MM-DDTHH:MM:SS
Support
๐งEmail: helpdesk@leasey.ai ยท Response time: Within 24 business hours
When contacting support include your company_id, the full request (credentials removed), the exact error message, and the time it occurred (UTC).
Leasey External API v2.0 โ ยฉ 2024 Lease.ai. All rights reserved.