{"openapi":"3.1.0","info":{"title":"goyostudio Korean Real Estate Transactions API","version":"1.0.0","description":"AI-native, machine-to-machine API for official Korean real-estate transaction records\n(국토교통부 실거래가, MOLIT via data.go.kr). Send a natural-language Korean address or\napartment-complex query; receive flat, token-efficient JSON with per-period statistics\nand individual transactions. Designed for LLM/agent consumption: every inference is\ndisclosed in resolved_note, ambiguity returns candidates instead of guessing, and\ndomain errors are machine-readable codes.\n\nMCP: the same tool is served statelessly at POST /mcp (Streamable HTTP, no authentication).\nThat endpoint is not a REST path; see x-mcp.\n\nPRICING: currently free within edge or app rate limits (50 requests / 10 seconds per IP). This API is x402-ready — a fixed\nmicro-price per request (indicative $0.001–$0.01, USDC on Base) may be enabled later,\nin which case unpaid requests receive HTTP 402 Payment Required per the x402 protocol\n(https://x402.org). Agents with x402 support need no code changes; see x-pricing.","termsOfService":"https://realestate-api.goyostudio.io/terms","contact":{"email":"developer@goyostudio.io"}},"x-pricing":{"current":"free","planned":{"protocol":"x402","price_usd_per_request":"0.001-0.01","network":"base","currency":"USDC","note":"HTTP 402 responses begin only after pricing is enabled; monitor this document."}},"x-mcp":{"transport":"streamable-http","url":"https://realestate-api.goyostudio.io/mcp","protocol":"2026-07-28","note":"Stateless remote MCP server. No authentication. Tool: get_korean_real_estate_transactions. Definition: docs/mcp-tools.json."},"servers":[{"url":"https://realestate-api.goyostudio.io"}],"paths":{"/api/v1/real-estate/transactions":{"get":{"operationId":"getKoreanRealEstateTransactions","summary":"Query real-estate transactions by natural-language Korean address","description":"Resolves q (e.g. \"강남구 대치동 은마 아파트 매매\") to an official district/complex and\nreturns statistics plus recent transactions for the period. Hint words inside q\n(아파트/오피스텔/…, 매매/전세/월세) are auto-inferred as type/tradeType/rentSubtype;\nexplicit query parameters always win over hints. Period words in q (\"최근 3개월\")\nare ignored — use startDate/endDate.","parameters":[{"name":"q","in":"query","required":true,"schema":{"type":"string"},"description":"Natural-language Korean address and/or complex name. Max ~30 Korean characters (90 UTF-8 bytes) and 8 whitespace-separated tokens.","example":"강남구 대치동 아파트 매매"},{"name":"type","in":"query","schema":{"type":"string","enum":["apartment","officetel","rowhouse","detached","presale","land","commercial","industrial"],"default":"apartment"},"description":"Property type. Default apartment unless inferred from q. tradeType=rent is available only for apartment/officetel/rowhouse/detached; presale/land/commercial/industrial are sale-only."},{"name":"tradeType","in":"query","schema":{"type":"string","enum":["sale","rent"],"default":"sale"},"description":"sale = 매매, rent = 전월세 (jeonse + wolse combined unless rentSubtype filters)."},{"name":"rentSubtype","in":"query","schema":{"type":"string","enum":["jeonse","wolse"]},"description":"Only with tradeType=rent. jeonse (전세) = deposit-only leases (monthly_rent = 0); wolse (월세) = leases with monthly rent > 0."},{"name":"startDate","in":"query","schema":{"type":"string","pattern":"^\\d{4}-(0[1-9]|1[0-2])$"},"description":"YYYY-MM inclusive. Default: 11 months before endDate (12-month window). Range max 24 months."},{"name":"endDate","in":"query","schema":{"type":"string","pattern":"^\\d{4}-(0[1-9]|1[0-2])$"},"description":"YYYY-MM inclusive. Default: current month."},{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":500,"default":100},"description":"Max transactions[] rows returned (newest first). Statistics always cover the full matching set."},{"name":"areaMin","in":"query","schema":{"type":"number","exclusiveMinimum":0},"description":"Minimum EXCLUSIVE area (전용면적) in square meters, inclusive. Not supply area (공급면적). Korean \"type\" labels are the integer part of the exclusive area, so a 84 type (\"전용 84\", \"국평\") is 84.00–84.99㎡ — pin it with areaMin=84&areaMax=84.99."},{"name":"areaMax","in":"query","schema":{"type":"number","exclusiveMinimum":0},"description":"Maximum EXCLUSIVE area (전용면적) in square meters, inclusive."},{"name":"groupBy","in":"query","schema":{"type":"string","enum":["month"]},"description":"Set to 'month' to add stats_by_month[] — per-month aggregates over the full matching set. Required for trend questions: transactions[] is capped at `limit`, so a trend cannot be rebuilt from the rows alone. Omitted by default to keep responses small."}],"responses":{"200":{"description":"Statistics and transactions. Shape depends on trade_type (sale vs rent).","content":{"application/json":{"schema":{"oneOf":[{"title":"SaleResponse","type":"object","properties":{"query":{"type":"string","description":"Echo of the q parameter."},"resolved_lawd_cd":{"type":"string","description":"5-digit district (시군구) code the query resolved to."},"resolved_sigungu":{"type":"string","description":"Full district name, e.g. 서울특별시 강남구."},"resolved_dong":{"type":["string","null"],"description":"Neighborhood (법정동/읍면) if the query pinned one."},"resolved_complex":{"type":["string","null"],"description":"Complex name if the query pinned one."},"resolved_note":{"type":"string","description":"Disclosure of every inference or correction made (type/tradeType inferred from q, typo fixes, succession of reorganized districts, ...). Absent when nothing was inferred."},"type":{"type":"string"},"trade_type":{"type":"string"},"period":{"type":"string","description":"Queried period, YYYY-MM~YYYY-MM (inclusive)."},"currency":{"type":"string","const":"KRW"},"count":{"type":"integer","description":"Total matching transactions. Statistics cover ALL matches even when transactions[] is truncated."},"truncated":{"type":"boolean","description":"Present (true) when count > limit; transactions[] holds only the newest `returned` rows."},"returned":{"type":"integer"},"missing_months":{"type":"array","items":{"type":"string"},"description":"Months in the period not yet covered by collection (including future months). Statistics exclude them; retry later for fuller coverage."},"area_min_m2":{"type":"number","description":"Echo of the areaMin filter, present only when one was applied."},"area_max_m2":{"type":"number","description":"Echo of the areaMax filter, present only when one was applied."},"cache":{"type":"string","enum":["hit","miss"]},"source":{"type":"string","description":"Data attribution (legal requirement)."},"price_avg":{"type":["integer","null"],"description":"KRW. Null when count = 0."},"price_min":{"type":["integer","null"]},"price_max":{"type":["integer","null"]},"stats_by_month":{"type":"array","description":"Per-month statistics, newest month first. Present only when groupBy=month. A month with no matching transaction is ABSENT rather than zero — cross-check missing_months to tell \"no coverage\" from \"no transactions\".","items":{"type":"object","properties":{"month":{"type":"string","description":"YYYY-MM."},"count":{"type":"integer"},"price_avg":{"type":["integer","null"]},"price_min":{"type":["integer","null"]},"price_max":{"type":["integer","null"]}}}},"transactions":{"type":"array","items":{"type":"object","properties":{"date":{"type":"string","description":"Contract date, YYYY-MM-DD."},"area_m2":{"type":"number","description":"Exclusive area in square meters."},"floor":{"type":["integer","null"]},"complex":{"type":["string","null"],"description":"Complex/building name (단지명). Null for land etc."},"dong":{"type":["string","null"],"description":"Neighborhood (법정동)."},"price":{"type":"integer","description":"KRW."}}}}}},{"title":"RentResponse","type":"object","properties":{"query":{"type":"string","description":"Echo of the q parameter."},"resolved_lawd_cd":{"type":"string","description":"5-digit district (시군구) code the query resolved to."},"resolved_sigungu":{"type":"string","description":"Full district name, e.g. 서울특별시 강남구."},"resolved_dong":{"type":["string","null"],"description":"Neighborhood (법정동/읍면) if the query pinned one."},"resolved_complex":{"type":["string","null"],"description":"Complex name if the query pinned one."},"resolved_note":{"type":"string","description":"Disclosure of every inference or correction made (type/tradeType inferred from q, typo fixes, succession of reorganized districts, ...). Absent when nothing was inferred."},"type":{"type":"string"},"trade_type":{"type":"string"},"period":{"type":"string","description":"Queried period, YYYY-MM~YYYY-MM (inclusive)."},"currency":{"type":"string","const":"KRW"},"count":{"type":"integer","description":"Total matching transactions. Statistics cover ALL matches even when transactions[] is truncated."},"truncated":{"type":"boolean","description":"Present (true) when count > limit; transactions[] holds only the newest `returned` rows."},"returned":{"type":"integer"},"missing_months":{"type":"array","items":{"type":"string"},"description":"Months in the period not yet covered by collection (including future months). Statistics exclude them; retry later for fuller coverage."},"area_min_m2":{"type":"number","description":"Echo of the areaMin filter, present only when one was applied."},"area_max_m2":{"type":"number","description":"Echo of the areaMax filter, present only when one was applied."},"cache":{"type":"string","enum":["hit","miss"]},"source":{"type":"string","description":"Data attribution (legal requirement)."},"rent_subtype":{"type":"string","enum":["jeonse","wolse"],"description":"Present when a subtype filter applied."},"deposit_avg":{"type":["integer","null"],"description":"KRW (보증금)."},"deposit_min":{"type":["integer","null"]},"deposit_max":{"type":["integer","null"]},"monthly_rent_avg":{"type":["integer","null"],"description":"KRW, averaged over wolse rows only."},"jeonse_count":{"type":"integer"},"wolse_count":{"type":"integer"},"stats_by_month":{"type":"array","description":"Per-month statistics, newest month first. Present only when groupBy=month. A month with no matching transaction is ABSENT rather than zero — cross-check missing_months to tell \"no coverage\" from \"no transactions\".","items":{"type":"object","properties":{"month":{"type":"string","description":"YYYY-MM."},"count":{"type":"integer"},"deposit_avg":{"type":["integer","null"]},"monthly_rent_avg":{"type":["integer","null"],"description":"Averaged over wolse rows only."},"jeonse_count":{"type":"integer"},"wolse_count":{"type":"integer"}}}},"transactions":{"type":"array","items":{"type":"object","properties":{"date":{"type":"string","description":"Contract date, YYYY-MM-DD."},"area_m2":{"type":"number","description":"Exclusive area in square meters."},"floor":{"type":["integer","null"]},"complex":{"type":["string","null"],"description":"Complex/building name (단지명). Null for land etc."},"dong":{"type":["string","null"],"description":"Neighborhood (법정동)."},"deposit":{"type":"integer","description":"KRW."},"monthly_rent":{"type":"integer","description":"KRW; 0 = jeonse."}}}}}}]}}}},"400":{"description":"INVALID_PARAMETER — malformed/unsupported parameters, q too long, contradictory hints in q without a deciding parameter.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","const":"INVALID_PARAMETER"},"message":{"type":"string"}},"required":["error","message"]}}}},"404":{"description":"UNRESOLVED_ADDRESS (no location matched) or COMPLEX_NOT_FOUND (area resolved, complex name unknown). candidates[] may list close matches — retry with one.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["AMBIGUOUS_ADDRESS","UNRESOLVED_ADDRESS","COMPLEX_NOT_FOUND"]},"message":{"type":"string"},"candidates":{"type":"array","items":{"type":"string"},"description":"Alternative interpretations. Pick one and retry with it as q."},"note":{"type":"string"}},"required":["error","message","candidates"]}}}},"422":{"description":"AMBIGUOUS_ADDRESS — several locations match. Pick one from candidates[] and retry with it as q.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["AMBIGUOUS_ADDRESS","UNRESOLVED_ADDRESS","COMPLEX_NOT_FOUND"]},"message":{"type":"string"},"candidates":{"type":"array","items":{"type":"string"},"description":"Alternative interpretations. Pick one and retry with it as q."},"note":{"type":"string"}},"required":["error","message","candidates"]}}}},"429":{"description":"Rate limited (50 requests / 10 seconds per IP). App-level 429s carry Retry-After and a JSON RATE_LIMITED body; an edge-level 429 may not. Wait Retry-After seconds (or ~10s if absent) before retrying.","headers":{"Retry-After":{"description":"Seconds to wait before retrying. Equals the rate-limit period.","schema":{"type":"integer","const":10}}},"content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","const":"RATE_LIMITED"},"message":{"type":"string"}},"required":["error","message"]}}}}}}}}}