Land-Listings.com API
The Land-Listings.com API allows approved Deluxe advertisers to integrate their property inventory with Land-Listings.com.
API access is managed by Land-Listings.com and is available to approved Deluxe advertisers. Contact Land-Listings.com to request API access.
What can I do with the API?
Export your inventory
Retrieve your own Land-Listings.com listings for use in your website, CRM, or another system.
Import and maintain listings
Send new listings to Land-Listings.com and keep property information updated automatically.
Manage listing media
Upload and manage listing images and PDF documents without entering them manually through the website.
You can send this documentation to the person or company that manages your website, CRM, listing-management software, or other property system. The technical integration instructions begin below.
Overview
Base URL: https://api.land-listings.com/v1. HTTPS is required. API credentials belong to one Land-Listings account and can access or manage only listings, images, and documents owned by that account.
Read / Export API (stored scope: read_feed) allows the customer's system to retrieve their own Land-Listings inventory for use in an external website, CRM, or other system. Write / Import API (stored scope: write_feed) allows the customer's system to create and update listings on Land-Listings.com and manage supported listing images and documents. Normal full API access includes both permissions.
Integration walkthrough
- Receive the managed API credential issued for your approved Deluxe account.
- Authenticate every request with the Bearer token.
- POST a listing with your stable
external_listing_id. - Read
LISTING_IDfromdata.id. - Store the association between your
external_listing_idandLISTING_ID. - PATCH that
LISTING_IDwhen an intentional listing change is needed. - Upload an image and read
IMAGE_IDfromdata.image.id. - Use
IMAGE_IDto set primary, reorder, or delete images. - Upload a PDF and read
DOCUMENT_IDfromdata.document.id. - Use
DOCUMENT_IDto update its description or delete it.
Authentication
Send the secret token using Bearer authentication. The compatibility header X-Api-Token is also supported. Keep credentials secret. The read_feed scope is the Read / Export API permission: it allows customers to pull their own Land-Listings inventory and reference data for use in an external website, CRM, or other system. The write_feed scope is the Write / Import API permission: it allows customers to push and maintain inventory on Land-Listings.com, including supported listings, images, and documents. GET /v1/listings requires read_feed or wildcard scope. Listing writes and every image/document route—including asset GET routes—require write_feed or wildcard scope and current Deluxe entitlement.
Authorization: Bearer YOUR_API_TOKEN
# Compatibility alternative:
X-Api-Token: YOUR_API_TOKEN
County taxonomy
County values come from Land-Listings' authoritative state/county taxonomy. This reference endpoint requires a valid managed API credential with read_feed or wildcard scope; current Deluxe entitlement is not required for this read-only lookup. The required state query value is a supported state or territory abbreviation. An invalid state returns HTTP 422 with validation_failed.
The response contains distinct canonical names in alphabetical order. Use one of these exact values for listing county. County identity is always state-specific; no county-table ID is exposed or accepted.
curl -H "Authorization: Bearer YOUR_API_TOKEN" \
"https://api.land-listings.com/v1/counties?state=TX"
HTTP/1.1 200 OK
{"success":true,"data":{"state":"TX","counties":["Anderson","Andrews","Angelina"]},"error":null,"meta":{"request_id":"...","version":"v1","resource":"counties","timestamp":"...","pagination":null},"links":{"self":"https://api.land-listings.com/v1/counties?state=TX"},"message":"Counties retrieved"}
Quick start — create a complete listing
This example creates a reasonably complete property using only fields supported by POST /v1/listings. Before submitting a county, retrieve Land-Listings' accepted canonical county values with GET /v1/counties?state=TX. Do not guess county spelling or formatting. The API validates county against state and stores the canonical Land-Listings value. Travis is used below as a canonical Texas example.
curl -X POST "https://api.land-listings.com/v1/listings" \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"external_listing_id": "LANDVILLE-10025",
"title": "40.25 Acres Near Austin, Texas",
"description": "40.25 acres of rural land with road access and open views.",
"price": 125000,
"acres": 40.25,
"owner_financing": true,
"general_location": "Approximately 8 miles north of Austin",
"address": "123 County Road 100",
"city": "Austin",
"state": "TX",
"county": "Travis",
"postal_code": "78701",
"has_residence": false,
"mls_number": "MLS-123456",
"latitude": 30.3456,
"longitude": -97.7431,
"map_zoom": 14,
"directions": "From Austin, travel north and follow County Road 100 to the property.",
"custom_map_url": null,
"video_url": null,
"video_as_header": false
}'
Successful creation
HTTP/1.1 201 Created
{
"success": true,
"data": {
"id": 123,
"external_listing_id": "LANDVILLE-10025",
"status": "Active",
"url": "https://land-listings.com/listing/123",
"created_at": "2026-09-23T12:00:00+00:00",
"updated_at": "2026-09-23T12:00:00+00:00"
},
"error": null,
"meta": {
"request_id": "EXAMPLE_REQUEST_ID",
"version": "v1",
"resource": "listings",
"timestamp": "2026-09-23T12:00:00+00:00",
"pagination": null,
"idempotent_replay": false
},
"links": {"self": "https://api.land-listings.com/v1/listings"},
"message": "Listing created"
}
data.id is your LISTING_ID. Save this LISTING_ID. You will use it to PATCH the listing, upload images, and upload documents. Also retain the association between your own external_listing_id and the returned LISTING_ID.Next steps
- Create the listing and receive
LISTING_ID. - Upload images using
LISTING_ID. - Receive an
IMAGE_IDfor each uploaded image. - Set the primary image or reorder images if desired.
- Upload PDFs using
LISTING_ID. - Receive a
DOCUMENT_IDfor each uploaded document. - PATCH the listing whenever property information changes.
Listings
Query parameters: page defaults to 1; per_page defaults to 25 and is constrained to 1–100; updated_after accepts a parseable date/time such as ISO 8601 and includes listings updated at or after that time.
curl -H "Authorization: Bearer YOUR_API_TOKEN" \
"https://api.land-listings.com/v1/listings?per_page=25&page=1&updated_after=2026-01-01T00:00:00Z"
{
"success": true,
"data": {
"items": [{"id": 123, "title": "20 acres", "price": 75000, "slug": "20-acres", "is_active": true, "created_at": "...", "updated_at": "..."}],
"total": 1, "per_page": 25, "current_page": 1, "last_page": 1
},
"error": null,
"meta": {"request_id": "...", "version": "v1", "resource": "listings", "timestamp": "...", "pagination": {"total": 1, "per_page": 25, "current_page": 1, "last_page": 1}}
}
curl -X POST "https://api.land-listings.com/v1/listings" \
-H "Authorization: Bearer YOUR_API_TOKEN" -H "Content-Type: application/json" \
-d '{"external_listing_id":"ABC123","title":"20 acres in Oklahoma","description":"Rural land with road access.","state":"OK","price":75000,"acres":20}'
external_listing_id is a customer-supplied, stable, case-sensitive synchronization identity scoped to your Land-Listings account. It is different from both mls_number and the Land-Listings data.id. Different API accounts may use the same external ID.
Repeated POST requests with the same external_listing_id for the same account return the existing listing unchanged. They do not create a duplicate or overwrite it. Use PATCH for intentional updates.
A new listing returns 201 Created. A retry returns 200 OK with the same resource and meta.idempotent_replay set to true. Read the Land-Listings identifier from data.id; use it as LISTING_ID in listing, image, and document routes.
New create — HTTP/1.1 201 Created
{
"success": true,
"data": {"id": 123, "external_listing_id": "ABC123", "status": "Active", "url": "https://land-listings.com/listing/123", "created_at": "...", "updated_at": "..."},
"error": null,
"meta": {"request_id": "...", "version": "v1", "resource": "listings", "timestamp": "...", "idempotent_replay": false}
}
Same external_listing_id retry — HTTP/1.1 200 OK
{
"success": true,
"data": {"id": 123, "external_listing_id": "ABC123", "status": "Active", "url": "https://land-listings.com/listing/123", "created_at": "...", "updated_at": "..."},
"error": null,
"meta": {"request_id": "...", "version": "v1", "resource": "listings", "timestamp": "...", "idempotent_replay": true}
}
Create field contract
| Field | Type | Requirement / null | Important validation |
|---|---|---|---|
| external_listing_id | string | Required, not null | 1–128 characters; trimmed; no control characters; case-sensitive identity |
| title | string | Required, not null | Nonblank; maximum 255 |
| description | string | Required, not null | Nonblank; maximum 50,000 characters and 65,535 encoded bytes |
| price | integer | Optional, nullable | 0 or greater |
| acres | number | Optional, nullable | Greater than 0; maximum two decimal places |
| owner_financing | boolean | Optional; defaults false | Boolean |
| general_location | string | Optional, nullable | Maximum 255 |
| address | string | Optional, nullable | Maximum 128 |
| city | string | Optional, nullable | Maximum 128 |
| state | string | Required, not null | Supported US state/territory abbreviation; normalized uppercase |
| county | string | Optional, nullable | Must match the listing state's canonical Land-Listings county taxonomy; surrounding whitespace and casing are normalized, and the canonical value is stored |
| postal_code | string | Optional, nullable | Five-digit ZIP or ZIP+4; leading zeroes preserved |
| has_residence | boolean | Optional; defaults false | Residence details require true |
| bedrooms | integer | Optional, nullable | 0–99; residence listings only |
| bathrooms | integer | Optional, nullable | 0–99; residence listings only |
| half_bathrooms | integer | Optional, nullable | 0–99; residence listings only |
| square_feet | integer | Optional, nullable | 1–2,147,483,647; residence listings only |
| mls_number | string | Optional, nullable | Maximum 128; not the synchronization key |
| latitude | number | Optional, nullable | −90 to 90; latitude and longitude supplied together |
| longitude | number | Optional, nullable | −180 to 180; latitude and longitude supplied together |
| map_zoom | integer | Optional; defaults 18 | 0–20 |
| directions | string | Optional, nullable | Maximum 20,000 |
| custom_map_url | string | Optional, nullable | HTTPS Google Maps Embed, id.land, mapright.com, or uc.mapright.com URL |
| video_url | string | Optional, nullable | HTTPS YouTube watch/embed/short URL or Vimeo video URL |
| video_as_header | boolean | Optional; defaults false | True requires a valid video URL |
For maps and videos, supply a supported HTTPS URL. Do not send iframe or script HTML.
Omitted fields remain unchanged. Explicit null clears nullable fields and explicit false sets a boolean false. The update fields are the create fields above except external_listing_id. Ownership, external identity, and status cannot be changed.
PATCH nullability: price, acres, general_location, address, city, county, postal_code, bedrooms, bathrooms, half_bathrooms, square_feet, mls_number, latitude, longitude, map_zoom, directions, custom_map_url, and video_url may be cleared with null. title, description, state, owner_financing, has_residence, and video_as_header cannot be null. Coordinates must resolve to either a complete pair or both null. Setting has_residence false clears residence details. Clearing video_url also makes video_as_header false.
| PATCH field | Type | Nullable? | Validation and explicit-null behavior |
|---|---|---|---|
| title | string | No | Nonblank, maximum 255 |
| description | string | No | Nonblank, maximum 50,000 characters and 65,535 encoded bytes |
| price | integer | Yes | 0 or greater; null clears |
| acres | number | Yes | Greater than 0, up to two decimals; null clears |
| owner_financing | boolean | No | False explicitly disables owner financing |
| general_location | string | Yes | Maximum 255; null clears |
| address | string | Yes | Maximum 128; null clears |
| city | string | Yes | Maximum 128; null clears |
| state | string | No | Supported abbreviation, normalized uppercase |
| county | string | Yes | Must resolve in the resulting state; canonical value stored; null clears |
| postal_code | string | Yes | ZIP or ZIP+4; null clears |
| has_residence | boolean | No | False clears all four residence-detail fields |
| bedrooms | integer | Yes | 0–99 and resulting residence must be true; null clears |
| bathrooms | integer | Yes | 0–99 and resulting residence must be true; null clears |
| half_bathrooms | integer | Yes | 0–99 and resulting residence must be true; null clears |
| square_feet | integer | Yes | 1–2,147,483,647 and resulting residence must be true; null clears |
| mls_number | string | Yes | Maximum 128; null clears |
| latitude | number | Yes | −90 to 90; final coordinates must be paired; null clears only with null longitude |
| longitude | number | Yes | −180 to 180; final coordinates must be paired; null clears only with null latitude |
| map_zoom | integer | Yes | 0–20; null clears |
| directions | string | Yes | Maximum 20,000; null clears |
| custom_map_url | HTTPS URL | Yes | Supported map provider only; null clears the custom map |
| video_url | HTTPS URL | Yes | YouTube/Vimeo only; null removes seller video and disables header video |
| video_as_header | boolean | No | True requires a valid resulting video; false explicitly disables it |
PATCH validates the final state/county pair. Supplying county resolves it against the resulting state. If state changes while county is omitted, an existing county is retained only when it remains valid in the new state; otherwise county is cleared. Arbitrary county strings and counties belonging only to another state return validation_failed without changing the listing.
The API rejects external_listing_id, user_id, ownership, status, membership, billing, promotion, timestamp, generated-video, and other internal fields on PATCH.
curl -X PATCH "https://api.land-listings.com/v1/listings/LISTING_ID" \
-H "Authorization: Bearer YOUR_API_TOKEN" -H "Content-Type: application/json" \
-d '{"price":72500,"owner_financing":false}'
HTTP/1.1 200 OK
{"success":true,"data":{"id":123,"external_listing_id":"ABC123","status":"Active","url":"https://land-listings.com/listing/123","created_at":"...","updated_at":"..."},"error":null,"meta":{"request_id":"...","version":"v1","resource":"listings","timestamp":"...","idempotent_replay":false}}
Images
Images use one multipart upload per request. Field name: image. JPEG/JPG, PNG, and GIF are supported. A Deluxe listing may store 100 images.
Technical maximum: 10,485,760 bytes per image.
- GET /v1/listings/{listing}/images
- POST /v1/listings/{listing}/images
- DELETE /v1/listings/{listing}/images/{image}
- PATCH /v1/listings/{listing}/images/{image}/primary
- PATCH /v1/listings/{listing}/images/order
curl -H "Authorization: Bearer YOUR_API_TOKEN" \
"https://api.land-listings.com/v1/listings/LISTING_ID/images"
curl -X POST "https://api.land-listings.com/v1/listings/LISTING_ID/images" \
-H "Authorization: Bearer YOUR_API_TOKEN" -F "image=@property.jpg"
curl -X PATCH -H "Authorization: Bearer YOUR_API_TOKEN" \
"https://api.land-listings.com/v1/listings/LISTING_ID/images/IMAGE_ID/primary"
curl -X PATCH "https://api.land-listings.com/v1/listings/LISTING_ID/images/order" \
-H "Authorization: Bearer YOUR_API_TOKEN" -H "Content-Type: application/json" \
-d '{"image_ids":[IMAGE_ID]}'
curl -X DELETE -H "Authorization: Bearer YOUR_API_TOKEN" \
"https://api.land-listings.com/v1/listings/LISTING_ID/images/IMAGE_ID"
Reordering requires the complete, duplicate-free collection of image IDs belonging to that listing.
Image list responses return data.items, data.count, and data.maximum. Each item contains id, listing_id, primary, display_order, and urls for large, medium, small, and thumbnail variants. Upload returns the new item at data.image; use data.image.id as IMAGE_ID. Primary returns the updated image item. Reorder returns the complete image-list response. Delete returns data.id, data.listing_id, and data.deleted=true.
Image response examples
GET list — 200 OK
{"success":true,"data":{"items":[{"id":44,"listing_id":123,"primary":true,"display_order":1,"urls":{"large":"...","medium":"...","small":"...","thumbnail":"..."}}],"count":1,"maximum":100},"error":null,"meta":{"request_id":"...","version":"v1","resource":"listings","timestamp":"..."}}
POST upload — 201 Created
{"success":true,"data":{"image":{"id":44,"listing_id":123,"primary":false,"display_order":1,"urls":{"large":"...","medium":"...","small":"...","thumbnail":"..."}},"count":1,"maximum":100},"error":null,"meta":{"request_id":"...","version":"v1","resource":"listings","timestamp":"..."}}
PATCH primary — 200 OK
{"success":true,"data":{"id":44,"listing_id":123,"primary":true,"display_order":1,"urls":{"large":"...","medium":"...","small":"...","thumbnail":"..."}},"error":null,"meta":{"request_id":"...","version":"v1","resource":"listings","timestamp":"..."}}
PATCH order — 200 OK
{"success":true,"data":{"items":[{"id":44,"listing_id":123,"primary":true,"display_order":1,"urls":{"large":"...","medium":"...","small":"...","thumbnail":"..."}}],"count":1,"maximum":100},"error":null,"meta":{"request_id":"...","version":"v1","resource":"listings","timestamp":"..."}}
DELETE — 200 OK
{"success":true,"data":{"id":44,"listing_id":123,"deleted":true},"error":null,"meta":{"request_id":"...","version":"v1","resource":"listings","timestamp":"..."}}
Documents
Documents use one multipart upload per request. Field name: document; optional field description. PDF is the only supported type, descriptions are limited to 250 characters, and a Deluxe listing may store five documents.
Technical maximum: 6,000,000 bytes per PDF.
- GET /v1/listings/{listing}/documents
- POST /v1/listings/{listing}/documents
- PATCH /v1/listings/{listing}/documents/{document}
- DELETE /v1/listings/{listing}/documents/{document}
curl -H "Authorization: Bearer YOUR_API_TOKEN" \
"https://api.land-listings.com/v1/listings/LISTING_ID/documents"
curl -X POST "https://api.land-listings.com/v1/listings/LISTING_ID/documents" \
-H "Authorization: Bearer YOUR_API_TOKEN" -F "document=@survey.pdf" -F "description=Property survey"
curl -X PATCH "https://api.land-listings.com/v1/listings/LISTING_ID/documents/DOCUMENT_ID" \
-H "Authorization: Bearer YOUR_API_TOKEN" -H "Content-Type: application/json" \
-d '{"description":"Updated survey"}'
curl -X DELETE -H "Authorization: Bearer YOUR_API_TOKEN" \
"https://api.land-listings.com/v1/listings/LISTING_ID/documents/DOCUMENT_ID"
Document list responses return data.items, data.count, and data.maximum. Each item contains id, listing_id, description, type, public url, created_at, and updated_at. Upload returns the new item at data.document; use data.document.id as DOCUMENT_ID. Description update returns the updated document item. Delete returns data.id, data.listing_id, and data.deleted=true.
Document response examples
GET list — 200 OK
{"success":true,"data":{"items":[{"id":77,"listing_id":123,"description":"Property survey","type":"pdf","url":"...","created_at":"...","updated_at":"..."}],"count":1,"maximum":5},"error":null,"meta":{"request_id":"...","version":"v1","resource":"listings","timestamp":"..."}}
POST upload — 201 Created
{"success":true,"data":{"document":{"id":77,"listing_id":123,"description":"Property survey","type":"pdf","url":"...","created_at":"...","updated_at":"..."},"count":1,"maximum":5},"error":null,"meta":{"request_id":"...","version":"v1","resource":"listings","timestamp":"..."}}
PATCH description — 200 OK
{"success":true,"data":{"id":77,"listing_id":123,"description":"Updated survey","type":"pdf","url":"...","created_at":"...","updated_at":"..."},"error":null,"meta":{"request_id":"...","version":"v1","resource":"listings","timestamp":"..."}}
DELETE — 200 OK
{"success":true,"data":{"id":77,"listing_id":123,"deleted":true},"error":null,"meta":{"request_id":"...","version":"v1","resource":"listings","timestamp":"..."}}
Responses & Errors
Successful resource responses use the standard envelope below. Endpoint examples above show the exact endpoint-specific data fields. Every standard response also contains meta.pagination (null for non-paginated responses), links.self, and the operation’s message. Timestamps and generated URLs are abbreviated with ... only for readability. Some authentication and rate-limit failures intentionally use a smaller response.
{"success":true,"data":{},"error":null,"meta":{"request_id":"...","version":"v1","resource":"listings","timestamp":"...","pagination":null},"links":{"self":"https://api.land-listings.com/v1/..."},"message":"Operation completed"}
{"success":false,"data":{},"error":{"code":"validation_failed","message":"The request data is invalid.","details":{}},"meta":{"request_id":"...","version":"v1","resource":"listings","timestamp":"..."}}
| Status | Condition | Actual code/response |
|---|---|---|
| 401 | Missing or invalid credential | missing_token or invalid_token is retained in safe request logs; response message identifies missing/invalid token |
| 403 | Write scope missing | insufficient_scope |
| 403 | Current Deluxe required | deluxe_required |
| 404 | Missing or non-owned resource | resource_not_found |
| 409 | External ID belongs to a soft-deleted listing | external_listing_id_retired |
| 409 | Unexpected create integrity conflict | integrity_failure |
| 422 | Request validation | validation_failed |
| 422 | Listing could not be activated | listing_activation_failed |
| 422 | Unsafe image dimensions | unsafe_image_dimensions |
| 422 | Image capacity reached | image_limit_reached |
| 422 | Invalid/incomplete image reorder | invalid_image_order |
| 422 | Document capacity reached | document_limit_reached |
| 500 | Safe internal listing failure | internal_error |
| 500 | Safe internal asset failure | image_operation_failed or document_operation_failed |
| 429 | Client rate limit | {"message":"Too Many Attempts."} plus Retry-After |
Limits
- 120 requests per minute per API client
- 100 images per Deluxe listing; recommended file size 5 MB or less; technical maximum 10,485,760 bytes per image
- 5 PDF documents per Deluxe listing; recommended file size 3 MB or less; technical maximum 6,000,000 bytes per PDF