# جستجوی مکان و آدرس


<span id="overview"></span>

با این سرویس، کاربر نام یک مکان یا آدرس را وارد می‌کند و فهرستی از نتیجه‌های مرتبط، مانند فروشگاه، خیابان یا محله، دریافت می‌کند.

برای ارسال درخواست از سرور، یک [کلید خصوصی](/dashboard/docs/authentication) با دسترسی این سرویس بسازید.

<span id="use-cases"></span>

## موارد استفاده

- ساخت کادر جستجوی مکان در وب‌سایت یا اپلیکیشن.
- پیشنهاد مکان‌های نزدیک به موقعیت یا محدوده دید کاربر.
- نمایش فقط مکان‌هایی از نوع دلخواه، مانند شهر، محله، خیابان یا POI.

برای همهٔ نوع‌های مکان از [جستجوی عمومی](#search-v5) استفاده کنید. برای محدود کردن خروجی به نوعی مانند شهر یا محله، [جستجو با نوع نتیجه](#search-v4-types) را ببینید.

### موقعیت کاربر و نمای نقشه

اگر کاربر در تهران باشد و نقشه را به شیراز ببرد، `location` موقعیت کاربر و `camera` مرکز نقشه است. برای تعیین منطقهٔ موردنظر، `camera` را همراه درخواست بفرستید.

![نمودار موقعیت کاربر در بیرون کادر نقشه، مرکز نقشه و دو گوشهٔ جنوب‌غربی و شمال‌شرقی](/dashboard/docs/assets/search-context.svg)

در این تصویر شماتیک، `sw` و `ne` دو گوشهٔ کادر نقشه‌اند. این پارامترها زمینهٔ مکانی را مشخص می‌کنند و فیلتر قطعی نتایج داخل کادر نیستند.

<span id="search-v5"></span>

## جستجوی عمومی

`GET https://search.services.balad.ir/v5/service/`

مکان‌ها و آدرس‌های مرتبط با متن ورودی را پیدا می‌کند. برای مشخص‌کردن منطقهٔ جستجو، `camera` را به مرکز منطقهٔ موردنظر تنظیم کنید. این مقدار نتیجه‌ها را به داخل کادر نقشه محدود نمی‌کند.

### جستجو با مرکز مرجع در تهران


#### cURL

```bash
curl --get "https://search.services.balad.ir/v5/service/" \
  --data-urlencode "text=کافه" \
  --data-urlencode "camera=51.3890,35.6892" \
  --data-urlencode "limit=5" \
  -H "Authorization: Bearer <BALAD_API_KEY>"
```


#### Python

```python
# Install: pip install httpx
import httpx

url = "https://search.services.balad.ir/v5/service/"
params = {
    "text": "کافه",
    "camera": "51.3890,35.6892",
    "limit": "5",
}
response = httpx.get(
    url,
    params=params,
    headers={"Authorization": "Bearer <BALAD_API_KEY>"},
    timeout=10.0,
)
response.raise_for_status()
print(response.text)
```


#### Go

```go
package main

import (
	"fmt"
	"io"
	"net/http"
	"net/url"
	"os"
)

func main() {
	endpoint, err := url.Parse("https://search.services.balad.ir/v5/service/")
	if err != nil {
		panic(err)
	}
	query := endpoint.Query()
	query.Set("text", "کافه")
	query.Set("camera", "51.3890,35.6892")
	query.Set("limit", "5")
	endpoint.RawQuery = query.Encode()
	request, err := http.NewRequest("GET", endpoint.String(), nil)
	if err != nil {
		panic(err)
	}
	request.Header.Set("Authorization", "Bearer <BALAD_API_KEY>")
	response, err := http.DefaultClient.Do(request)
	if err != nil {
		panic(err)
	}
	defer response.Body.Close()
	if response.StatusCode < 200 || response.StatusCode >= 300 {
		panic(fmt.Sprintf("HTTP %d", response.StatusCode))
	}
	if _, err := io.Copy(os.Stdout, response.Body); err != nil {
		panic(err)
	}
}
```


#### PowerShell

```powershell
$url = "https://search.services.balad.ir/v5/service/"
$params = @{
    text = "کافه"
    camera = "51.3890,35.6892"
    limit = "5"
}
$query = ($params.GetEnumerator() | ForEach-Object {
    [uri]::EscapeDataString([string]$_.Key) + "=" + [uri]::EscapeDataString([string]$_.Value)
}) -join "&"
$url += "?" + $query
$headers = @{ Authorization = "Bearer <BALAD_API_KEY>" }
Invoke-RestMethod -Uri $url -Headers $headers
```


#### PHP

```php
<?php
// Install: composer require guzzlehttp/guzzle
require __DIR__ . "/vendor/autoload.php";

$client = new \GuzzleHttp\Client();
$response = $client->get("https://search.services.balad.ir/v5/service/", [
    "headers" => ["Authorization" => "Bearer <BALAD_API_KEY>"],
    "query" => [
        "text" => "کافه",
        "camera" => "51.3890,35.6892",
        "limit" => "5",
    ],
    "timeout" => 10,
]);
echo $response->getBody();
```


#### Node.js

```javascript
// Node.js 18+
async function main() {
  const url = new URL("https://search.services.balad.ir/v5/service/");
  const params = {
    text: "کافه",
    camera: "51.3890,35.6892",
    limit: "5",
  };
  url.search = new URLSearchParams(params).toString();
  const response = await fetch(url, {
    headers: { Authorization: "Bearer <BALAD_API_KEY>" },
  });
  if (!response.ok) throw new Error("HTTP " + response.status);
  console.log(await response.text());
}

main().catch((error) => {
  console.error(error);
  process.exitCode = 1;
});
```




### نمونه پاسخ

```json
{
  "results": [
    {
      "id": "poi:12345",
      "type": "poi",
      "maintext": "کافه مثال",
      "subtitle": "تهران، خیابان انقلاب",
      "center_point": { "lat": 35.7001, "lng": 51.3911 },
      "neighborhood_name": "فردوسی"
    }
  ]
}
```

### پارامترها

| نام | نوع | اجباری | پیش‌فرض | توضیح |
| --- | --- | --- | --- | --- |
| `text` | `string` | بله | ندارد | عبارت جستجو؛ مانند نام مکان، خیابان یا آدرس. |
| `location` | `string` | خیر | ندارد | موقعیت جغرافیایی کاربر، مثلاً از GPS، به ترتیب طول و عرض جغرافیایی: `51.3890,35.6892`. با مرکز نقشه فرق دارد؛ برای تعیین منطقهٔ جستجو به‌تنهایی به این پارامتر تکیه نکنید و `camera` را هم بفرستید. |
| `camera` | `string` | خیر | ندارد | مرکز نمای فعلی نقشه به ترتیب `longitude,latitude`؛ مانند `51.3890,35.6892`. بدون نقشه هم می‌توانید مرکز منطقهٔ موردنظر را بفرستید. برای جستجوی اطراف کاربر، آن را برابر موقعیت کاربر بگذارید. |
| `sw` | `string` | خیر | ندارد | گوشهٔ جنوب‌غربی کادر دیده‌شدهٔ نقشه، به ترتیب `longitude,latitude`؛ مانند `51.30,35.65`. همراه `ne` بفرستید تا سرویس موقعیت کاربر را نسبت به نمای نقشه بسنجد؛ این کادر فیلتر قطعی نتایج نیست. |
| `ne` | `string` | خیر | ندارد | گوشهٔ شمال‌شرقی همان کادر، به ترتیب `longitude,latitude`؛ مانند `51.50,35.80`. همراه `sw` بفرستید؛ طول و عرض این گوشه باید از طول و عرض گوشهٔ `sw` بیشتر باشند. |
| `zoom` | `number` | خیر | ندارد | بزرگ‌نمایی فعلی نقشه؛ عدد بزرگ‌تر یعنی نمای نزدیک‌تر و مقدار اعشاری هم پذیرفته می‌شود، مانند `14.5`. همراه `location`، `camera`، `sw` و `ne` در انتخاب موقعیت مرجع نقش دارد؛ شعاع جستجو بر حسب کیلومتر نیست. |
| `limit` | `integer` | خیر | `10` | حداکثر تعداد نتایج. مقدارهای رایج بین `1` تا `40` هستند. |

### فیلدهای پاسخ

| نام | نوع | توضیح |
| --- | --- | --- |
| `results` | `array<object>` | فهرست نتایج جستجو به ترتیب ارتباط و نزدیکی. |
| `results[].id` | `string` | شناسه داخلی نتیجه. |
| `results[].type` | `string` | نوع مکان: `poi` مکان مشخص مثل کافه یا بیمارستان؛ `road` معبر مثل خیابان یا کوچه؛ `roundabout` میدان؛ `neighborhood` محله؛ `city` شهر؛ `county` شهرستان؛ `province` استان؛ `village` روستا. |
| `results[].maintext` | `string` | عنوان اصلی نتیجه برای نمایش. |
| `results[].subtitle` | `string` | توضیح کوتاه یا آدرس مکمل. |
| `results[].center_point` | `object` | مختصات مرکز نتیجه. |
| `results[].geometry` | `object` | هندسه نتیجه، در صورت وجود. |
| `results[].neighborhood_name` | `string` | نام محله مرتبط، در صورت وجود. |

### کدهای وضعیت

کدهای مستند این درخواست: `200`، `204`، `400`، `401`، `403`، `404`، `429`، `5xx`. [معنی کدها و راه بررسی خطا](/dashboard/docs/status-codes)

<span id="search-v4-types"></span>

## جستجو با نوع نتیجه

`GET https://search.services.balad.ir/v4/service/{result_types}/`

جستجو را به یک یا چند نوع نتیجه محدود می‌کند. برای این مسیر، باید یکی از `location` یا `location_city` را بفرستید.

### جستجوی شهر


#### cURL

```bash
curl --get "https://search.services.balad.ir/v4/service/city/" \
  --data-urlencode "text=تهران" \
  --data-urlencode "location=51.3890,35.6892" \
  -H "Authorization: Bearer <BALAD_API_KEY>"
```


#### Python

```python
# Install: pip install httpx
import httpx

url = "https://search.services.balad.ir/v4/service/city/"
params = {
    "text": "تهران",
    "location": "51.3890,35.6892",
}
response = httpx.get(
    url,
    params=params,
    headers={"Authorization": "Bearer <BALAD_API_KEY>"},
    timeout=10.0,
)
response.raise_for_status()
print(response.text)
```


#### Go

```go
package main

import (
	"fmt"
	"io"
	"net/http"
	"net/url"
	"os"
)

func main() {
	endpoint, err := url.Parse("https://search.services.balad.ir/v4/service/city/")
	if err != nil {
		panic(err)
	}
	query := endpoint.Query()
	query.Set("text", "تهران")
	query.Set("location", "51.3890,35.6892")
	endpoint.RawQuery = query.Encode()
	request, err := http.NewRequest("GET", endpoint.String(), nil)
	if err != nil {
		panic(err)
	}
	request.Header.Set("Authorization", "Bearer <BALAD_API_KEY>")
	response, err := http.DefaultClient.Do(request)
	if err != nil {
		panic(err)
	}
	defer response.Body.Close()
	if response.StatusCode < 200 || response.StatusCode >= 300 {
		panic(fmt.Sprintf("HTTP %d", response.StatusCode))
	}
	if _, err := io.Copy(os.Stdout, response.Body); err != nil {
		panic(err)
	}
}
```


#### PowerShell

```powershell
$url = "https://search.services.balad.ir/v4/service/city/"
$params = @{
    text = "تهران"
    location = "51.3890,35.6892"
}
$query = ($params.GetEnumerator() | ForEach-Object {
    [uri]::EscapeDataString([string]$_.Key) + "=" + [uri]::EscapeDataString([string]$_.Value)
}) -join "&"
$url += "?" + $query
$headers = @{ Authorization = "Bearer <BALAD_API_KEY>" }
Invoke-RestMethod -Uri $url -Headers $headers
```


#### PHP

```php
<?php
// Install: composer require guzzlehttp/guzzle
require __DIR__ . "/vendor/autoload.php";

$client = new \GuzzleHttp\Client();
$response = $client->get("https://search.services.balad.ir/v4/service/city/", [
    "headers" => ["Authorization" => "Bearer <BALAD_API_KEY>"],
    "query" => [
        "text" => "تهران",
        "location" => "51.3890,35.6892",
    ],
    "timeout" => 10,
]);
echo $response->getBody();
```


#### Node.js

```javascript
// Node.js 18+
async function main() {
  const url = new URL("https://search.services.balad.ir/v4/service/city/");
  const params = {
    text: "تهران",
    location: "51.3890,35.6892",
  };
  url.search = new URLSearchParams(params).toString();
  const response = await fetch(url, {
    headers: { Authorization: "Bearer <BALAD_API_KEY>" },
  });
  if (!response.ok) throw new Error("HTTP " + response.status);
  console.log(await response.text());
}

main().catch((error) => {
  console.error(error);
  process.exitCode = 1;
});
```




### نمونه پاسخ

```json
{
  "results": [
    {
      "id": "city:tehran",
      "type": "city",
      "maintext": "تهران",
      "subtitle": "استان تهران",
      "center_point": { "lat": 35.6892, "lng": 51.3890 }
    }
  ]
}
```

### پارامترها

| نام | نوع | اجباری | پیش‌فرض | توضیح |
| --- | --- | --- | --- | --- |
| `result_types` | `path string` | بله | ندارد | نوع یا چند نوع جداشده با ویرگول در مسیر؛ مانند `city,neighborhood`. مقدارهای مجاز: `city` شهر؛ `county` شهرستان؛ `neighborhood` محله؛ `road` معبر مثل خیابان یا کوچه؛ `road_intersection` تقاطع معابر؛ `roundabout` میدان؛ `poi` مکان مشخص مثل فروشگاه یا بیمارستان. |
| `text` | `string` | بله | ندارد | عبارت جستجو. |
| `location` | `string` | خیر | ندارد | مختصات مرجع در قالب `longitude,latitude`؛ در صورت ارسال نشدن `location_city`، الزامی است. |
| `location_city` | `string` | خیر | ندارد | شهر مرجع جستجو؛ در صورت ارسال نشدن `location`، الزامی است. |

### فیلدهای پاسخ

| نام | نوع | توضیح |
| --- | --- | --- |
| `results` | `array<object>` | نتایج محدودشده به نوع یا نوع‌های انتخابی. |
| `results[].id` | `string` | شناسه نتیجه. |
| `results[].type` | `string` | نوع نتیجه از میان نوع‌های انتخاب‌شده در `result_types`؛ معنی هر مقدار در جدول پارامترها آمده است. برای مکان مشخصی که توکن POI در پاسخ آن موجود نیست، ممکن است `other-poi` به‌جای `poi` برگردد. |
| `results[].maintext` | `string` | عنوان اصلی نتیجه. |
| `results[].subtitle` | `string` | متن مکمل یا آدرس. |
| `results[].center_point` | `object` | مختصات مرکز نتیجه. |

### کدهای وضعیت

کدهای مستند این درخواست: `200`، `204`، `400`، `401`، `403`، `404`، `429`، `5xx`. [معنی کدها و راه بررسی خطا](/dashboard/docs/status-codes)
