Integrate your CRM with ListStream. Follow the guide
For CRMs and platforms

Send listings for every agency you serve. One API, or the REAXML you already make.

For CRMs, website providers and integrators that handle many agencies. Each agency approves you once; after that you send its listings with JSON or REAXML, and ListStream publishes them. Here is exactly what we accept and how it behaves. Reading listings instead? See For AI and search.

Quickstart

  1. Create a developer account in the developer console and a test key. Note your sandbox ID (SB and four letters).
  2. Get an access token (it lasts an hour; reuse it):
curl -s https://liststream.com.au/oauth/token \
  -u "$CLIENT_ID:$CLIENT_SECRET" -d grant_type=client_credentials
# → { "access_token": "…", "token_type": "Bearer", "expires_in": 3600 }
  1. Send a listing to your sandbox ID. It's checked and reported, never published:
curl -s -X PUT https://liststream.com.au/v1/listings/$SANDBOX_ID/SAMPLE-1 \
  -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
  -d '{"type":"residential","status":"current","modifiedAt":"2026-11-10T09:30:00+10:00",
       "address":{"streetNumber":"12","street":"Sample Street","suburb":"Eumundi","state":"QLD","postcode":"4562"},
       "headline":"Sample home","price":{"text":"Offers over $750,000"},
       "agents":[{"name":"Jordan Hale","mobile":"0491 570 156"}]}'
# → 202 { "deliveryId": "…", "status": "queued", "report": "https://liststream.com.au/v1/deliveries/…" }
  1. Read the report at the report URL in the answer, or add a webhook in the console and wait for delivery.completed.
  2. When it all works, create a live key and ask each agency to connect (Connections). Every endpoint is in the API reference.

The ListStream API

For CRMs, website platforms and integrators. Send listings as JSON, or as REAXML through an endpoint shaped like realestate.com.au's Listing Upload API, so existing REA integration code can point at ListStream with few changes. Every delivery gets a per-listing report. There are no integration fees.

Base URL
https://liststream.com.au
Keys
Create them in the developer console: test keys straight away, live keys whenever you're ready.
Specification
OpenAPI 3.1, for code generators and API tools.
Errors
JSON { error: { code, message, fields? } }, with field-by-field messages for invalid listings (422). Fields ListStream doesn't know are refused, so a typo is never silently ignored. /oauth/token answers in the OAuth format, { error, error_description }.
Rate limit
300 requests a minute per account and environment (429, with Retry-After), plus the delivery limits below.

Keys and tokens

OAuth 2.0 client credentials. Exchange your client ID and secret for an access token that lasts an hour, and send it as a Bearer token. Revoking a key in the console stops its tokens working.

POST https://liststream.com.au/oauth/token
Authorization: Basic base64(<client_id>:<client_secret>)
Content-Type: application/x-www-form-urlencoded

grant_type=client_credentials

200 OK
{ "access_token": "eyJ...", "token_type": "Bearer", "expires_in": 3600 }

Test mode

Test keys (ls_test_...) only accept listings with your account's sandbox agent ID (SB plus four letters, shown in the console). Deliveries go through the same checks as live ones and get the same kind of report, but nothing is published and no listing is kept, so a test status change or removal is reported as skipped. Test delivery reports are kept for 90 days, like live ones. Live keys (ls_live_...) publish, and only for agencies that have approved a connection to you.

Sending listings

JSON. PUT the whole listing to create or replace it. modifiedAt is when it last changed in your system; an update older than what ListStream holds is ignored. All times are ISO 8601 with a time zone (Z or +10:00); inspection and auction times are shown in the property's local time. With price.show: false (or rent.show: false), neither the price figure nor the price text is published. Up to 36 photos. Send each feature as its own item (commas inside one are kept). bedrooms: 0 is shown only for the Studio category. Change just the status with POST .../status, and remove a listing with DELETE.

PUT https://liststream.com.au/v1/listings/<ListStream ID>/<your listing ID>
Authorization: Bearer eyJ...
Content-Type: application/json

{
  "type": "residential",
  "status": "current",
  "modifiedAt": "2026-11-10T09:30:00+10:00",
  "address": { "streetNumber": "1", "street": "Sample Street", "suburb": "Eumundi", "state": "QLD", "postcode": "4562" },
  "headline": "Sample home",
  "price": { "text": "Offers over $700,000" },
  "bedrooms": 3, "bathrooms": 2,
  "agents": [ { "name": "Jordan Hale", "mobile": "0491 570 156" } ],
  "photos": [ { "url": "https://samplecrm.example/photos/1.jpg" } ]
}

202 Accepted
{ "deliveryId": "6f86c062-...", "status": "queued",
  "report": "https://liststream.com.au/v1/deliveries/6f86c062-..." }

REAXML. One document or a zip with photos, up to 20 MB, with the same report shape as realestate.com.au's Listing Upload API. Results: NEW, PROCESSED, DELETED, UNCHANGED, SKIPPED.

POST https://liststream.com.au/listing/v1/upload
Authorization: Bearer eyJ...
Content-Type: application/xml

<propertyList>...</propertyList>

202 Accepted
{ "uploadId": "b8476b79-..." }

GET https://liststream.com.au/listing/v1/upload/b8476b79-...

{ "uploadId": "b8476b79-...", "progress": "COMPLETED", "result": "NEW",
  "agencyId": "FINCHM", "externalListingId": "EX-3", "issues": { "errors": [], "warnings": [] } }

The latest report for one listing: GET /listing/v1/upload?agencyId=...&externalListingId=.... The ListStream report for any delivery: GET /v1/deliveries/{id}.

Webhooks

Set an endpoint per environment in the console. We send delivery.completed when a delivery has been processed, and connection.approved and connection.revoked when an agency changes its connection to you. Each request carries ListStream-Event-Id (the same on every retry, so you can ignore duplicates) andListStream-Signature: t=...,v1=..., an HMAC-SHA256 of <t>.<raw body> with your endpoint secret. A delivery that can't be processed also sends delivery.completed, with status: "failed".

// Node.js: check a webhook came from ListStream
import { createHmac, timingSafeEqual } from "node:crypto";

function verify(rawBody, header, secret) {           // header: ListStream-Signature
  const parts = Object.fromEntries(String(header ?? "").split(",").map((p) => p.trim().split("=", 2)));
  const t = Number(parts.t), v1 = parts.v1;
  if (!Number.isFinite(t) || typeof v1 !== "string") return false;
  if (Math.abs(Date.now() / 1000 - t) > 300) return false;          // older than 5 minutes
  const expected = createHmac("sha256", secret).update(`${parts.t}.${rawBody}`).digest("hex");
  return v1.length === expected.length && timingSafeEqual(Buffer.from(expected), Buffer.from(v1));
}

Answer with any 2xx within 10 seconds. Anything else is retried with growing gaps for up to 3 days. Events may arrive out of order, and occasionally more than once. Events from the last 3 days that had no endpoint to go to are sent when you add one.

Connections

A live key can only send an agency's listings after the agency approves. Ask with POST /v1/connections and the agency's six-letter ListStream ID (ask the agency for it); it appears in the agency's dashboard to approve, and you get a connection.approved webhook. A valid six-letter ID always gets 202 (so the answer doesn't reveal whether an agency exists), and GET /v1/connections shows a request as pending until the agency approves, whether or not the ID exists. The agency's name appears once approved. A connection the agency revokes stays revoked unless the agency approves it again. Up to 100 new requests a day. ListStream never approves on an agency's behalf.

How listings are matched

  • Agency, then your reference. A listing is the agency's ListStream ID plus your own listing reference (uniqueID, or the id in the API path). Send changes with the same reference and the same listing updates; the newest modTime / modifiedAt wins.
  • Agents belong to agencies. Listings are always published under the agency. Agents are the people named on a listing (up to 5 in JSON; the lead agent first, or listingAgent id="1" in REAXML).
  • One address, one current listing per agency. If an agency already has a current listing at the same address under another reference, a new one is skipped with a message naming the existing reference. A listing that came from a hand upload in the dashboard is replaced by yours instead.
  • Several campaigns per property. Other agencies, or a later campaign after a sale, are kept as separate listings. An old page links to the current one; a current page lists past campaigns, with other agencies' shown as facts only. You never see another agency's listings through the API.

REAXML in

We follow the REAXML propertyList DTD (revision 1.65). Listings arrive by FTP or SFTP, HTTPS push, a feed URL we check hourly, or a file uploaded in the dashboard (up to 20 MB). Sending a listing again updates it, matched on agentID and uniqueID.

Listing types
residential, land, rural and rental. Commercial, commercial land, business and holiday rental are skipped for now, with a reason shown.
Statuses
current, sold, leased, withdrawn, off market and deleted. Sold and leased stay visible as marked; withdrawn, off market and deleted are hidden.
agentID
Must be the agency's six-letter ListStream ID. Listings with any other agent ID are skipped, so no one can change another agency's listings.
Required
uniqueID, modTime, and a suburb and state in the address.
Price
The advertised price text (price view) is shown as written. A price figure marked hidden (display="no") is never published.
Privacy
Vendor details are removed when a file is processed and are never published.

FTP and SFTP

Send REAXML the way you already send it to the portals. Each agency creates its feed login in its ListStream dashboard (Connections) and gives it to you.

Host
feeds.liststream.com.au
Protocols
Explicit FTPS (AUTH TLS) on port 21, passive mode; SFTP on port 22. Plain FTP works only if the agency turns it on in its dashboard, using the login name with -plain added.
Login
ls- plus the agency's ListStream ID in lower case, with the password from the agency's dashboard.
Files
REAXML .xml, or a .zip with the XML and its photos. Photos can also be uploaded as separate files before the XML that names them. Up to 20 MB per file.
Temporary names
Files ending in .tmp, .part or .filepart are ignored until renamed.
Result
A file is accepted when the upload completes; the agency sees each listing's result in its dashboard. Uploaded files don't stay on the server.

HTTPS push

For systems that send over HTTPS. The agency issues a push token in its dashboard; send it as a Bearer token. The body is a REAXML document (application/xml) or a zip (application/zip), or a multipart file field.

POST https://liststream.com.au/api/feeds/push
Authorization: Bearer lsf_...
Content-Type: application/xml

<propertyList>...</propertyList>

202 Accepted
{ "id": "6f86c062-...", "status": "queued",
  "report": "https://liststream.com.au/api/feeds/deliveries/6f86c062-..." }

GET https://liststream.com.au/api/feeds/deliveries/6f86c062-...
Authorization: Bearer lsf_...

{ "status": "done",
  "counts": { "new": 1, "updated": 0, "unchanged": 0, "skipped": 0 },
  "items": [ { "uniqueId": "EX-1", "agentId": "EXAMPL", "result": "new", "listingId": "..." } ],
  "errors": [] }

The report lists every listing in the delivery with its result: new, updated, unchanged, removed or skipped, and a message when it was skipped.

Limits

File size
20 MB per file or request (413 above that). Zips may unpack to at most 25 MB per file, 80 MB in total and 3,000 files.
Deliveries
600 per agency per hour, across all channels, including API deliveries for a single agency (429 above that). Dashboard uploads take up to 20 files at a time.
API
300 requests a minute per account and environment, and the same for access tokens per key.
New listings
2,000 per agency per day. Agencies awaiting review: 50 per day, and their pages aren't offered to search engines until approved.
Photos
The first 30 photos of each listing are copied and resized for its page; any more stay as the CRM's own links.

Getting started

The quickest route is the API: create an account in the developer console, build against test mode, then ask agencies to connect. If you'd rather keep sending files, each agency gets its feed details on the Connections page of its dashboard: an FTP or SFTP login (see FTP and SFTP), or an HTTPS push token (see HTTPS push). Use the agency's ListStream ID as the agent ID. There are no integration fees. Questions: hello@liststream.com.au.

Agencies have their own guide: For agencies and agents. To read listings (JSON, structured data, llms.txt), see For AI and search.