{"openapi":"3.1.0","info":{"title":"Moveandstay agent API","version":"1.0.0","description":"Moveandstay is a directory of move-in-ready stays and workspaces — serviced apartments, extended-stay accommodation, serviced offices and coworking spaces — worldwide — strongest in Asia-Pacific. This API lets an agent search it, read one property, and send an enquiry through the same pipeline a website visitor's enquiry goes through.\n\nWHAT THIS API CANNOT TELL YOU, stated plainly so you do not infer it:\n- Availability. We hold no calendar. Nothing here says whether a property is free on a date.\n- Minimum stay. We do not store one.\n- Full pricing. Only a \"from\" rate, and a null rate means not stated.\n- Anything beyond the property name in free-text search.\n\nAn enquiry is an introduction to the operator, not a booking or a reservation. We take no commission. Do not promise a reply, a response time, or a number of properties that will get in touch.\n\nAs at 2026-10-05, the directory holds 1,809 published properties across 57 cities in 34 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.","contact":{"name":"Moveandstay support","email":"contact@moveandstay.com"},"termsOfService":"https://moveandstay.com/terms"},"servers":[{"url":"https://moveandstay.com/api/agent/v1"}],"externalDocs":{"description":"Human-readable reference","url":"https://moveandstay.com/docs"},"x-mcp-endpoint":{"url":"https://moveandstay.com/mcp","transport":"streamable-http","description":"The same three capabilities as MCP tools, with the same keys and the same budget. Setup: https://moveandstay.com/docs/mcp"},"security":[{"bearerAuth":[]}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","description":"API keys are issued by contact@moveandstay.com. There is no anonymous tier."}},"schemas":{"Error":{"type":"object","required":["error"],"properties":{"error":{"type":"object","required":["code","message"],"properties":{"code":{"type":"string","enum":["unauthorized","rate_limited","invalid_json","invalid_request","unknown_city","unknown_country","unknown_type","property_not_found","consent_required","idempotency_conflict","method_not_allowed","server_error"]},"message":{"type":"string"}}}}},"PropertySummary":{"type":"object","required":["id","name","url","city","type","rate_from","capacity","has_photos"],"properties":{"id":{"type":"string","format":"uuid","description":"The property reference. Pass this to /enquiries as property_id."},"name":{"type":"string"},"url":{"type":"string","format":"uri","description":"The public page, for linking a person to it."},"address":{"type":"string","nullable":true},"city":{"type":"object","properties":{"name":{"type":"string"},"slug":{"type":"string"}}},"country":{"type":"object","nullable":true,"properties":{"name":{"type":"string"},"slug":{"type":"string"}}},"type":{"type":"object","properties":{"slug":{"type":"string","enum":["serviced-apartments","extended-stay","serviced-offices","coworking-spaces"]},"label":{"type":"string"}}},"rate_from":{"type":"object","nullable":true,"description":"The operator's \"from\" rate, exactly as they gave it. null means NOT STATED — not free, and not \"ask us\". There is no other pricing.","required":["amount","currency","period"],"properties":{"amount":{"type":"number"},"currency":{"type":"string","description":"ISO 4217, e.g. HKD."},"period":{"type":"string","enum":["monthly","nightly","daily"]}}},"capacity":{"type":"object","description":"Every field is nullable, and null means the operator has not told us — never that the answer is zero.","properties":{"guests_min":{"type":"integer","nullable":true},"guests_max":{"type":"integer","nullable":true},"bedrooms_min":{"type":"integer","nullable":true},"bedrooms_max":{"type":"integer","nullable":true},"workstations":{"type":"integer","nullable":true},"private_offices":{"type":"integer","nullable":true},"meeting_rooms":{"type":"integer","nullable":true}}},"has_photos":{"type":"boolean"},"photo_url":{"type":"string","nullable":true}}},"PropertyDetail":{"allOf":[{"$ref":"#/components/schemas/PropertySummary"},{"type":"object","properties":{"description":{"type":"string","nullable":true},"amenities":{"type":"array","items":{"type":"string"}},"faq":{"type":"array","items":{"type":"object","properties":{"question":{"type":"string"},"answer":{"type":"string"}}}},"photos":{"type":"array","items":{"type":"object","properties":{"url":{"type":"string"},"alt":{"type":"string","nullable":true}}}},"units":{"type":"array","description":"Room or desk types the operator has published.","items":{"type":"object","properties":{"unit_type":{"type":"string"},"guests":{"type":"integer","nullable":true},"bedrooms":{"type":"integer","nullable":true},"size_sqm":{"type":"number","nullable":true},"rate_from":{"type":"object","nullable":true,"description":"The operator's \"from\" rate, exactly as they gave it. null means NOT STATED — not free, and not \"ask us\". There is no other pricing.","required":["amount","currency","period"],"properties":{"amount":{"type":"number"},"currency":{"type":"string","description":"ISO 4217, e.g. HKD."},"period":{"type":"string","enum":["monthly","nightly","daily"]}}}}}},"latest_updates":{"type":"array","description":"What the property itself told us recently, checked by Moveandstay before publication: availability, busy and quiet periods, booking lead time, what the price covers, offers, terms. Expired items are left out; the newest per kind.","items":{"type":"object","properties":{"kind":{"type":"string","enum":["availability","busy_periods","booking_tips","price","promotion","included","policies","minimum_stay","guest_profile","news"]},"text":{"type":"string"},"source":{"type":"string","enum":["operator","website"]},"observed_on":{"type":"string","format":"date"},"valid_until":{"type":"string","format":"date","nullable":true}}}},"last_confirmed":{"type":"object","nullable":true,"description":"When the page was last confirmed, and by whom.","properties":{"on":{"type":"string","format":"date"},"by":{"type":"string","enum":["operator","website"]}}}}}]},"EnquiryRequest":{"type":"object","required":["contact","consent","idempotency_key"],"properties":{"property_id":{"type":"string","format":"uuid","description":"The property to enquire about. Leave it out to send the enquiry to our matching team instead."},"contact":{"type":"object","required":["name","email"],"properties":{"name":{"type":"string","maxLength":120},"email":{"type":"string","format":"email","maxLength":200},"phone":{"type":"string","maxLength":40,"nullable":true}}},"requirements":{"type":"object","properties":{"country":{"type":"string","description":"Country slug."},"city":{"type":"string","description":"City slug."},"type":{"type":"string","enum":["serviced-apartments","extended-stay","serviced-offices","coworking-spaces"]},"location_area":{"type":"string","maxLength":160},"move_in_date":{"type":"string","format":"date"},"duration_value":{"type":"integer","minimum":1,"maximum":120},"duration_unit":{"type":"string","enum":["day","week","month"]},"capacity":{"type":"integer","minimum":1,"maximum":200,"description":"Guests, or desks for a workspace. REQUIRED when property_id is given: the operator is told the number and there is no honest default for it."},"budget_amount":{"type":"number","minimum":0},"budget_currency":{"type":"string","minLength":3,"maxLength":3},"budget_period":{"type":"string","enum":["monthly","nightly","daily"]},"message":{"type":"string","maxLength":4000}}},"consent":{"type":"object","required":["granted"],"description":"You are submitting somebody else's contact details to a company that will email them. This is where you confirm they agreed.","properties":{"granted":{"type":"boolean","enum":[true],"description":"Must be literally true. Not \"true\", not 1, not \"yes\"."},"source":{"type":"string","maxLength":200,"description":"How consent was obtained, in a few words."}}},"idempotency_key":{"type":"string","description":"Required. Send the same value if you retry, so a timeout cannot produce a second enquiry. Reusing it with different content is a 409."}}},"EnquiryResponse":{"type":"object","required":["status","route"],"properties":{"status":{"type":"string","enum":["RECEIVED","RECEIVED_UNDER_REVIEW"],"description":"RECEIVED — the enquiry entered the pipeline. RECEIVED_UNDER_REVIEW — it has been saved and is being looked at. Tell the person what the status says and nothing more."},"enquiry_id":{"type":"string","nullable":true},"route":{"type":"string","enum":["property","concierge"],"description":"property — sent to the property you named. concierge — sent to our matching team, who contact suitable properties."},"replayed":{"type":"boolean","description":"True when this answer came from a previous call with the same idempotency_key."}}}}},"paths":{"/properties":{"get":{"operationId":"searchProperties","summary":"Search published properties","description":"Free text (`q`) matches the PROPERTY NAME ONLY — not the description, address or amenities. Narrow by place with country, city and type. An unknown slug is an error, not an empty list. A capacity filter excludes properties that state no capacity rather than assuming they fit.","parameters":[{"name":"q","in":"query","schema":{"type":"string","maxLength":120},"description":"Property name."},{"name":"country","in":"query","schema":{"type":"string"},"description":"Country slug."},{"name":"city","in":"query","schema":{"type":"string"},"description":"City slug."},{"name":"type","in":"query","schema":{"type":"string"},"description":"One or more of serviced-apartments, extended-stay, serviced-offices, coworking-spaces, comma-separated."},{"name":"min_capacity","in":"query","schema":{"type":"integer","minimum":1}},{"name":"min_workstations","in":"query","schema":{"type":"integer","minimum":1}},{"name":"has_photos","in":"query","schema":{"type":"boolean"}},{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":50,"default":20}},{"name":"offset","in":"query","schema":{"type":"integer","minimum":0}}],"responses":{"200":{"description":"Matching properties, in the order the website ranks them.","content":{"application/json":{"schema":{"type":"object","required":["results","total","limit","offset"],"properties":{"results":{"type":"array","items":{"$ref":"#/components/schemas/PropertySummary"}},"total":{"type":"integer","description":"Total matching the filters, not the number returned."},"limit":{"type":"integer"},"offset":{"type":"integer"}}}}}},"400":{"description":"A parameter was malformed, or named a place or type we do not cover.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"No key, or not one of ours.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"This key's hourly read budget is spent. Retry-After says when.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/properties/{id}":{"get":{"operationId":"getProperty","summary":"One published property","description":"No endpoint returns a property's email address or phone number. Use /enquiries to make contact.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"The id search returned."}],"responses":{"200":{"description":"The property.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PropertyDetail"}}}},"400":{"description":"That is not a property reference. Use the id search returned.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"No key, or not one of ours.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No published property has that reference.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"This key's hourly read budget is spent.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/enquiries":{"post":{"operationId":"createEnquiry","summary":"Send an enquiry","description":"Reaches the same pipeline a website enquiry reaches. With property_id it goes to that property; without one it goes to our matching team. Consent and an idempotency key are both required.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/EnquiryRequest"}}}},"responses":{"200":{"description":"Accepted. Check `status`: RECEIVED, or RECEIVED_UNDER_REVIEW, which means saved and being looked at.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EnquiryResponse"}}}},"400":{"description":"A field was malformed, or consent.granted was not true.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"No key, or not one of ours.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No published property has that reference.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"That idempotency_key was already used for a different enquiry.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"This key's hourly enquiry budget is spent.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/health":{"get":{"operationId":"health","summary":"Is the API up","description":"The one endpoint that answers without a key.","security":[],"responses":{"200":{"description":"Up."}}}}}}