Skip to main content

REAXML API feeds

Use FeedSync's Upload API to send individual REAXML listings from a CRM or another server-side integration. Uploads are processed asynchronously, and every accepted request returns an ID that can be used to retrieve its processing report.

The Uploads OpenAPI reference is the machine-readable contract for endpoints, request formats, response fields, and HTTP status codes.

A CRM delivering listings for several agencies can hold one credential for all of them instead of one per feed — see CRM API accounts.

Operations​

MethodFeedSync pathBehavior
POST/api/v1/listing/v1/uploadAccept one REAXML listing and return 202 plus uploadId.
GET/api/v1/listing/v1/upload/{uploadId}Return the processing report.
GET/api/v1/listing/v1/upload?agencyId=…&externalListingId=…Search reports by REAXML agentID and uniqueID.

Provision credentials​

Create one OAuth client per external system and target feed:

  1. Open OAuth Clients at /oauth-clients or from the feed's OAuth tab.
  2. Select the provider and feed and grant listing:listings:write.
  3. Copy the client ID and client secret when displayed.
  4. Store the secret in a secret manager or encrypted server configuration.

Never place credentials in frontend JavaScript, mobile code, URLs, source control, screenshots, or normal request logs.

Request a bearer token​

Request a token with OAuth client credentials:

The client ID and client secret are integration credentials, not a FeedSync username and password. HTTP Basic authentication calls its two credential slots “username” and “password”; place the client ID in the first slot and the client secret in the second. In curl, --user "CLIENT_ID:CLIENT_SECRET" creates that Authorization header.

curl --request POST "https://feedsync.com.au/api/v1/oauth/token" \
--user "CLIENT_ID:CLIENT_SECRET" \
--header "Accept: application/json" \
--header "Content-Type: application/x-www-form-urlencoded" \
--data-urlencode "grant_type=client_credentials"
{
"access_token": "opaque-access-token",
"token_type": "bearer",
"expires_in": 3600,
"refresh_token": "feedsync-extension-token",
"scope": "listing:listings:write",
"consumer_id": "7ebfcd36-b5b0-46e6-a3fb-d88b18f04c37"
}

refresh_token can be exchanged through /api/v1/oauth/refresh. An integration may instead request another client-credentials token after expiry. Access tokens are opaque secrets.

Omitting scope grants the scopes assigned to the OAuth client. You may send scope=listing:listings:write to request an explicit subset.

FeedSync currently revokes the client's earlier live tokens when it issues a new one. Multiple workers should share one cached token instead of racing to request separate tokens.

Upload one listing​

curl --request POST "https://feedsync.com.au/api/v1/listing/v1/upload" \
--header "Authorization: Bearer ACCESS_TOKEN" \
--header "Accept: application/json" \
--header "Content-Type: application/xml" \
--data-binary @listing.xml

FeedSync accepts application/xml and text/xml, including values with a charset parameter. The body limit is 10 MiB.

The body must be well-formed REAXML containing exactly one supported property element. That element must contain:

  • agentID, used as agencyId in report search;
  • uniqueID, used as externalListingId in reports.

Supported property elements are residential, rental, commercial, land, rural, business, commercialLand, and holidayRental.

<?xml version="1.0" encoding="UTF-8"?>
<propertyList>
<residential status="current" modTime="2026-09-11-10:00:00">
<agentID>OFFICE42</agentID>
<uniqueID>CRM-10001</uniqueID>
<category name="House" />
<address display="yes">
<suburb display="yes">Fremantle</suburb>
<state>WA</state>
<postcode>6160</postcode>
</address>
</residential>
</propertyList>

This is a structural example, not a complete REAXML schema. Keep uniqueID stable for every update and terminal status change to the same listing.

Accepted response​

HTTP/1.1 202 Accepted
Content-Type: application/json
X-Transaction-Id: 36028179-ff20-46fe-b17a-3f50e10f175f
X-RateLimit-Limit-minute: 300
X-RateLimit-Remaining-minute: 299
{
"uploadId": "a4db2bab-b71a-4617-a40a-234868c96721"
}

202 means FeedSync authenticated and stored the document for processing. It does not mean the listing passed validation or was imported. Persist the upload ID.

Every submission creates a new upload ID, including a duplicate document. FeedSync returns 409 after ten uploads for the same agentID and uniqueID are already IN_PROGRESS.

Retrieve a report​

curl "https://feedsync.com.au/api/v1/listing/v1/upload/a4db2bab-b71a-4617-a40a-234868c96721" \
--header "Authorization: Bearer ACCESS_TOKEN" \
--header "Accept: application/json"
{
"uploadId": "a4db2bab-b71a-4617-a40a-234868c96721",
"completedTime": "2026-09-11T03:15:28.000000Z",
"progress": "COMPLETED",
"result": "PROCESSED",
"externalListingId": "CRM-10001",
"listingId": "87124",
"agencyId": "OFFICE42",
"issues": {
"warnings": [],
"errors": []
}
}

progress has two possible values:

ValueMeaning
IN_PROGRESSQueued or processing. completedTime, result, and listingId may be null.
COMPLETEDProcessing reached a terminal result. Inspect result and issues.

Terminal results are NEW, PROCESSED, DELETED, UNCHANGED, SKIPPED, and INTERNAL_ERROR. COMPLETED describes processing progress; it does not by itself mean success.

Warnings and errors contain type, field, messages, and helpCentreUrl.

Poll after a short delay, then use exponential backoff with jitter and a maximum interval. Do not poll continuously. Preserve the upload ID when escalating a stalled upload.

Search reports​

curl --get "https://feedsync.com.au/api/v1/listing/v1/upload" \
--header "Authorization: Bearer ACCESS_TOKEN" \
--header "Accept: application/json" \
--data-urlencode "agencyId=OFFICE42" \
--data-urlencode "externalListingId=CRM-10001"

The response is an unpaginated array ordered newest first and constrained to the authenticated client's feed:

[
{
"uploadId": "a4db2bab-b71a-4617-a40a-234868c96721",
"lastModified": "2026-09-11T03:14:59.000000Z"
}
]

Errors and status codes​

Errors use the Partner Platform envelope:

{
"errors": [
{
"status": "406",
"title": "Not Acceptable",
"detail": "Accept must allow application/json",
"meta": {
"transactionId": "36028179-ff20-46fe-b17a-3f50e10f175f"
}
}
]
}
StatusMeaning
202Listing accepted for processing.
400Missing body/identifiers, invalid XML, wrong number of listings, or missing search parameters.
401Bearer token is missing, invalid, expired, or revoked.
403Missing scope, unauthorized feed, or no feed associated with the client.
404Upload report is not available to this client's feed or URL is invalid.
405HTTP method is not supported.
406Accept cannot receive JSON or upload Content-Type is not XML.
409Too many copies of this listing are already in the processing queue.
413XML exceeds FeedSync's 10 MiB limit.
429Request rate limit exceeded.
500FeedSync could not accept or report the upload.

Store transactionId when present. Never log Authorization, client secret, token, or the complete property XML in ordinary logs.

Every token and upload API response includes X-Transaction-Id. Upload operations are limited to 300 requests per minute per OAuth client and include X-RateLimit-Limit-minute and X-RateLimit-Remaining-minute. A 429 also includes Retry-After in seconds.

Retry and duplicate handling​

The upload operation has no idempotency-key header. Design for at-least-once delivery:

  1. Persist uploadId after every 202; do not resubmit that delivery.
  2. After an ambiguous network failure, search by agencyId and externalListingId before retrying.
  3. Retry transient 429 and 5xx responses with capped exponential backoff and jitter.
  4. Treat 400, 403, 406, and 413 as configuration or payload faults.
  5. Accept that duplicate requests create different upload IDs and keep source documents deterministic.

Production checklist​

  • Use HTTPS and verify certificates.
  • Keep one OAuth client per system and feed.
  • Share the cached token between workers.
  • Send raw bytes using --data-binary semantics.
  • Preserve agentID, uniqueID, upload ID, timestamps, status, and safe error metadata.
  • Poll asynchronously and treat COMPLETED plus a failure result as a terminal failure.
  • Reconcile source listings periodically so missed deliveries cannot leave data stale indefinitely.