moveandstayFind me a place
For agents

Moveandstay API for agents

A keyed HTTP API that lets an AI agent search Moveandstay's listings, read one listing, and send an enquiry through the same pipeline a visitor's enquiry goes through.

Moveandstay is a directory of move-in-ready stays and workspaces: serviced apartments, extended-stay accommodation, serviced offices and coworking spaces. Coverage is worldwide — strongest in Asia-Pacific. We take no booking commission — an enquiry is an introduction to the operator, not a reservation.

What it does, and what it does not

  • Search published properties by country, city, category, capacity and property name.
  • Read one property: its description, amenities, the operator's own FAQ, photos, unit types, and dated statements from the property.
  • Send an enquiry — either to a specific property, or to our matching team when no single property is named.

It is not a booking API and there is nothing to reserve. It is not an availability API: we do not hold a live calendar, so no endpoint will tell you whether a property is free on a date. A property may have told us what was free, and that comes back as a dated statement to quote with its date, never as a booking. It cannot create or edit listings.

As at 2026-10-25, the directory holds 2,729 published properties across 157 cities in 40 countries. These are point-in-time figures read from the database when this page was generated; they change with every import, so do not cache them.

Authentication

Every endpoint except the health check needs an API key, sent as a bearer token. There is no anonymous tier: a request without a key is a 401. Ask contact@moveandstay.com for one.

curl -H 'Authorization: Bearer YOUR_KEY' \
  'https://moveandstay.com/api/agent/v1/properties?city=hong-kong&limit=5'

Each key has its own hourly budget — generous for reads, deliberately tight for enquiries. A spent budget answers 429 with a Retry-After header saying when the next slot frees, rather than a flat hour.

GET /api/agent/v1/properties/{id}

id is the value search returned. The response adds the description, the amenity list, the operator's FAQ, the photos, and three more fields:

  • units — the property's units and their rates, the same rows as its page's "Units and rates": each unit the property names, and each size or office product (kind: hot_desk, dedicated_desk, private_office, meeting_room, virtual_office, day_pass) only its dated price statements name. Each has guests, bedrooms (0 is a studio), size_sqm, its own rate_from and rate_to or null (price on request), who gave the price (price_source: operator, website, or listing for a rate stored on the unit) and the day (price_observed_on), and availability: the latest statement about it being free, with its day. Quote it with its day, never as a booking.
  • latest_updates — short dated statements about the property: what the property told us (source: "operator") or what we read on its own website (source: "website"). The statement itself is in text, and kind says what it is about (for example availability, minimum_stay, price). Each has the day it was observed (observed_on) and, for things that go stale, the last day it applies (valid_until). They can cover availability, minimum stay, price, what the price includes, terms, offers, busy and quiet periods, and news. Expired items are left out; for each kind only what the most recent statement said is sent (every news item is kept); at most 10. We check each item before it is published.
  • last_confirmed — the day the page was last confirmed (on) and by whom (by): operator when the property confirmed it, website when it was checked against the property's own website. null if it never has been.
  • facts — in some cities only (absent elsewhere): the numbers behind what the page shows, per kind. price and availability are lists, one per unit type (unit_type, or null for the property); minimum_stay, deposit and included are one each, or null. Every fact has the day it was said (confirmed_on), who said it (source: operator for the property, website for its own site) and the last day it applies (valid_until). Quote them with their day: "the property said on 2026-11-03 that a one-bedroom is free from 1 December". They are never a calendar and never a booking.
  • freshness — in the same cities: confirmed, partly or not_confirmed, how recently the property (or, counting less, its own website) confirmed its price, availability and minimum stay. A band, never a score; not_confirmed says nothing bad about a property.
  • rate_confirmation — in the same cities: whether rate_from is a price the property (operator) or its website confirmed, with the day (confirmed_on); not_confirmed whenever no dated fact backs it.

A latest_updates item is what the property said on that day, not a calendar and not a booking. Say "the property said on 2026-10-01 that …" (or "the property's website said on …" when source is website), never that a unit is available or reserved.

No endpoint returns a property's email address or phone number. The enquiry endpoint is how a property is contacted.

POST /api/agent/v1/enquiries

Send property_id and the enquiry goes to that property. Leave it out and it goes to our matching team, who contact suitable properties on the traveller's behalf. Both land in the same pipeline a website enquiry lands in.

{
  "property_id": "3f1a2b4c-5d6e-7f80-9a1b-2c3d4e5f6071",
  "contact": {
    "name": "Alice Tan",
    "email": "alice@example.com",
    "phone": "+852 1234 5678"
  },
  "requirements": {
    "move_in_date": "2026-11-01",
    "duration_value": 3,
    "duration_unit": "month",
    "capacity": 2,
    "budget_amount": 40000,
    "budget_currency": "HKD",
    "budget_period": "monthly",
    "message": "Quiet flat, close to the MTR."
  },
  "consent": { "granted": true, "source": "asked in chat" },
  "idempotency_key": "your-unique-id-for-this-enquiry"
}
  • consent.granted must be literally true. You are submitting somebody else's contact details to a company that will email them; this is where you confirm they agreed.
  • idempotency_key is required. Send the same value if you retry, so a timeout cannot produce a second enquiry. Reusing a key with different content is a 409.
  • requirements.capacity is required when property_id is given — the operator is told how many people or desks the enquiry is for, and there is no honest default.
  • There is no bedrooms on an enquiry: an apartment's size is asked as the number of guests, requirements.capacity. Without property_id, properties are ranked on the price of the size that sleeps them (2 a bedroom, a studio for 1–2); that size never leaves a property out (a stated capacity below the guests still does). A size named in message ("a 3-bedroom") is the size asked for: a property with nothing that big is not contacted, and the budget is judged on that size's own price.

Two success shapes, both 200

{ "status": "RECEIVED",              "enquiry_id": "…", "route": "property" }
{ "status": "RECEIVED_UNDER_REVIEW", "enquiry_id": "…", "route": "concierge" }

RECEIVED means the enquiry entered the pipeline. RECEIVED_UNDER_REVIEW means it has been saved and is being looked at. Tell the person what the status says and nothing more: we do not promise a reply, a response time, or a number of properties that will get in touch.

Errors

Every error is { "error": { "code": …, "message": … } }. Branch on code; show message.

CodeStatusMeans
unauthorized401No key, or not one of ours.
rate_limited429This key's budget for the hour is spent. Retry-After says when.
invalid_request400A field is missing, malformed or out of range.
consent_required400consent.granted was not true.
unknown_city / unknown_country / unknown_type400That slug is not one we cover.
property_not_found404No published property has that reference.
idempotency_conflict409That key was already used for a different enquiry.
server_error500Ours. Safe to retry with the same idempotency key.

What we cannot tell you

Stated plainly, because an agent that knows the edges of a source is more useful than one that guesses at them:

  • Availability. We hold no calendar. Nothing here says a property is free on a date. latest_updates may hold a dated statement from the property about what was free: quote it with its date, and never say a unit is available or reserved.
  • Minimum stay. Only as a dated statement in latest_updates, when the property told us one. Otherwise it is not stated: ask the operator through an enquiry.
  • Full pricing. Only a "from" rate: rate_from, and per unit in units. Amount, currency and period are exactly as stored, never converted. It may have been given by the property, entered by our team, or found on a public page about the property. It is indicative: the property confirms the real price. rate_from: null means *not stated* — not free, and not "ask us".
  • Long-stay suitability as a filter. Most properties on the site take stays of a month or more, but we have no stored field for it, so there is no filter to offer.
  • Search beyond the name. q matches the property name. To narrow by place, use country, city and type.

Machine-readable

  • OpenAPI description — the whole surface, for a connector platform or a code generator.
  • MCP server at /mcp — the same three capabilities as MCP tools.
  • /llms.txt — what this site is for and when not to use it.
  • Every public page also answers to Accept: text/markdown, or a .md suffix.

Questions, or a key: contact@moveandstay.com.