Reallyo Listings API

Send your rental and sale listings to Reallyo from your own systems or an AI agent; Reallyo publishes them to the listing portals. Any Reallyo account; your plan sets how many rentals can be available at once.

For AI agents (MCP): https://mcp.reallyo.com
In Claude or ChatGPT, add it as a custom connector: sign in with your Reallyo login and choose read only or read and write (no API key needed); disconnect it under API settings in your Reallyo dashboard. In code and developer tools, send the header Authorization: Bearer rly_live_….
REST: OpenAPI 3.1 · Agent summary: llms.txt
Keys and connected apps: API settings in your Reallyo dashboard (no key yet? make one there; re-roll and disable keys; disconnect apps). Using the API means agreeing to the API Terms.

Two ids, and the MLS number

idReallyo's id for the listing (a number). Every listing on your account has one, including those made in the Reallyo dashboard. A listing you create has id: null until Reallyo has created it.
external_idYour id for the unit (e.g. your property-management unit id), unique on your account. Listings made in the dashboard have none until you give them one.
mls_idThe listing's MLS number (a field of the listing). /v1/listings/mls_id/{mls_id} names an existing listing by it, matched trimmed, ignoring case and repeated spaces; several matches → 409 mls_ambiguous with their ids.

Use id for any listing you have seen in a response, external_id for your own units, and the MLS number when that is what you have.

How it works

  1. Create a listing with POST /v1/listings; external_id (your own id) and mls_id are optional fields of it. The response is 201 Created with Reallyo's id and a Location header (or 202 Accepted if Reallyo has not finished creating it yet: id is null for a moment). A second create with the same external_id is refused (409 external_id_taken, with the existing listing's id). To retry a create safely without an external_id, send an Idempotency-Key header.
  2. Change or take down any listing on your account by any of its names: PATCH / DELETE. To manage a listing made in the dashboard with your own id, give it one: PATCH /v1/listings/{id} with {"external_id":"UNIT-12B"}.
  3. Every listing is checked first. A listing that fails the checks is refused with 422 invalid_listing and nothing is stored; error.details.errors names each field and what to send instead.
  4. Accepted changes are stored and then applied to the listing, usually within seconds; last_change says queued, then applied. One that cannot be applied as sent is held or failed, with a message saying why. Changes can also be paused: kept, and applied later in the order sent (below).
  5. Available rentals count towards your plan's listing limit, those made in the dashboard included; sales and other statuses do not. At the limit a change that would add one is refused with plan_limit_reached and not saved; nothing else is done. To keep it, send it as a draft, then update it to available once you are under the limit (mark a unit rented, remove one, or upgrade).
  6. Keep phone numbers, email addresses and web links out of the description: Zillow declines them, so Reallyo holds such listings.
  7. When a unit is let, set status to "rented". Removing a listing takes it down; it is kept, never deleted.
  8. Keys: an account can have several named keys. A key can be read only (it reads and validates; a change is 403 key_read_only), disabled (403 key_disabled) or limited to IP addresses (403 ip_not_allowed, naming the address seen). GET /v1/me names the key and shows daily_changes.
  9. One listing per request, by design. Limits: 120 requests a minute per key. Reallyo applies up to 100 listing changes a day per account (unless agreed otherwise); later ones are kept and paused until midnight UTC, then applied in order. The API refuses changes (429 daily_limit) only past twice the daily limit.
  10. Unusual bulk changes are paused until the account holder confirms them by email: within 24 hours, taking down more than a fifth of the account's available rentals (at least 10), adding many listings in states where it had none, or changing rents by more than half on many listings. Only those changes wait, with any later change to the same listings; your other changes go on. Once confirmed, they are applied in order.

Example

curl -X POST https://listings-api.reallyo.com/v1/listings \
  -H "Authorization: Bearer $REALLYO_API_KEY" -H "Content-Type: application/json" \
  -d '{"external_id":"UNIT-12B","mls_id":"A12012329",
       "status":"available","offer_type":"rent","price":2450,"bedrooms":2,"bathrooms":1,
       "description":"Bright two-bedroom with in-unit laundry, two blocks from the subway…",
       "address":{"street_number":"222","street":"East 39th Street","unit":"12B",
                  "city":"New York","state_code":"NY","postcode":"10016"},
       "available_from":"2026-11-01","pets":{"cats":true},
       "photos":[{"url":"https://example.com/12b/living-room.jpg"}]}'

curl -X PATCH https://listings-api.reallyo.com/v1/listings/4100001 \
  -H "Authorization: Bearer $REALLYO_API_KEY" -H "Content-Type: application/json" \
  -d '{"external_id":"UNIT-3"}'

Endpoints

GET /v1/mePlan, listing limit, available rentals, limit remaining
GET /v1/listingsEvery listing on your account (dashboard and API), each with id, external_id, status, last_change and a summary (address, unit, price, bedrooms, photo count). Search with ?q=222 E 39th 12B; filter with ?bedrooms=, ?status=, ?last_change=; page with ?after=
POST /v1/listingsCreate a listing (the only way); returns Reallyo's id. Optional: external_id, mls_id, header Idempotency-Key
GET /v1/listings/{id}
GET /v1/listings/external_id/{external_id}
The whole listing (every field, photos as URLs), its status and last_change
PATCH /v1/listings/{id}
PATCH /v1/listings/external_id/{external_id}
Change some fields, e.g. {"status":"rented"}; {"external_id":"…"} gives the listing your own id
DELETE /v1/listings/{id}
DELETE /v1/listings/external_id/{external_id}
Take down (kept, never deleted)
GET · PATCH · DELETE /v1/listings/mls_id/{mls_id}The same, by MLS number (URL-encoded). GET /v1/listings?mls_id= filters by it.
POST /v1/listings/validateCheck without storing

Listing fields

status"available" | "coming_soon" | "pending" | "rented" | "sold" | "draft""available" is on the market and published by Reallyo (counts towards your plan's listing limit). "coming_soon"/"pending" show on your Reallyo pages only. "rented"/"sold" take it off the market; "draft" keeps it private. default "available"
offer_type"rent" | "sale" default "rent"
titlestringOptional. Generated from the address and size when omitted.
descriptionstringThe listing text renters see. Required for "available". default ""
address requiredobjectThe property address. US only.
address.street_numberstringHouse or building number, e.g. "222". default ""
address.street requiredstringStreet name, e.g. "East 39th Street".
address.unitstringApartment or unit, e.g. "16B". Empty for a whole house. default ""
address.city requiredstring
address.state_code requiredstringTwo-letter US state code, e.g. "NY".
address.postcode requiredstringUS ZIP code.
address.neighborhoodstring default ""
address.hide_street_numberbooleanPublish the street without the house number. realtor.com and apartments.com refuse such listings. default false
latitudenumber
longitudenumber
pricenumberMonthly rent (rent) or asking price (sale), in USD. Required for "available".
bedroomsinteger0 for a studio.
bathroomsnumberHalf baths as .5, e.g. 1.5.
square_feetinteger
property_type"apartment" | "assisted living" | "barn" | "bungalow" | "cabin" | "castle" | "co-op" | "condo" | "cottage" | "detached house" | "duplex" | "farm" | "flat" | "fourplex" | "high-rise" | "house" | "houseboat" | "land" | "loft" | "maisonette" | "manufactured" | "mid-rise" | "mobile" | "multi-family home" | "penthouse" | "semi-detached house" | "senior housing" | "single-family home" | "studio" | "terraced house" | "townhouse" | "triplex" | "villa" | "windmill" default "apartment"
year_builtinteger
available_fromstring | string"now", or the date the property becomes available. default "now"
lease_term"1_year" | "6_months" | "monthly" | "rent_to_own" | "variable"Rentals only. default "1_year"
petsobjectRentals only. Which pets are allowed. default {"cats":false,"small_dogs":false,"large_dogs":false}
pets.catsboolean default false
pets.small_dogsboolean default false
pets.large_dogsboolean default false
furnishedbooleanRentals only. default false
smoking_allowedbooleanRentals only. default false
utilities_includedarrayRentals only. default []
photosarrayIn display order; the first is the cover. At least one is required for "available". We copy each photo to our CDN — your URL only has to work when you send it. We copy each link once; to change a photo, send it at a new link. default []
photos[].url requiredstringA publicly reachable JPEG, PNG, GIF or WebP, up to 50 MB.
photos[].captionstring default ""
videosarrayYouTube, Vimeo or Wistia links. Others are dropped. default []
mls_idstring default ""

Status

availableOn the market: shown on Reallyo, which decides which portals it goes to. A rental counts towards your plan's listing limit.
coming_soon · pendingShown on your Reallyo pages; not sent to the portals and not counted against your listing limit.
rented · sold · draftOn Reallyo, not sent to the portals.
removedTaken down (kept, never deleted). Left out of GET /v1/listings unless you ask for ?status=removed.

last_change

What happened to the latest change you sent for the listing: result, message (what to do), checks, received_at, processed_at. Null for a listing never changed through the API.

queuedAccepted and stored, waiting to be applied. Until then, status and listing show the version you sent.
pausedAccepted and stored, but waiting: past today's daily limit (applied after midnight UTC), or an unusual bulk change waiting for the account holder's confirmation. See message.
appliedDone: status and listing show what Reallyo now holds.
heldNot applied as sent: your plan's listing limit, contact details in the description, or a photo that could not be copied. See message.
failedNot applied; see message.

Questions: hello@reallyo.com