# Bamelak AI — Private Tehran Property Pricing API Version: 1.0.3 Base URL: https://ai.bamelak.com OpenAPI: https://ai.bamelak.com/api/openapi Human documentation: https://ai.bamelak.com/api-docs ## Authentication All /api/v1 endpoints require Authorization: Bearer . An administrator creates and revokes keys at https://ai.bamelak.com/api-dashboard. API keys cannot access the admin panel or start discovery/update jobs. Send Content-Type: application/json. Limit: 60 requests per minute per key; maximum body 16KB. Never put credentials in the URL or JSON body. Request/response logs are retained for 90 days. Every price is in TOMAN (not IRR/rial). Area is in square meters. Coordinates use WGS84 decimal latitude/longitude. Coverage: Tehran municipal districts 1, 2 and 3 only. ## POST /api/v1/estimate Required: latitude (number), longitude (number), area (positive number <=10000), propertyType (apartment|house|land). Optional district: "1"|"2"|"3". It must agree with coordinates; the server determines district using stored approximate municipal polygons. Optional numeric fields: buildingAge (0..150), bedrooms (0..20), bathrooms (0..20), floor (-10..100), totalFloors (1..100), parkingSpaces (0..20), landArea (positive <=100000). Optional boolean fields: elevator, parking, storage, renovated, balcony, swimmingPool, saunaJacuzzi, gym, lobby, concierge, roofGarden, centralCooling, premiumView. Optional neighborhood: string <=80 characters. Omitted features use the existing model defaults. For land, landArea takes precedence over area for total price. Example input: {"latitude":35.769,"longitude":51.453,"area":100,"propertyType":"apartment","buildingAge":10,"parking":true,"elevator":true} Success: {"requestId":"UUID","data":{"calculationId":"...","district":"3","currency":"toman","area":100,"price":{"minimum":NUMBER,"middle":NUMBER,"maximum":NUMBER},"pricePerM2":{"minimum":NUMBER,"middle":NUMBER,"maximum":NUMBER},"confidence":"low|medium|high","calibrationSampleCount":NUMBER,"createdAt":"ISO8601","disclaimer":"..."}} Uses the current calibrated model, active local observations and nearby market evidence. Sparse evidence can yield low confidence; do not call this a verified transaction price. ## POST /api/v1/neighborhood-price — قیمت میانگین محله Input uses a NAME, no coordinates. Required neighborhood: Persian string 2..80 chars. Optional district: "1"|"2"|"3"; propertyType defaults to apartment; optional area returns estimated totals. Example input: {"neighborhood":"دروس","district":"3","area":100} The server normalizes Persian/Arabic letters and spacing, resolves catalog names/aliases and unambiguous single-letter spelling mistakes. Catalog aliases that describe distinct market areas keep their exact sample name (e.g. الهیه); prices are never substituted from another neighborhood. Uses active observations dated within 180 days, excludes demo data and archived comparables, deduplicates linked calibration/comparable rows and removes 1.5*IQR outliers. Requires at least 3 recent observations; otherwise returns INSUFFICIENT_DATA without making up a price. Success data: neighborhood, canonicalNeighborhood, requestedNeighborhood, district, matchedBy, propertyType, currency="toman", pricePerM2={minimum,average,middle,maximum}, totalPrice=same fields or null, area, location, evidence, confidence, method, createdAt. minimum=P10; maximum=P90; middle=median; average=arithmetic mean after outlier removal. This is an observed distribution, not a property's valuation interval. location is the sample centroid with precision="sample-centroid", not the official neighborhood boundary. evidence: sampleCount, excludedOutliers, verifiedCount, askingPriceCount, oldestDate, latestDate, maximumAgeDays=180. Converted Divar calibrations remain asking-price-derived evidence even if their listing was reviewed and the calibration row has a verified flag. Confidence is sample-size based (3..7 low, 8..19 medium, >=20 high); inspect verifiedCount and askingPriceCount before treating it as transaction evidence. Property features are heterogeneous: totalPrice is a neighborhood benchmark times area, not an individualized estimate. ## Errors { "requestId": "UUID", "error": { "code": "CODE", "message": "description", "details": OPTIONAL_OBJECT } } 401 UNAUTHORIZED; 429 RATE_LIMITED (Retry-After: 60); 415 JSON_REQUIRED; 413 BODY_TOO_LARGE; 400 INVALID_JSON; 422 VALIDATION_ERROR / OUTSIDE_COVERAGE / INSUFFICIENT_DATA; 404 UNKNOWN_NEIGHBORHOOD; 409 AMBIGUOUS_NEIGHBORHOOD; 500 INTERNAL_ERROR. Unknown input fields are rejected. Do not repeatedly retry invalid/insufficient requests. Retry 429 after the header delay; retry temporary 500 sparingly. ## Supported catalog District 1: اراج؛ ازگل؛ امامزاده قاسم؛ اوین؛ باغ فردوس؛ تجریش؛ جماران؛ چیذر؛ حصار بوعلی؛ حکمت؛ دارآباد؛ دربند؛ درکه؛ دزاشیب؛ زعفرانیه؛ سوهانک؛ شهرک دانشگاه؛ شهرک نفت؛ شهرک شهید محلاتی (aliases: شهرک محلاتی)؛ فرمانیه (aliases: کامرانیه شمالی)؛ قیطریه؛ کاشانک؛ کوهسار؛ گلابدره؛ محمودیه (aliases: الهیه، فرشته)؛ نیاوران (aliases: اقدسیه)؛ ولنجک District 2: پونک؛ تهران ویلا (aliases: تهران‌ویلا)؛ دریان نو (aliases: دریان‌نو، شادمهر)؛ سعادت آباد (aliases: سعادت‌آباد)؛ شهرآرا؛ شهرک غرب (aliases: شهرک قدس)؛ صادقیه (aliases: آریاشهر)؛ طرشت؛ فرحزاد؛ گیشا (aliases: کوی نصر)؛ شهرک آزمایش؛ ستارخان؛ مرزداران (aliases: شهرک ژاندارمری)؛ آسمان؛ بهرود؛ پرواز؛ دریا؛ سپهر؛ ایوانک؛ شریف؛ توحید District 3: آرارات؛ امانیه (aliases: جردن، آفریقا)؛ اختیاریه (aliases: دولت، دیباجی، رستم آباد)؛ پاسداران؛ دروس؛ داودیه (aliases: میرداماد)؛ زرگنده؛ سیدخندان (aliases: سید خندان)؛ قلهک؛ کاوسیه (aliases: ظفر)؛ ونک؛ ده ونک (aliases: ده‌ونک) ## curl examples curl -X POST 'https://ai.bamelak.com/api/v1/neighborhood-price' -H 'Authorization: Bearer YOUR_API_KEY' -H 'Content-Type: application/json' -d '{"neighborhood":"دروس","area":100}' curl -X POST 'https://ai.bamelak.com/api/v1/estimate' -H 'Authorization: Bearer YOUR_API_KEY' -H 'Content-Type: application/json' -d '{"latitude":35.769,"longitude":51.453,"area":100,"propertyType":"apartment"}'