Skip to contentSkip to Content
API ReferenceProperties

Properties API

CRUD endpoints for managing your property listings programmatically.

For image uploads, see Property Images.

List Properties

GET /api/v1/properties

Returns a paginated list of your non-deleted properties.

Query parameters:

ParameterTypeDescription
pageintegerPage number (default 1).
limitintegerItems per page (default 20, max 100).
minRentnumberMinimum monthly rent (USD).
maxRentnumberMaximum monthly rent (USD).
minBedroomsintegerMinimum bedrooms.
minBathroomsnumberMinimum bathrooms (allows 1.5 etc).
availableBeforestringISO date YYYY-MM-DD — only properties available on or before this date.
petFriendlytrue|falseFilter pet-friendly properties.
hasParkingtrue|falseFilter properties with parking.
citystringSubstring 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/properties

Request 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/:id

Response (200 OK): { "data": <property> }.

Update Property

PATCH /api/v1/properties/:id

Send only the fields you want to update.

Response (200 OK): { "data": <updated property> }.

Delete Property

DELETE /api/v1/properties/:id

Soft-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/bulk

Submit 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/:jobId

Poll 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.