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
| Method | FeedSync path | Behavior |
|---|---|---|
POST | /api/v1/listing/v1/upload | Accept 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:
- Open OAuth Clients at
/oauth-clientsor from the feed's OAuth tab. - Select the provider and feed and grant
listing:listings:write. - Copy the client ID and client secret when displayed.
- 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 asagencyIdin report search;uniqueID, used asexternalListingIdin 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:
| Value | Meaning |
|---|---|
IN_PROGRESS | Queued or processing. completedTime, result, and listingId may be null. |
COMPLETED | Processing 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"
}
}
]
}
| Status | Meaning |
|---|---|
202 | Listing accepted for processing. |
400 | Missing body/identifiers, invalid XML, wrong number of listings, or missing search parameters. |
401 | Bearer token is missing, invalid, expired, or revoked. |
403 | Missing scope, unauthorized feed, or no feed associated with the client. |
404 | Upload report is not available to this client's feed or URL is invalid. |
405 | HTTP method is not supported. |
406 | Accept cannot receive JSON or upload Content-Type is not XML. |
409 | Too many copies of this listing are already in the processing queue. |
413 | XML exceeds FeedSync's 10 MiB limit. |
429 | Request rate limit exceeded. |
500 | FeedSync 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:
- Persist
uploadIdafter every202; do not resubmit that delivery. - After an ambiguous network failure, search by
agencyIdandexternalListingIdbefore retrying. - Retry transient
429and5xxresponses with capped exponential backoff and jitter. - Treat
400,403,406, and413as configuration or payload faults. - 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-binarysemantics. - Preserve
agentID,uniqueID, upload ID, timestamps, status, and safe error metadata. - Poll asynchronously and treat
COMPLETEDplus a failure result as a terminal failure. - Reconcile source listings periodically so missed deliveries cannot leave data stale indefinitely.