# Документация Подключите карту, адресный поиск, маршрут и матрицу расстояний к своему сайту или приложению. ## С чего начать Для карты достаточно подключить JavaScript и CSS SDK **1.0.0-rc.9**. Регистрация и ключ не нужны. Для поиска адресов, расчёта маршрута и матрицы создайте проект и API-ключ. API можно попробовать в пределах бесплатной квоты после регистрации и подтверждения email. Пополнять баланс и привязывать банковскую карту для этого не нужно. [Получить ключ и выполнить первый запрос](https://mmapps.ru/docs/getting-started). | Задача | Раздел | | --- | --- | | Выполнить первый запрос API | [Быстрый старт](https://mmapps.ru/docs/getting-started) | | Добавить карту на страницу | [Подключение карты](https://mmapps.ru/docs/maps) | | Работать с объектами, событиями и интерфейсом карты | [Полный справочник SDK RC9](https://mmapps.ru/docs/sdk) | | Найти адрес или координаты | [Поиск адресов](https://mmapps.ru/docs/addresses) | | Рассчитать автомобильный путь | [Маршрут](https://mmapps.ru/docs/routes) | | Сравнить расстояния и время между точками | [Матрица расстояний](https://mmapps.ru/docs/matrix) | | Выдать права и ограничить доступ | [Ключи API](https://mmapps.ru/docs/keys) | | Узнать цену и контролировать расходы | [Расходы и лимиты](https://mmapps.ru/docs/billing) | ## Справочники и файлы - [OpenAPI](https://mmapps.ru/gateway.openapi.yaml) — HTTP-методы, поля запросов и ответов, ошибки и ограничения. - [Типы SDK](https://cdn.mmapps.ru/sdk/1.0.0-rc.9/index.d.ts) — точные сигнатуры JavaScript API в формате TypeScript. - [Список разделов в Markdown](https://mmapps.ru/llms.txt). - [Вся документация одним файлом](https://mmapps.ru/llms-full.txt). На каждой странице есть оглавление, кнопки копирования примеров и ссылка на Markdown. В примерах замените условный ключ своим, а адреса и координаты — данными Вашего приложения. ## Условия использования Карта и SDK бесплатны. Запросы сервисного API используют бесплатную квоту, а после её исчерпания — баланс аккаунта. Расчёт матрицы учитывается по числу пар точек. Доступность операций и права ключа проверяйте в кабинете. Ммаппс можно использовать в CRM и других приложениях за авторизацией. Результаты API разрешено сохранять в своей базе и использовать повторно с соблюдением лицензий исходных данных и требований к персональным данным. [Подробнее о хранении и оплате](https://mmapps.ru/docs/billing). [Пользовательское соглашение](https://mmapps.ru/documents/terms), [обработка персональных данных](https://mmapps.ru/documents/terms#privacy) и [лицензии SDK и карты](https://mmapps.ru/documents/sdk-license). ## Чтение без интернета После первого посещения и сохранения страниц документацию можно читать без сети. Добавить сайт на устройство можно через меню браузера. Для загрузки карты, запросов API и работы с кабинетом нужен интернет. --- # Быстрый старт Создайте ключ и выполните первый запрос к API Ммаппс. ## Выберите способ подключения Если нужна только карта, начните с [примера без ключа](https://mmapps.ru/docs/maps). Следующие шаги нужны для поиска адресов, маршрута и матрицы. ## Попробуйте API бесплатно После регистрации и подтверждения email Вы можете выпустить личный API-ключ и выполнять запросы в пределах [бесплатной месячной квоты](https://mmapps.ru/docs/billing). Пополнять баланс и привязывать банковскую карту для этого не нужно. Проверьте поиск на адресах, с которыми работает Ваш бизнес. Когда квота закончится, новые платные запросы потребуют средств на балансе и доступного бюджета. Регистрация для бесплатной карты по-прежнему не нужна. ## Создайте проект и ключ 1. [Зарегистрируйтесь](https://mmapps.ru/app/register), подтвердите email и откройте [«Проекты и ключи»](https://mmapps.ru/app/projects). 2. Используйте основной проект или создайте отдельный для своего приложения. 3. Нажмите «Создать ключ», выберите «На сервере» и разрешите подсказки адресов (`search`). 4. Скопируйте ключ: полностью он показывается один раз. Сохраните его в приватных настройках сервера. Для JavaScript в браузере создайте отдельный ключ «На сайте» и укажите разрешённый сайт. Серверный ключ в браузер не передавайте. [Подробнее о правах и хранении](https://mmapps.ru/docs/keys). ## Выполните запрос Базовый адрес API — `https://mmapps.ru`. Переменная окружения `MMAPPS_SERVER_KEY` в примере должна содержать Ваш серверный ключ. `YOUR_SERVER_KEY` — условное обозначение, а не действующий ключ. ```bash curl --request POST 'https://mmapps.ru/v1/search' \ --header "Authorization: Bearer ${MMAPPS_SERVER_KEY}" \ --header 'Content-Type: application/json' \ --header 'Accept: application/json' \ --header 'Idempotency-Key: 4c9cc4ef-b924-40df-8f61-c36a865b2d7e' \ --data '{"q":"Примерная улица","limit":5}' ``` Замените «Примерная улица» на нужный Вам адрес. Для каждого нового запроса создавайте новый `Idempotency-Key`. Если повторяете тот же запрос, сохраните прежний ключ и тело. ## Обработайте ответ Читайте `outcome` и список `candidates`. Отобразите `candidate.label` и предложите пользователю выбрать подходящий адрес. `candidate.point` может быть `null`: такой вариант нельзя использовать как координату. `ref` сохраняйте целиком, включая `id` и `dataset_version`. HTTP 200 может означать, что вариантов нет или нужно уточнить запрос. Форматы и значения результатов описаны в [разделе поиска](https://mmapps.ru/docs/addresses). ## Проверьте расход Откройте [«Использование»](https://mmapps.ru/app/usage), затем задайте бюджет в [«Лимиты и уведомления»](https://mmapps.ru/app/limits). Бесплатная квота общая для проектов аккаунта. Для диагностики сохраняйте код ошибки и `X-Request-Id`. Не записывайте API-ключи, адреса пользователей и координаты в журналы ошибок и аналитику. --- # Подключение бесплатной карты Карта и JavaScript SDK работают без регистрации и API-ключа. ## Минимальный пример Сохраните HTML и откройте его через веб-сервер. Контейнеру карты нужна явная высота. JS и CSS подключайте из одной версии SDK — **1.0.0-rc.9**. ```html Карта Ммаппс
``` Подложка загружается с публичного CDN. Не добавляйте к этим запросам API-ключ, заголовок Authorization или cookies. Если подключаете файлы SDK со своего сервера, сохраняйте весь комплект выпуска, включая worker рядом с `index.js` и лицензионные файлы. ## Добавьте метку Следующий код выполняется после создания карты: ```javascript const marker = map.objects.add({ id: 'office', kind: 'marker', point: { latitude: 55.75, longitude: 37.61 }, label: 'Пример офиса', style: { color: '#1187ff' }, }); marker.on('click', () => { marker.popup.open({ text: 'Пример карточки места' }); }); ``` Замените координаты на положение Вашего офиса. Используйте `text` для текста карточки, а для собственного оформления — DOM-элемент. [Объекты, коллекции, GeoJSON и кластеры](https://mmapps.ru/docs/sdk#obieekty-i-kollekcii). ## Подключите поиск [Зарегистрируйтесь](https://mmapps.ru/app/register) и создайте ключ «На сайте» с правами `search`, `geocode`, `reverse` и добавьте адрес Вашего сайта в разрешённые. `YOUR_BROWSER_KEY` ниже заменяется этим браузерным ключом. ```javascript import { createSearchController } from 'https://cdn.mmapps.ru/sdk/1.0.0-rc.9/index.js'; const services = createClient({ apiBaseUrl: 'https://mmapps.ru', apiKey: 'YOUR_BROWSER_KEY', }); const controller = createSearchController({ client: services.geocoder, map, fitResults: true, }); const search = map.controls.addSearch({ controller, position: 'top-left', onSelect(selection) { // Сохраните selection.ref и selection.point в состоянии приложения. }, }); // При удалении компонента: // search.remove(); controller.destroy(); services.destroy(); ``` Выбор строки — локальное действие без повторного геокодинга. `selection.point` может быть `null`, `selection.queryPoint` сохраняет исходную точку обратного поиска. Кнопки маршрута и передачи результата подключаются через `onRoute` и `onShare`. [Все методы поиска](https://mmapps.ru/docs/sdk#poisk-i-vybor-adresa). ## Тема и номера домов `theme: 'light'` или `'dark'` задаёт тему при создании, `map.setTheme()` меняет её позже. Для поддерживаемой подложки настройка `houseNumbers` управляет появлением и размером номеров: ```javascript const map = await geo.createMap({ element: document.getElementById('map'), mapId: 'ru', houseNumbers: { minZoom: 15.5, sizeScale: 0.88 }, }); ``` `minZoom` — масштаб появления подписей, `sizeScale` — множитель размера шрифта. Настройка не добавляет отсутствующие номера в данные. Не создавайте две карты в одном контейнере: пример выше заменяет параметры первого вызова. ## Готовый виджет и дополнительные возможности `createMapWidget()` объединяет карту, поиск, редактор маршрута, меню точки и при необходимости таймлайн. Передайте только сервисы, которые нужны приложению. Бесплатная карта работает и без них. SDK также поддерживает собственные маркеры, карточки, линии, полигоны, окружности, кластеры, управление камерой и воспроизведение Ваших временных данных. [Полный справочник SDK RC9](https://mmapps.ru/docs/sdk). ## Освобождение ресурсов При удалении карты вызывайте `map.destroy()`. Если использовали виджет — `widget.destroy()`. Отдельно созданные контроллеры, таймлайн и API-клиент освобождайте через их `destroy()`; функции, возвращённые `on()`, отменяют подписку на событие. Перемещение карты, отображение объектов и готовой линии маршрута бесплатны. Поиск, расчёт маршрута и матрицы — отдельные запросы сервисного API. [Тарифы](https://mmapps.ru/docs/billing). --- # JavaScript SDK RC9 Справочник публичных методов, параметров и событий SDK 1.0.0-rc.9. ## Подключение и типы SDK поставляется как браузерный ES-модуль. Подключите `https://cdn.mmapps.ru/sdk/1.0.0-rc.9/index.css`, затем импортируйте нужные функции из `https://cdn.mmapps.ru/sdk/1.0.0-rc.9/index.js`. [Готовая HTML-страница](https://mmapps.ru/docs/maps). Точные типы поставляются вместе с выпуском: [точка входа TypeScript](https://cdn.mmapps.ru/sdk/1.0.0-rc.9/index.d.ts), [экспорты SDK](https://cdn.mmapps.ru/sdk/1.0.0-rc.9/types/clients/maps/index.d.ts). Ссылки на типы ниже относятся к той же версии. Обозначение `?` в сигнатурах означает необязательный аргумент. | Экспорт | Назначение | | --- | --- | | `createClient` | Карта и клиент сервисного API | | `createMap` | Отдельная карта | | `createMapWidget` | Карта с готовыми инструментами | | `checkedPoint` | Проверка координат | | `createGeocoder` | Адресный клиент со своим обработчиком запросов | | `createSearchController` | Состояние поиска и выбор адреса | | `attachSearchControl` | Форма поиска в DOM-контейнере | | `attachRouteControl` | Редактор маршрута | | `attachContextMenu` | Меню действий с точкой | | `createRouteOverlay` | Отображение рассчитанного маршрута | | `routeView`, `routeCandidates`, `geocodedRouteView` | Подготовка ответа маршрута для интерфейса | | `matrixView`, `geocodedMatrixView` | Проверка ответа матрицы | | `createTimeline`, `attachTimelineControl` | Временные данные и панель воспроизведения | | `MapSDKError`, `GeocoderError` | Классы ошибок | ## Клиент и сервисные запросы `createClient(options?) → GeoClient`. Без параметров создаёт клиент бесплатной карты. Параметры `ClientOptions`: `apiBaseUrl`, `apiKey`, `catalogUrl`, `fetch`, `timeoutMs`. ```javascript import { createClient } from 'https://cdn.mmapps.ru/sdk/1.0.0-rc.9/index.js'; const geo = createClient({ apiBaseUrl: 'https://mmapps.ru', apiKey: 'YOUR_BROWSER_KEY', }); const operationKey = crypto.randomUUID(); const result = await geo.geocoder.search( { q: 'Примерная улица', limit: 5 }, { operationKey }, ); ``` `apiBaseUrl` — адрес API без пути, параметров и фрагмента. Для сервисных вызовов используйте HTTPS и браузерный ключ с нужными правами и разрешённым origin. `YOUR_BROWSER_KEY` — условное обозначение. Серверный ключ в SDK не передавайте. | Метод | Результат | | --- | --- | | `geo.createMap(options)` | `Promise` | | `geo.geocoder.search(query, options?)` | Подсказки адресов | | `geo.geocoder.geocode(query, options?)` | Координаты по адресу | | `geo.geocoder.reverse(query, options?)` | Адрес по точке | | `geo.geocoder.resolve(ref, options?)` | Выбранный объект | | `geo.routes.calculate(request, options?)` | Маршрут по координатам | | `geo.routes.geocode(request, options?)` | Маршрут по адресам и подтверждённым точкам | | `geo.routes.matrix(request, options?)` | Матрица по координатам | | `geo.routes.matrixGeocode(request, options?)` | Матрица по адресам и подтверждённым точкам | | `geo.on('usage', callback)` | Подписка на учёт операции; возвращает функцию отписки | | `geo.on('error', callback)` | Подписка на ошибку; возвращает функцию отписки | | `geo.destroy()` | Завершение работы клиента | `OperationOptions` содержит `signal?: AbortSignal` и `operationKey?: string`. Для повторов сохраняйте ключ и тело запроса; изменение данных — новая операция. Если ключ не задан, SDK создаёт его сам. Отмена ожидания через `signal` не доказывает, что запрос не успел выполниться. `usage` передаёт `operationId`, `requestId`, `chargedMicrorub`, `funding`, `retryAfter`, `stage`. При наличии в ответе доступны `quantity`, `freeUnits`, `paidUnits`, `meter`. Суммы и количества передаются строками. [Правила оплаты](https://mmapps.ru/docs/billing), [типы клиента](https://cdn.mmapps.ru/sdk/1.0.0-rc.9/types/clients/maps/client.d.ts). ## Создание карты `createMap(options) → Promise` и `geo.createMap(options) → Promise`. После создания дождитесь `map.ready`. | Параметр | Назначение | | --- | --- | | `element` | Обязательный DOM-контейнер с заданной высотой | | `mapId`, `catalogUrl` | Выбор карты и каталога у `geo.createMap`; по умолчанию `ru` и публичный каталог | | `styleUrl` | URL собственного публичного стиля | | `basemap` | `{type: 'public', styleUrl, …}` или `{type: 'public_cdn', catalogUrl, mapId}` | | `view` | Начальные `center`, `zoom`, `bearing`, `pitch` | | `initialPoint`, `editable` | Исходная точка и возможность её изменения | | `theme` | `'light'` или `'dark'` | | `houseNumbers` | `{minZoom?, sizeScale?}` для поддерживаемой подложки | | `controls`, `interactions` | Инструменты и жесты, описанные ниже | | `renderMarker` | Отрисовщик маркера исходной точки и совместимых маркеров | | `workerUrl` | URL worker из того же выпуска | | `signal`, `timeoutMs` | Отмена и таймаут загрузки | | `fetch` | Свой fetch у `createMap`; для `geo.createMap` задаётся на клиенте | | `onReady`, `onLoading`, `onError` | Обратные вызовы состояния | У публичного `basemap` дополнительно возможны `styleSha256`, `styleBytes`, `assetSizes`. Для обычного подключения достаточно `mapId`. `houseNumbers.minZoom` принимает 0–20, `sizeScale` — 0,5–2; стандартные значения — 16 и 1. Настройки меняют существующие подписи, а не добавляют данные. Координаты `GeoPoint` имеют вид `{latitude, longitude}`. `checkedPoint(latitude, longitude)` проверяет конечные числа и диапазоны WGS84. GeoJSON использует обратный порядок: `[longitude, latitude]`. `Bounds` — `{west, south, east, north}`, экранная точка — `{x, y}`. ## Состояние и события карты | Метод или поле | Назначение | | --- | --- | | `map.ready` | Ожидание готовности | | `map.getState()` | `loading`, `ready`, `degraded`, `failed`, `destroyed` | | `map.waitForIdle({signal?, timeoutMs?}?)` | Ожидание завершения текущей отрисовки | | `map.resize()` | Обновление размера после изменения контейнера | | `map.setTheme(theme)` | Смена светлой или тёмной темы | | `map.setBasemap(basemap)` | Асинхронная смена подложки с сохранением камеры и объектов | | `map.setPoint(point)` | Установка исходной точки; `null` удаляет её | | `map.getQueryPoint()` | Исходная точка или `null` | | `map.focusPoint(point, zoom?)` | Фокус на точке | | `map.fitPoints(points, options?)`, `map.fitVisible(options?)` | Подбор видимой области | | `map.on(type, callback)`, `map.once(type, callback)` | Подписка, возвращающая отписку | | `map.off(type, callback)` | Отмена подписки | | `map.onPointChange(callback)` | Изменение исходной точки, причина `drag` или `click` | | `map.onMarkerClick(callback)` | Клик по совместимому маркеру | | `map.destroy()` | Удаление карты и принадлежащих ей ресурсов | События указателя: `click`, `dblclick`, `contextmenu`, `mousemove`, `mouseenter`, `mouseleave`, `pointerdown`, `pointerup`, `touchstart`, `touchend`. События камеры: `move`, `movestart`, `moveend`, `zoom`, `zoomend`, `rotate`, `pitch`, `resize`, `idle`. Состояние: `statechange`, `error`, `destroy`. Событие указателя содержит `point`, `screen`, `objectId`, `originalEvent`, `stopPropagation()` и `preventDefault()`. [Типы карты и событий](https://cdn.mmapps.ru/sdk/1.0.0-rc.9/types/clients/maps/types.d.ts). Для существующих интеграций сохранены `setVisits(points)`, `setMarkers(points)`, `setTracks(tracks)`. Они принимают типы `MapPoint` и `Track`; при новом подключении используйте `objects` и `createRouteOverlay`. [Типы совместимых методов](https://cdn.mmapps.ru/sdk/1.0.0-rc.9/types/frontend-contracts.d.ts). ## Камера и жесты | `map.camera` | Назначение | | --- | --- | | `getState()`, `getCenter()`, `getZoom()`, `getBounds()` | Чтение вида | | `setView(view, transition?)` | Центр, масштаб, поворот и наклон | | `panTo(point, transition?)` | Перемещение центра | | `setZoom(zoom, transition?)`, `zoomIn(transition?)`, `zoomOut(transition?)` | Масштаб | | `fitBounds(bounds, options?)` | Показать область | | `fitObjects(ids?, options?)` | Показать объекты | | `project(point)`, `unproject(screenPoint)` | Перевод между координатами и пикселями | | `setLimits({minZoom?, maxZoom?, bounds?})` | Ограничение камеры; `bounds: null` снимает границу | | `stop()` | Остановка анимации | `transition` задаёт `duration` и `mode: 'ease'`, `'fly'` или `'jump'`. `FitOptions` содержит `maxZoom`, `duration`, `padding` (число или отступы по четырём сторонам), `resetOrientation`. `map.interactions.getState()`, `set(options)`, `enable()`, `disable()` управляют жестами. Параметры: `dragPan`, `scrollZoom` (boolean или `'cooperative'`), `doubleClickZoom`, `touchZoom`, `touchRotate`, `dragRotate`, `touchPitch`, `keyboard`. ## Объекты и коллекции `map.objects.add(object)` возвращает `ObjectHandle`. У каждого объекта обязательны уникальный `id` и `kind`. | `kind` | Геометрия | Сокращённый метод | | --- | --- | --- | | `marker` | `point`, необязательные `draggable`, `renderer` | `addMarker(object)` | | `line` | `points` | `addLine(object)` | | `polygon` | `rings` | `addPolygon(object)` | | `circle` | `center`, `radiusM` | `addCircle(object)` | | `rectangle` | `bounds` | `addRectangle(object)` | | `geojson` | `geometry` | `add({id, kind: 'geojson', geometry})` | Сокращённые методы принимают те же поля без `kind`. Общие параметры: `label`, `properties`, `visible`, `selected`, `style`, `collection`, `zIndex`. Стиль: `color`, `fillColor`, `width`, `opacity`, `fillOpacity`, `radius`, `dash`. `objects` также предоставляет `get(id)`, `getAll()`, `remove(id)`, `clear()`, `replace(objects)`, `getBounds(ids?)`, `toGeoJSON(ids?)`, `importGeoJSON(value, {replace?, collection?}?)`. `batch(changes)` принимает записи `{action: 'upsert', object}` или `{action: 'remove', id}`. Поддерживаемая GeoJSON-геометрия: `Point`, `MultiPoint`, `LineString`, `MultiLineString`, `Polygon`, `MultiPolygon`, `GeometryCollection`. Используйте строковые ID объектов, JSON-совместимые `properties` и корректный порядок координат. `objects.createCollection(id)` создаёт группу. Коллекция имеет `id`, `add`, `get`, `getAll`, `remove`, `clear`, `setVisible`, `setFilter(predicate | null)`, `setStyle`, `getBounds`, `on`, `once`, `destroy`. События: `add`, `change`, `remove`, `statechange`, `destroy`. ## Маркеры, карточки и подсказки `ObjectHandle` содержит `id`, `getData()`, `update(change)`, `setVisible(boolean)`, `setSelected(boolean)`, `getBounds()`, `getPoint()`, `remove()`, `on()`, `once()`, `popup` и `tooltip`. Через `update` нельзя менять `id` и `kind`. События объекта: `click`, `dblclick`, `contextmenu`, `mouseenter`, `mouseleave`, `dragstart`, `drag`, `dragend`, `change`, `remove`, `popupopen`, `popupclose`. `popup` и `tooltip` имеют одинаковые методы: `open(content)`, `update(content)`, `load(loader)`, `close()`, `isOpen()`. `content` — `{text?, element?, offset?, maxWidth?}`. В `load` передаётся функция `(signal) => Promise`; используйте сигнал для отмены своего запроса. ```javascript const marker = map.objects.addMarker({ id: 'example', point: { latitude: 55.75, longitude: 37.61 }, label: 'Наша точка', }); marker.popup.open({ text: 'Карточка места', maxWidth: 270 }); marker.update({ selected: true }); ``` Для собственного маркера `renderer(data)` возвращает новый `HTMLElement`, объект `{element, anchor?, offset?, update?, destroy?}` или `null` для стандартного вида. Создавайте отдельный DOM-элемент для каждого маркера. Пользовательский текст вставляйте через `textContent`. ## Кластеры `map.clusters.create(id, options?) → ClusterGroup`; доступны также `get(id)`, `getAll()`, `clear()`. Параметры группы: `radius`, `maxZoom`, `minPoints`, `zoomOnClick`, `style`. Это группировка Ваших точек в браузере, не адресный поиск. ```javascript const group = map.clusters.create('places', { zoomOnClick: true }); group.setPoints([ { id: 'a', point: { latitude: 55.75, longitude: 37.61 } }, { id: 'b', point: { latitude: 55.76, longitude: 37.62 } }, ]); ``` | Метод группы | Назначение | | --- | --- | | `getState()` | Состояние, ревизия и количество точек | | `setPoints(points)`, `getPoint(id)`, `getPoints()`, `clear()` | Данные | | `batch(changes)` | `{action: 'upsert', point}` или `{action: 'remove', id}` | | `setVisible(value)`, `setFilter(predicate \| null)`, `setStyle(style)` | Отображение | | `getBounds()`, `getRendered(limit?)` | Область и отображённые узлы | | `getChildren(reference, options?)` | Непосредственные дочерние узлы | | `getLeaves(reference, {limit?, offset?, signal?, timeoutMs?}?)` | Исходные точки кластера | | `getExpansionZoom(reference, options?)` | Масштаб раскрытия | | `expand(reference, options?)` | Раскрыть кластер камерой | | `on(type, callback)`, `once(type, callback)`, `destroy()` | Подписки и удаление | `ClusterPoint` содержит `id`, `point`, необязательные `label`, `properties`, `selected`. `ClusterSnapshot` — `{nodes, truncated, loading}`. Узел имеет `kind: 'cluster'` с `reference` или `kind: 'point'` с исходной точкой. Reference принадлежит конкретной ревизии группы; после изменения данных получите новый, иначе возможен `STALE_CLUSTER`. События: `click`, `dblclick`, `contextmenu`, `mouseenter`, `mouseleave`, `change`, `destroy`, `error`. Стиль: `color`, `pointColor`, `selectedColor`, `textColor`, `clusterRadius`, `pointRadius`, `textSize`, `opacity`, `textFont`. Для запросов узлов доступны `signal`, `timeoutMs`, у `getChildren` также `limit`, у `expand` — параметры перехода камеры. ## Инструменты карты `map.controls.set(id, options)` включает или настраивает встроенный инструмент; `false` выключает его. Общие параметры: `position` (`top-left`, `top-right`, `bottom-left`, `bottom-right`), `visible`, `margin`. | ID | Дополнительные параметры | | --- | --- | | `navigation` | `showZoom`, `showCompass`, `visualizePitch` | | `scale` | `unit: 'metric' / 'imperial' / 'nautical'`, `maxWidth` | | `attribution` | `compact`; сохраняйте требуемую атрибуцию данных | | `fullscreen` | `container`, `pseudo` | | `geolocation` | `trackUserLocation`, `showUserLocation`, `showAccuracyCircle`, `zoomToUserAccuracy`, `maxZoom`, `positionOptions` | | `theme` | Общие параметры размещения | Геолокация использует разрешение браузера. `positionOptions` содержит `enableHighAccuracy`, `timeout`, `maximumAge`. `controls.add({id, element, position?, visible?, margin?, onAdd?, onRemove?})` добавляет свой инструмент. Также доступны `get(id)`, `getAll()`, `remove(id)`, `clear()`. `ControlHandle`: `id`, `element`, `getState()`, `setPosition()`, `setVisible()`, `setMargin()`, `focus()`, `remove()`, `destroy()`. [Полные типы инструментов](https://cdn.mmapps.ru/sdk/1.0.0-rc.9/types/clients/maps/control-types.d.ts). ## Поиск и выбор адреса `createSearchController({client, map?, filters?, language?, limit?, fitResults?})` создаёт контроллер. `client` — `geo.geocoder` или результат `createGeocoder()`. В выпуске SDK `1.0.0-rc.11` предусмотрен параметр `mapContext`: при наличии `map` он включён по умолчанию и передаёт снимок центра и области карты. `mapContext: false` оставляет намеренно глобальный поиск. Движение карты само по себе запросов не делает; текстовый Enter использует тот же поиск подсказок, не добавляя геокодинг. Для этой возможности требуется подключить именно этот выпуск после его публикации. | Метод | Назначение | | --- | --- | | `getState()`, `getResponse()` | Состояние интерфейса и последний ответ | | `search(q, options?)`, `geocode(q, options?)` | Текстовый запрос | | `reverse(point, radiusM?, options?)` | Обратный поиск | | `confirm(ref)` | Явный локальный выбор; возвращает `Promise` | | `setSelectionOpen(boolean)` | Открыть или закрыть карточку | | `useContext(ref)` | Выбрать контекст поиска | | `setFilters(filters)`, `clear()` | Фильтры и очистка состояния | | `on(type, callback)`, `destroy()` | Подписки и освобождение ресурсов | `filters` поддерживает `country_codes` и ссылки `region`, `locality`, `street`. События контроллера: `change`, `confirm`, `response`, `error`. Фазы `SearchState`: `idle`, `loading`, `candidates`, `not_found`, `needs_context`, `outside_coverage`, `selected`, `error`, `destroyed`. `SearchSelection` содержит `candidate`, `ref`, `point`, `alternative`, `queryPoint`, `userConfirmed: true`. Выбор не вызывает новый HTTP-запрос. `point` может быть `null`; не создавайте из него маршрут. `map.controls.addSearch(options)` размещает поиск на карте. Передайте либо `controller`, либо `client` с настройками `filters`, `language`, `limit`, `fitResults`. Общие настройки: размещение, `debounceMs`, `placeholder`, `width`, `onSelect`, `onRoute`, `onShare`. Результат `SearchMapControl` дополнительно имеет `controller`, `dockElement`, `openSelection()`, `closeSelection()`. Для своей вёрстки используйте `attachSearchControl({controller, element, dockElement?, debounceMs?, placeholder?, onSelect?, onRoute?, onShare?})`. Результат: `element`, `dockElement`, `focus()`, `setVisible()`, `openSelection()`, `closeSelection()`, `destroy()`. Самостоятельно созданный контроллер освобождайте отдельно. `onRoute(selection)` и `onShare(selection)` выполняют действия Вашего приложения; само открытие карточки не рассчитывает маршрут. [Пример подключения](https://mmapps.ru/docs/maps), [типы поиска](https://cdn.mmapps.ru/sdk/1.0.0-rc.9/types/clients/maps/search.d.ts). ## Свой обработчик запросов геокодера `createGeocoder({baseUrl, fetch?, timeoutMs?, signal?, credentials?, paths?, requestHeaders?}) → Geocoder` нужен для подключения к своему backend. Методы: `search`, `geocode`, `reverse`, `resolve`. `paths` задаёт пути этих четырёх операций, `requestHeaders(operation, options?)` — заголовки. `credentials` принимает `'omit'` или `'same-origin'`. Для прямого подключения к API Ммаппс используйте `createClient` с браузерным ключом. В `resolve` первый аргумент — сам `ref`, а не `{ref}`; дополнительные параметры — `language`, `signal`, `operationKey`. ## Расчёт и отображение маршрута `geo.routes.calculate({start, end, via?, profile?}, options?)` принимает `GeoPoint`, профиль — `'car'`. `geo.routes.geocode()` принимает в каждой позиции `{point}`, `{ref}` или `{q}`. Текст требует подтверждения. [Запросы и результаты](https://mmapps.ru/docs/routes). `routeView(response)` возвращает `{track, input, snapped, distanceM, durationS, routingVersion}`. `track` может быть `null`. `geocodedRouteView(response)` возвращает `{route, waypoints}`, где каждый waypoint содержит `index`, `point`, `candidates`. `routeCandidates(value)` извлекает кандидатов из результата геокодинга. Эти функции работают с готовым ответом и не отправляют запросов. ```javascript import { createRouteOverlay } from 'https://cdn.mmapps.ru/sdk/1.0.0-rc.9/index.js'; const overlay = createRouteOverlay(map); overlay.set(routeResponse); // Ответ calculate() или geocode(). overlay.fit(); // overlay.clear(); // overlay.destroy(); ``` `createRouteOverlay(map)` создаёт слой. `set(response | null)`, `clear()`, `fit()`, `destroy()` управляют им. Результат `no_route` не превращается в прямую линию. ## Редактор маршрута `attachRouteControl(map, service, {recalculate?}?) → RouteControl`. `service` должен предоставлять `calculate`, например `geo.routes`. `recalculate: 'on-change'` пересчитывает после завершённых изменений пользователем; `'manual'` требует явного расчёта. | Метод | Назначение | | --- | --- | | `getState()` | `visible`, `picking`, `phase`, `stops`, `operationKey`, `errorCode` | | `open(destination?)`, `close()` | Открыть или закрыть редактор; `destination` подтверждает конечную точку | | `setStops(stops)` | Программно задать точки без расчёта | | `chooseEndpoint('start' / 'end', stop)` | Выбрать конечную точку с учётом режима пересчёта | | `acceptSelection(selection)` | Принять явно выбранную точку; возвращает boolean | | `pick(index)` | Выбрать остановку на карте | | `calculate(options?)` | Выполнить расчёт | | `cancel()`, `fit()` | Отменить ожидание или показать маршрут | | `on(type, callback)`, `destroy()` | Подписки и удаление | `RouteStop` — `{point, label?}`; в списке остановок допускаются незаполненные `null`. События: `change`, `result`, `error`. Фазы: `editing`, `loading`, `route`, `no_route`, `error`. [Типы редактора](https://cdn.mmapps.ru/sdk/1.0.0-rc.9/types/clients/maps/route-control.d.ts). ## Матрица расстояний `geo.routes.matrix({sources, targets, profile?}, options?) → Promise` рассчитывает пары координат. `geo.routes.matrixGeocode()` использует `{point}`, `{ref}` или `{q}` в списках. Профиль — `'car'`, параметры операции — `signal`, `operationKey`. ```javascript const operationKey = crypto.randomUUID(); const matrix = await geo.routes.matrix({ sources: [{ latitude: 55.75, longitude: 37.61 }], targets: [{ latitude: 55.76, longitude: 37.62 }], profile: 'car', }, { operationKey }); const cell = matrix.cells[0][0]; if (cell.status === 'ok') { // cell.distance_m — метры; cell.duration_s — секунды. } ``` `matrixView(value, expected?)` проверяет готовый ответ, необязательный `expected` — исходный `MatrixRequest`. `geocodedMatrixView(value, expected)` принимает обязательный `GeocodeMatrixRequest`. Обе функции возвращают проверенный ответ и не вызывают API. До подтверждения текстовых адресов `matrix` равна `null`. Для `no_route` расстояние и время равны `null`. [Ограничения, тариф и подтверждение адресов](https://mmapps.ru/docs/matrix), [типы матрицы](https://cdn.mmapps.ru/sdk/1.0.0-rc.9/types/clients/maps/matrix.d.ts). ## Таймлайн `createTimeline(map, {data, time?, markerRenderer?, observationInterpolation?}) → Timeline` отображает временные данные Вашего приложения. Время — Unix в **миллисекундах UTC**. ```javascript import { createTimeline, attachTimelineControl } from 'https://cdn.mmapps.ru/sdk/1.0.0-rc.9/index.js'; const from = Date.UTC(2026, 0, 1, 9); const to = from + 60 * 60 * 1000; const timeline = createTimeline(map, { data: { version: 1, range: { from, to }, referenceTime: from, entities: [{ id: 'example', label: 'Наш объект', locations: [{ id: 'stop', from, to, basis: 'planned', point: { latitude: 55.75, longitude: 37.61 }, }], }], }, time: from, }); const control = attachTimelineControl(map, timeline); // При удалении: control.destroy(); timeline.destroy(); ``` `TimelineData`: `version: 1`, `range: {from, to}`, `referenceTime`, `entities`. Каждый объект имеет `id`, необязательные `label`, `locations`, `observations`. Местоположение: `{id, from, to?, point, basis, label?}`, где `basis` — `'reported'` или `'planned'`; интервал `[from, to)`. `point: null` означает неизвестную координату. Наблюдение: `{at, point, accuracyM?}`. | Метод | Назначение | | --- | --- | | `getSnapshot()` | Время, период, воспроизведение и позиции объектов | | `setData(data)` | Обновить данные | | `seek(time)` | Перемотка | | `play({speed?}?)`, `pause()` | Воспроизведение | | `getRoutePlans(selection)` | Подготовить планы расчёта без сети | | `prepareRoutes(client, options)` | Явно выполнить ограниченное число запросов маршрута | | `clearRoutes()` | Удалить подготовленные маршруты | | `on('change' / 'destroy', callback)`, `destroy()` | Подписки и удаление | Без включённой интерполяции промежутки между наблюдениями остаются неизвестными. `observationInterpolation: {maxGapMs}` явно разрешает оценку между соседними измерениями; `maxGapMs` — 1–600 000 мс. В `TemporalPosition.source` различаются `location`, `observation`, `interpolated`, `unknown`. Выбор для плана — `{entityId, basis, intermediate: 'observations' / 'none', from?, to?}`. Для `prepareRoutes` дополнительно обязательны `maxRequests`, `operationKeyPrefix`, необязателен `signal`. Сохраняйте префикс для повторов. Результат содержит `requested`, `reused`, `prepared`, `noRoute`. Подготовка вызывает платный расчёт маршрута; перемотка и воспроизведение — локальные действия. `attachTimelineControl(mapOrElement, timeline, {order?, onPrepareRoutes?}?)` создаёт панель. Она предоставляет `element`, `setVisible(boolean)`, `destroy()`. `onPrepareRoutes({entityId, basis})` открывает Ваш интерфейс подготовки; само воспроизведение его не вызывает. [Все типы таймлайна](https://cdn.mmapps.ru/sdk/1.0.0-rc.9/types/clients/maps/timeline.d.ts). ## Панели и меню точки `map.layout.mount({id, element, slot: 'top' / 'bottom', order?, visible?})` размещает панель в общем стеке. Меньший `order` — ближе к центру карты. `map.layout.reserve({id, element, edge, gap?})` резервирует место под уже размещённую панель приложения; `edge` — `top`, `bottom`, `left`, `right`. Оба метода возвращают `LayoutHandle`: `element`, `setVisible()`, `remove()`, `destroy()`. `layout.getInsets()` читает отступы, `layout.onChange(callback)` подписывается на их изменение и возвращает отписку. `attachContextMenu(map, {element, search?, routes?, onError?})` подключает меню к контейнеру карты. Передайте существующий `SearchController` и `RouteControl`. Меню открывается правой кнопкой мыши или с клавиатуры; действия — «Что здесь?», «Маршрут отсюда», «Маршрут сюда». Недоступные сервисы не выполняются. `MapContextMenu` содержит `element`, `open(point, screen?)`, `close()`, `isOpen()`, `destroy()`. Открытие меню бесплатно. Только выбор действия запускает обратный поиск или выбор точки маршрута с учётом режима пересчёта. ## Готовый виджет `createMapWidget(options) → Promise` объединяет инструменты карты. Используйте параметры карты, кроме `editable`, и добавьте нужные сервисы: ```javascript import { createClient, createMapWidget } from 'https://cdn.mmapps.ru/sdk/1.0.0-rc.9/index.js'; const geo = createClient({ apiBaseUrl: 'https://mmapps.ru', apiKey: 'YOUR_BROWSER_KEY' }); const widget = await createMapWidget({ element: document.getElementById('map'), mapId: 'ru', services: { geocoder: geo.geocoder, routes: geo.routes }, search: { placeholder: 'Адрес или координаты' }, routing: { recalculate: 'manual' }, }); await widget.ready; // При удалении: widget.destroy(); geo.destroy(); ``` Параметры виджета: `services`, `search` (настройки поиска или `false`), `routing` (boolean или настройки редактора), `controls` (без `search`), `timeline`, `timelineControl`, `contextMenu`, `onSelect`, `onRoute`, `onShare`, `onError`. Меню точки по умолчанию включено, `contextMenu: false` отключает его. Виджет предоставляет `map`, `ready`, `search`, `routes`, `timeline`, `contextMenu`; необязательные инструменты могут быть `null`. `setServices(services)` меняет сервисы, сохраняя публичную карту и внешние объекты. `destroy()` освобождает виджет. [Типы виджета](https://cdn.mmapps.ru/sdk/1.0.0-rc.9/types/clients/maps/widget.d.ts). ## Ошибки и завершение работы `MapSDKError` содержит `code`, `httpStatus`, `retryable`, `requestId`, `operationId`, `retryAfter`, `stage`. `GeocoderError` дополнительно предоставляет `status`. Используйте эти поля для сообщения об ошибке и решения о повторе. Локальные коды включают `INVALID_ARGUMENT`, `DESTROYED`, `ABORTED`, `DEADLINE_EXCEEDED`, `RESOURCE_UNAVAILABLE`, `WORKER_CONFLICT`, `RENDERER_ERROR`, `INVALID_RESPONSE`, `STALE_CLUSTER`, `BUSY`, `RANDOM_SOURCE_UNAVAILABLE`. Коды сервисного API описаны в [разделе ошибок](https://mmapps.ru/docs/billing#osibki). Храните функции отписки и возвращаемые handles. При размонтировании удаляйте самостоятельно созданные панели и контроллеры, затем карту и клиент. `destroy()` карты и виджета освобождает принадлежащие им ресурсы; внешний API-клиент освобождается отдельно. Не создавайте новые экземпляры при каждом обновлении состояния компонента. --- # Геокодер и поиск адресов Подсказки адресов, координаты по адресу и поиск адреса по точке. ## Методы и права | HTTP | Право ключа | Назначение | | --- | --- | --- | | `POST /v1/search` | `search` | Подсказки при вводе | | `POST /v1/geocode` | `geocode` | Координаты по адресу | | `POST /v1/reverse` | `reverse` | Адрес по координатам | | `POST /v1/resolve` | `resolve` | Получить объект по выбранному `ref` | | `GET /v1/status` | `status`, серверный ключ | Версия и покрытие данных | API принимает JSON с Bearer-ключом. [Полный пример запроса](https://mmapps.ru/docs/getting-started). В SDK доступны методы `geo.geocoder`; их сигнатуры — в [справочнике SDK](https://mmapps.ru/docs/sdk). ## Покрытие и обновление данных Адресный поиск основан на OpenStreetMap. Наличие карты населённого пункта не гарантирует полноту адресов в геокодере: здания, номера домов и дороги могут отсутствовать или устареть. Перед интеграцией проверьте адреса, с которыми работает Ваш сервис, на бесплатной квоте API. Версию и установленное покрытие адресной базы возвращает `GET /v1/status` с серверным ключом и правом `status`. Карта и геокодер обновляются отдельно. Дата сборки карты в [публичном каталоге](https://cdn.mmapps.ru/catalog/channels/stable.json) не является датой обновления геокодера. ## Поиск по тексту Тело запроса для `search` или `geocode`: ```json {"q":"Примерная улица","limit":5} ``` `q` — непустая строка до 256 символов, `limit` — от 1 до 10. Для ограничения области поиска используйте `filters` по [схеме запроса](https://mmapps.ru/gateway.openapi.yaml). Не передавайте отсутствующие фильтры как массив `[]`. `bias` задаёт мягкий приоритет: обязательный `focus` с `latitude`/`longitude` и необязательный `viewport` с `west`, `south`, `east`, `north`. Все координаты конечные, центр находится внутри области, `south <= north`. При `west > east` область пересекает 180-й меридиан. Явные фильтры и распознанный город из текста сохраняют приоритет. `search_context` в ответе показывает источник области (`filters`, `query`, `viewport`, `none`), `locality` или `null` и признак расширения `expanded`. Это приоритет поиска, а не местоположение пользователя. При повторе операции сохраняйте исходный `bias`; сознательный поиск в другой области получает новый `Idempotency-Key`. ## Обратный геокодинг Тело запроса для `reverse`. Замените координаты в примере на нужную точку: ```json {"point":{"latitude":55.75,"longitude":37.61},"radius_m":1000,"limit":5} ``` В API координаты задаются полями `latitude` и `longitude`. Геокодер учитывает попадание в связанное с адресом здание и расстояние до ближайшего объекта. Исходная точка остаётся в `query_point`: не заменяйте её точкой найденного адреса. | Поле | Как использовать | | --- | --- | | `relation` | Отношение точки к найденному объекту | | `geometry_distance_m` | Расстояние до контура; `null`, если контура нет | | `point_distance_m` | Расстояние до возвращённой адресной точки | | `geometry.shape` | Контур здания, если он доступен | Значения `relation`: `inside_linked_building`, `on_linked_building_boundary`, `nearest_linked_geometry`, `nearest_address_point`. Радиус применяется к объекту: адресная точка может оказаться дальше радиуса, если контур здания покрывает исходную точку. ## Выбор результата - `label` — текст для отображения. - `point` — координата или `null`. Наличие адреса не гарантирует наличие координат. - `needs_confirmation` — необходимость подтверждения пользователем. - `precision` — детализация распознанного адреса; это не обещание точности входа в здание. - `alternative_points` — альтернативные точки; выбор остаётся за пользователем. - `ref` — ссылка на объект, содержащая `id` и `dataset_version`. Передавайте её целиком в `resolve` как `{"ref": selectedRef}`. Если `ref` устарел, повторите поиск и предложите новый выбор. Не заменяйте выбранный объект автоматически поиском по его подписи. ## Атрибуция OpenStreetMap Поиск адресов, прямое и обратное геокодирование используют данные OpenStreetMap по ODbL 1.0. Если эти функции доступны пользователям Вашего приложения, при публичном использовании укажите OpenStreetMap и добавьте ссылку на сведения о лицензии. Атрибуцию можно разместить **один раз в общем футере приложения**, без подписи под каждым полем адреса, подсказкой или отдельным результатом. Футер должен быть читаемым и видимым пользователям на страницах, где доступны поиск адресов или геокодирование. Например: ```html ``` Упоминание OpenStreetMap только на сайте Ммаппс не заменяет атрибуцию в Вашем приложении. При отображении карты соблюдайте [правила OSMF для интерактивных карт](https://osmfoundation.org/wiki/Licence/Attribution_Guidelines#Interactive_maps): указание источника подложки обычно размещают в углу карты или рядом с ней. Это правило закреплено в [пункте 9.4 пользовательского соглашения](https://mmapps.ru/documents/terms#maps-licenses). Подробнее — в [разъяснениях OSMF по геокодированию](https://osmfoundation.org/wiki/Licence/Community_Guidelines/Geocoding_-_Guideline). ## Контур здания `geometry` присутствует в кандидате поиска и в результате `resolve`: `null`, если связанного контура нет, иначе содержит `shape` и сведения о геометрии. `shape` — GeoJSON `Polygon` или `MultiPolygon`, в том числе с отверстиями. В GeoJSON порядок координат — **[longitude, latitude]**. Контур можно отобразить без дополнительного запроса. Если используете `Accept: application/geo+json`, он находится в `properties.compact_geo.geometry.shape`; геометрия самого Feature описывает точку результата. ## Результаты и ошибки | `outcome` | Действие приложения | | --- | --- | | `candidates` | Показать варианты для выбора | | `not_found` | Предложить уточнить адрес | | `needs_context` | Уточнить город, улицу или другой контекст | | `outside_coverage` | Сообщить, что точка вне покрытия | Пустой успешный ответ тоже учитывается как операция. `resolve` и `status` не имеют отдельной платы, но ограничены по частоте. [Повторы и обработка ошибок](https://mmapps.ru/docs/billing). --- # Маршрут Рассчитайте автомобильный маршрут с остановками в заданном порядке. ## Маршрут по координатам `POST /v1/route` требует право `route`. Передайте начальную и конечную точки; промежуточные остановки задаются в `via`. ```json { "start": {"latitude":55.75,"longitude":37.61}, "end": {"latitude":55.76,"longitude":37.62}, "via": [], "profile": "car" } ``` Замените координаты в примере на свои начальную и конечную точки. Порядок остановок сохраняется: автоматическая оптимизация порядка посещения не выполняется. Расчётное время не учитывает пробки. ## Вызов из SDK Создайте клиент с `apiBaseUrl: 'https://mmapps.ru'` и [браузерным ключом](https://mmapps.ru/docs/keys). Используйте координаты, выбранные пользователем: ```javascript const operationKey = crypto.randomUUID(); const result = await geo.routes.calculate({ start: selectedStart, end: selectedEnd, via: orderedStops, profile: 'car', }, { operationKey }); ``` Сохраняйте `operationKey` для повтора того же запроса. При изменении точек или порядка остановок создайте новый ключ операции. ## Маршрут по адресам `POST /v1/route/geocode` и `geo.routes.geocode()` принимают для каждой точки один из вариантов: `{q: 'адрес'}`, `{ref: selectedRef}` или `{point: selectedPoint}`. 1. Отправьте адреса в `start`, `end` и при необходимости `via`. 2. Покажите кандидатов из `waypoints` и попросите пользователя подтвердить каждый адрес. Даже единственный кандидат из текстового поиска требует выбора. 3. Замените текст выбранными `ref` или `point` и отправьте запрос с новым ключом операции. Пока требуется выбор, ответ содержит `outcome: 'needs_confirmation'`, а `route` равен `null`. Устаревший `ref` требует повторного поиска и выбора. Права: `route:geocode`, а также `geocode` для текста, `resolve` для ссылок и `route` для расчёта. ## Отображение результата Исходные координаты сохраняются в `input_points`, точки привязки к дороге — отдельно в `snapped_points`. Не перемещайте выбранные пользователем маркеры автоматически. При `outcome: 'no_route'` дорожный путь не найден, `geometry` равна `null`. Сообщите об этом пользователю. Прямую линию между точками нельзя выдавать за рассчитанный маршрут. Готовую геометрию можно отобразить средствами [SDK](https://mmapps.ru/docs/sdk) без нового расчёта. Проверяйте ошибки запроса по [OpenAPI](https://mmapps.ru/gateway.openapi.yaml). `ROUTING_UNAVAILABLE` означает, что расчёт сейчас недоступен. ## Стоимость Расчёт — одна операция `route`. В запросе по адресам каждый выполненный текстовый поиск учитывается отдельно как `geocode`. Подтверждённые координаты и ссылки не создают нового списания за геокодинг. До подтверждения всех адресов маршрут не рассчитывается и не оплачивается. [Тарифы, повторные запросы и учёт расходов](https://mmapps.ru/docs/billing). --- # Матрица расстояний Получите автомобильные расстояния и расчётное время для всех пар двух списков точек. ## Что возвращает матрица `POST /v1/matrix` принимает `sources` и `targets`. Ответ `cells[i][j]` описывает путь от источника `i` к назначению `j`. Например, 2 источника × 3 назначения — один запрос и 6 элементов. Матрица помогает сравнить расстояния между складами, магазинами и адресами доставки. Направления A→B и B→A могут отличаться. Автомобильный профиль `car` не учитывает пробки и дату выезда; время является оценкой. Матрица не выбирает порядок посещения и не возвращает линию маршрута. ## Где пригодится - **Доставка:** сравнить пути от складов до адресов заказов и выбрать, откуда отправлять каждый заказ. - **Выездные бригады:** сравнить время в пути от свободных сотрудников до новой заявки. - **Пункты выдачи:** предложить покупателю ближайший пункт по дороге. Передайте два списка точек: откуда и куда нужно ехать. Для двух складов и трёх заказов Вы получите шесть расстояний и шесть оценок времени. По этой таблице Ваше приложение может выбрать подходящий вариант. [Пример на главной](https://mmapps.ru/#distance-matrix). ## Доступ Разрешите `matrix` в [настройках ключа](https://mmapps.ru/app/projects). Для матрицы по текстовым адресам нужно также `geocode`, для выбранных ссылок — `resolve`. Матрица должна быть доступна в текущем тарифе аккаунта. Проверить это можно серверным ключом с правом `status`: `GET /platform/v1/capabilities`, поле `matrix.enabled`. В `matrix.limits` возвращаются ограничения конкретного подключения. ## Запрос по координатам ```bash curl --request POST 'https://mmapps.ru/v1/matrix' \ --header "Authorization: Bearer ${MMAPPS_SERVER_KEY}" \ --header 'Content-Type: application/json' \ --header 'Idempotency-Key: matrix-example-operation-001' \ --data '{"sources":[{"latitude":55.75,"longitude":37.61}],"targets":[{"latitude":55.76,"longitude":37.62}],"profile":"car"}' ``` В SDK RC9: ```javascript const operationKey = crypto.randomUUID(); const result = await geo.routes.matrix({ sources: selectedSources, targets: selectedTargets, profile: 'car', }, { operationKey }); ``` Каждый список содержит объекты `{latitude, longitude}`. Текущий запрос может содержать до 25 пар; каждая пара должна находиться в пределах 200 км по прямой. Дорожное расстояние в результате может быть больше. Точные ограничения — в [OpenAPI](https://mmapps.ru/gateway.openapi.yaml). ## Чтение результата | `cells[i][j].status` | Расстояние и время | | --- | --- | | `ok` | `distance_m` в метрах, `duration_s` в секундах | | `no_route` | Оба значения `null`; путь между этой парой не найден | Не превращайте `null` в ноль: это создало бы ложный результат «рядом». При ошибке сервиса завершённая матрица не возвращается, элементы матрицы не оплачиваются. ## Матрица по адресам `POST /v1/matrix/geocode` и `geo.routes.matrixGeocode()` принимают те же списки, но каждая позиция — `{q: 'адрес'}`, `{ref: selectedRef}` или `{point: selectedPoint}`. Текстовый поиск возвращает кандидатов в `waypoints.sources` и `waypoints.targets`; `matrix` остаётся `null`. Покажите варианты пользователю, замените каждый текст подтверждённой ссылкой или координатой и отправьте новый запрос с новым ключом операции. Даже единственный кандидат требует подтверждения. ## Тариф и повторы Матрица учитывается **по элементам**, а не по запросам. 2 000 элементов в месяц входят в бесплатную квоту; затем — **39 ₽ за 1 000 элементов** (0,039 ₽ за элемент). Применимый тариф и доступность проверяйте в кабинете. Если осталось 3 бесплатных элемента, запрос на 25 элементов использует 3 бесплатных и 22 платных: 0,858 ₽. Повторяющиеся пары, диагональ и завершённые `no_route` также учитываются. Выполненный поиск текстовых адресов оплачивается отдельно; `resolve` бесплатен. `Idempotency-Key` обязателен. Повторяйте тот же запрос с прежним ключом; другое тело с тем же ключом даст 409. Количество элементов, расход квоты и стоимость видны в [статистике и CSV](https://mmapps.ru/app/usage). [Общие правила расходов](https://mmapps.ru/docs/billing). --- # Ключи и доступ Выберите тип ключа, разрешите нужные операции и ограничьте доступ своего приложения. ## Типы ключей | Тип | Где используется | Ограничение доступа | | --- | --- | --- | | На сервере | Backend сайта или приложения | Внешние IP и подсети, по желанию | | На сайте | JavaScript SDK в браузере | Обязательный список разрешённых сайтов | Для бесплатной карты ключ не нужен. Ключ сервисного API передаётся заголовком `Authorization: Bearer …`; SDK делает это при настройке `apiKey`. ## Создание и права В [«Проекты и ключи»](https://mmapps.ru/app/projects) выберите проект, нажмите «Создать ключ» и укажите понятное имя. Полный ключ показывается один раз. | Операция | Необходимые права | | --- | --- | | Подсказки | `search` | | Геокодинг | `geocode` | | Обратный геокодинг | `reverse` | | Получение выбранного объекта | `resolve` | | Маршрут по координатам | `route` | | Маршрут по адресам | `route:geocode`; для выполняемых действий — `geocode`, `resolve`, `route` | | Матрица по координатам | `matrix` | | Матрица по адресам | `matrix`; для текста — `geocode`, для ссылки — `resolve` | | Статус и возможности аккаунта | `status`, только серверный ключ | Выбирайте права явно. Матрица доступна, когда она включена для аккаунта; наличие SDK само по себе не выдаёт это право. Фактическую доступность маршрута и матрицы можно проверить серверным ключом через `GET /platform/v1/capabilities`. ## Разрешённые сайты В поле «Разрешённые сайты» укажите домены по одному на строку, например `shop.example.ru`. Без протокола добавится `https://`. Если нужен нестандартный порт, укажите его явно. `example.ru` и `www.example.ru` добавляются отдельно. Путь страницы, параметры и `*` не допускаются. Для рабочего подключения требуется HTTPS. В демосреде для локальной разработки можно указать `http://localhost:8080`. Браузерный ключ виден посетителю сайта. Разрешённый origin ограничивает браузерные запросы, но не заменяет права и бюджет. Серверный ключ храните только на сервере. ## Разрешённые IP Для серверного ключа поддерживаются IPv4, IPv6 и подсети, например `203.0.113.0/24`. Указывайте адрес выхода сервера в интернет. Пустой список разрешает запросы с любого IP. ## Изменение и отзыв Кнопка «Настроить» меняет имя, разрешённые сайты или IP, права и денежный бюджет. Тип ключа не меняется: создайте другой ключ, если нужно перенести подключение с сервера в браузер. Технические ограничения общие для подключений с одного IP-адреса: до 20 запросов в секунду и до 60 новых сетевых соединений в минуту. Они заданы сервисом и не настраиваются для ключа. Используйте постоянные соединения; существующее соединение может обслуживать несколько HTTP-запросов. При HTTP-ограничении ответ содержит `429` и `Retry-After`. «Отозвать» запрещает новые сервисные запросы. Для замены создайте ключ и обновите настройки приложения. Бесплатная карта продолжит работать. Ключ Geo API не даёт доступа к платежам и управлению аккаунтом. Для кабинета нужны вход и подтверждённый email. --- # Расходы и лимиты Карта бесплатна; сервисные запросы используют квоту, затем оплачиваются с баланса. ## Тарифы | Услуга | Бесплатно в месяц | За 1 000 сверх квоты | | --- | --- | --- | | Карта и SDK | Без ограничений по квоте API | Бесплатно | | Подсказки адресов | 5 000 | 15 ₽ | | Геокодинг | 3 000 | 49 ₽ | | Обратный геокодинг | 3 000 | 49 ₽ | | Маршрут | 1 000 | 99 ₽ | | Элемент матрицы расстояний | 2 000 | 39 ₽ | | resolve, status | В пределах частоты запросов ключа | Без отдельной оплаты | Квота общая для проектов аккаунта. Матрица учитывается по парам точек, остальные платные операции — по выполненным запросам. Применимый тариф и доступные операции проверяйте в кабинете. ## Бесплатная проба API [Создайте аккаунт](https://mmapps.ru/app/register), подтвердите email и выпустите ключ в разделе [«Проекты и ключи»](https://mmapps.ru/app/projects). Запросы в пределах бесплатной квоты доступны без пополнения баланса и привязки банковской карты. [Первый запрос по шагам](https://mmapps.ru/docs/getting-started). Когда квота закончится, новые платные запросы потребуют предоплаты и доступного бюджета. Годовой лицензии и обязательной подписки нет. ## Хранение результатов Результаты API можно сохранять у себя: в базе данных, кеше, заказах и отчётах. Используйте найденные адреса, координаты и рассчитанные маршруты повторно, в том числе на другой карте. Чтение сохранённого результата не вызывает новый запрос к Ммаппс и не расходует квоту. Соблюдайте лицензии исходных данных, включая OpenStreetMap, и требования к персональным данным. Право сохранять результаты закреплено в [пункте 2.3 пользовательского соглашения](https://mmapps.ru/documents/terms#sdk). Для поиска адресов и геокодирования атрибуцию OpenStreetMap можно разместить один раз в общем футере приложения, без подписи под каждым полем адреса. [Правила размещения и пример](https://mmapps.ru/docs/addresses#atribuciia-openstreetmap). ## Что считается операцией - Поиск, геокодинг и обратный геокодинг учитываются при успешном выполнении, в том числе с пустым результатом или необходимостью уточнения. - Расчёт маршрута — одна операция `route`. - Матрица — `N × M` элементов, включая повторяющиеся пары, диагональ и завершённые `no_route`. - В маршруте и матрице по адресам каждый выполненный поиск текста — отдельный `geocode`. До подтверждения адресов сам маршрут или матрица не оплачивается. - `resolve` и `status` — без отдельной платы, в пределах частоты запросов ключа. - Перемещение карты, маркеры, кластеры, отображение готовой геометрии и воспроизведение Ваших данных на таймлайне не расходуют квоту API. Ошибка запроса или сервиса отличается от успешного ответа «ничего не найдено». У маршрута проверяйте `outcome`, у матрицы — статус каждой пары. При частичном выполнении поиска по адресам уже выполненные операции могут быть учтены; смотрите квитанцию и историю использования. ## Баланс и месячный бюджет После исчерпания бесплатной квоты нужны доступный баланс и разрешённый бюджет. Бюджет `0` оставляет только бесплатную квоту. Бюджеты аккаунта и проекта действуют одновременно. Создание другого проекта не увеличивает квоту. Месяц учитывается по Москве. [«Лимиты и уведомления»](https://mmapps.ru/app/limits) позволяют ограничить расходы, [«Использование»](https://mmapps.ru/app/usage) — посмотреть историю, применить фильтры и выгрузить CSV. В статистике матрицы запросы и элементы указаны отдельно. ## Повтор запроса Для новой логической операции создавайте новый `Idempotency-Key`; в SDK это `operationKey`. При сетевом сбое повторяйте то же тело с прежним ключом. Не создавайте новый ключ при каждом автоматическом повторе. Изменение тела при прежнем ключе возвращает 409. Сервис хранит ответ для повторной выдачи 15 минут; после этого повтор не запускает новую оплачиваемую операцию. Этот срок не ограничивает хранение полученного результата в Вашей базе по условиям соглашения. Если ответ для повтора истёк или операция ещё обрабатывается, сначала уточните её состояние. Заголовок `X-Usage-Operation` содержит идентификатор операции. Квитанцию можно прочитать через `GET /platform/v1/usage-operations/{id}` тем же API-ключом с нужными правами. `X-Charged-Microrub` передаёт сумму целым числом в миллионных долях рубля; `X-Geo-Funding` — `free`, `paid` или `mixed`. Для обычной матрицы `X-Geo-Quantity`, `X-Geo-Free-Units` и `X-Geo-Paid-Units` показывают число элементов. ## Ошибки | HTTP | Что делать | | --- | --- | | 401 | Проверить API-ключ и его отзыв | | 402 | Проверить доступный баланс | | 403 | Проверить права, разрешённый сайт или IP, бюджет и состояние аккаунта | | 409 | Проверить повтор операции, её состояние или актуальность `ref` | | 413 | Уменьшить размер запроса | | 422 | Исправить поля по схеме запроса | | 429 | Снизить частоту, учитывать `Retry-After`, если он есть | | 503 | Показать временную недоступность; при разрешённом повторе сохранить ключ операции | По умолчанию JSON ошибки содержит `error.code`, `error.message`, `error.request_id`, `error.retryable`. Для `Accept: application/problem+json` используется формат Problem Details из OpenAPI. Решение о повторе принимайте по коду и `retryable`, а не только по HTTP-статусу. `ROUTING_UNAVAILABLE` означает недоступность расчёта. `INCOMPATIBLE_GEO_SCHEMA` — временную несовместимость сервиса; не пытайтесь обходить её запросом старого формата. При `IDEMPOTENCY_SCHEMA_CHANGED` прежняя операция уже учтена: новый ключ может создать новый расход. ## Пополнения и возвраты Пополняйте баланс через кабинет, минимум — 300 ₽. Возврат со страницы оплаты ещё не подтверждает зачисление — дождитесь подтверждённого статуса платежа. После регистрации чека в разделе [«Платежи»](https://mmapps.ru/app/payments) появится кнопка «Скачать чек»: электронную копию можно открыть в браузере и распечатать или сохранить в PDF. Правила возвратов описаны в [пользовательском соглашении](https://mmapps.ru/documents/terms#payments). Для обращения в поддержку достаточно кода ошибки и ID запроса. Не отправляйте ключи и географические данные пользователей.