Properties API
CRUD endpoints for managing your property listings programmatically.
For image uploads, see Property Images.
List Properties
GET /api/v1/propertiesReturns a paginated list of your non-deleted properties.
Query parameters:
| Parameter | Type | Description |
|---|---|---|
page | integer | Page number (default 1). |
limit | integer | Items per page (default 20, max 100). |
minRent | number | Minimum monthly rent (USD). |
maxRent | number | Maximum monthly rent (USD). |
minBedrooms | integer | Minimum bedrooms. |
minBathrooms | number | Minimum bathrooms (allows 1.5 etc). |
availableBefore | string | ISO date YYYY-MM-DD — only properties available on or before this date. |
petFriendly | true|false | Filter pet-friendly properties. |
hasParking | true|false | Filter properties with parking. |
city | string | Substring match on city. |
Response (200 OK):
{
"data": [
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"address": "123 Main St, Apt 4B, New York, NY 10001",
"monthlyRent": 2500,
"bedrooms": 2,
"bathrooms": 1,
"available": true,
"createdAt": "2026-01-15T10:30:00.000Z"
}
],
"pagination": {
"page": 1,
"limit": 20,
"total": 42,
"totalPages": 3
}
}Create Property
POST /api/v1/propertiesRequest body:
{
"address": "123 Main St, Apt 4B, New York, NY 10001",
"monthlyRent": 2500,
"bedrooms": 2,
"bathrooms": 1,
"description": "Sunny 2BR with updated kitchen and hardwood floors.",
"available": true,
"imageUrls": ["https://example.com/photo1.jpg"]
}imageUrls is optional — if provided, the server queues an async image import and the response includes an imageImport block with a jobId you can poll via GET /properties/:id/images/import/:jobId.
Response (201 Created): Includes a Location: /api/v1/properties/:id header.
{
"data": {
"id": "550e8400-e29b-41d4-a716-446655440000",
"address": "123 Main St, Apt 4B, New York, NY 10001",
"monthlyRent": 2500,
"bedrooms": 2,
"bathrooms": 1,
"available": true,
"createdAt": "2026-01-15T10:30:00.000Z"
}
}Get Property
GET /api/v1/properties/:idResponse (200 OK): { "data": <property> }.
Update Property
PATCH /api/v1/properties/:idSend only the fields you want to update.
Response (200 OK): { "data": <updated property> }.
Delete Property
DELETE /api/v1/properties/:idSoft-delete. Sets deletedAt on the property — the row is hidden from list/get responses but kept in the database for audit and recovery. Returns 204 No Content.
Bulk Create Properties
POST /api/v1/properties/bulkSubmit up to 500 properties in a single request. Processing happens asynchronously — you get a job ID back immediately.
Field names are flexible. You can use camelCase (monthlyRent, bedrooms) or common alternatives from property management tools (rent, beds, street_address, monthly_rent, etc.). Values like "$1,500", "3 BR", and "yes" are coerced automatically. Unknown fields are surfaced in the job result as unmappedFields.
Requires: Pro or Scale plan.
Request body:
{
"properties": [
{ "street": "123 Main St", "rent": 1500, "beds": 2, "baths": 1, "city": "Austin" },
{ "address": "456 Oak Ave", "monthlyRent": 2000, "bedrooms": 3, "bathrooms": 2 }
]
}Supports Idempotency-Key header.
Response (202 Accepted):
{
"data": {
"jobId": "550e8400-e29b-41d4-a716-446655440000",
"status": "pending",
"total": 2
}
}Get Bulk Import Job Status
GET /api/v1/properties/bulk/:jobIdPoll this endpoint to check progress. You can also subscribe to the bulk_import.completed webhook event.
Response (200 OK):
{
"data": {
"jobId": "550e8400-e29b-41d4-a716-446655440000",
"status": "completed",
"total": 100,
"created": 95,
"failed": 5,
"createdPropertyIds": ["id1", "id2", "..."],
"unmappedFields": ["custom_field_x", "internal_id"],
"errors": [
{ "row": 3, "field": "monthlyRent", "message": "Required", "code": "validation" },
{ "row": 98, "message": "Property limit exceeded (100 max for pro plan)", "code": "capacity" }
],
"createdAt": "2026-02-19T10:00:00.000Z",
"completedAt": "2026-02-19T10:00:05.000Z"
}
}status is one of pending, processing, completed, failed.