Доставка и точки самовывоза
Способы доставки и точки самовывоза можно читать и менять, если у приложения есть право на настройки магазина.
Если этого права нет, ответ 403:
{"status":"error","message":"Недостаточно прав для операции"}
Доставка
GET /admin/delivery_variants.json возвращает все способы доставки магазина, отсортированные по position. Для чтения одного способа используйте GET /admin/delivery_variants/:id.json. Чтобы получить несколько способов, прочитайте общий список или запросите каждый отдельно.
Метод GET /admin/delivery_variants/by_ids.json не поддерживается: он возвращает 404 с HTML-страницей. Такой же ответ возвращается для несуществующего идентификатора.
В общем объекте есть id, position, title, description, type, charge_up_to, inverted, show_zip_code, min_order_sum, payment_delivery_variants, delivery_locations, delivery_time_intervals, created_at, updated_at. Для типов с датой доставки объект также содержит show_calendar_in_checkout, delivery_date_required, forbid_weekends, utc_from_address, estimated_delivery_period, order_time_is_later, forbidden_days, show_time_intervals_in_checkout, time_intervals_required.
Массив payment_delivery_variants содержит связи со способами оплаты. Покупателю доступны только способы оплаты, связанные с выбранной доставкой. Чтобы при создании привязать все существующие способы оплаты, передайте add_payment_gateways: true. Это поле не возвращается в ответе.
min_order_sum в ответе есть. Передача 1000 в теле создания оставляет в объекте null.
Поле delivery_locations содержит города и регионы, для которых доступен способ доставки. При сохранении передавайте их в delivery_locations_attributes — массиве или объекте с числовыми ключами.
Для каждой локации обязательны country и region. Значение city: null распространяет локацию на весь регион. Например, обл Ленинградская при city: null сохраняется без изменения. Если передать город без региона, API вернёт 422:
{"delivery_locations.sanitized_region_name": ["Не заполнены обязательные поля"]}
Неизвестное имя региона сохраняется как передано. Удаление локации — тот же массив с id и _destroy: 1.
У доставки «от локации» тарифные зоны задаются в delivery_zones. Города каждой зоны передаются во вложенном locations_attributes. Поле delivery_locations_attributes у этого типа меняет отдельный список доступных локаций и не изменяет зоны.
Тип вне списка, например DeliveryVariant::Unknown или DeliveryVariant::NovaPoshta, отвечает 422. Текст ошибки — отсутствующий перевод not_in_variants_list.
В списке магазина встречаются и другие типы. DeliveryVariant::None тоже хранит price. DeliveryVariant::NoDelivery — способ «доставка не требуется», у него нет полей даты доставки. Точки самовывоза относятся к DeliveryVariant::PickUp, а не к способу с названием «Самовывоз», если у того другой type.
DELETE /admin/delivery_variants/:id.json отвечает 200 и {"status":"ok"}.
Дата и интервалы
Для фиксированной доставки, внешней доставки, доставки от локации, доставки от суммы и самовывоза можно настроить календарь и интервалы времени. Передайте интервалы строкой в time_intervals, разделяя пары часов запятыми: 10-14,14-18. В ответе InSales вернёт разобранный массив delivery_time_intervals. У каждого интервала есть time_from, time_to и признаки дней недели; для такой строки все семь признаков равны true.
Повторная запись time_intervals не заменяет сохранённые интервалы. При этом флаги календаря изменяются: show_calendar_in_checkout, estimated_delivery_period, forbidden_days, delivery_date_required, forbid_weekends, order_time_is_later, show_time_intervals_in_checkout и time_intervals_required.
Часы вроде 10:00-14:00 отвечают 422:
{"time_intervals": ["Некорректный формат! Пример: 10-14, 14-18, 18-22\n"]}
| Параметр | Описание |
|---|---|
delivery_variant[time_intervals] необязательныйстрока |
Интервалы часов: 10-14,14-18. |
delivery_variant[show_time_intervals_in_checkout] необязательныйлогический |
Показывать интервалы при оформлении. |
delivery_variant[time_intervals_required] необязательныйлогический |
Интервал обязателен. |
delivery_variant[show_calendar_in_checkout] необязательныйлогический |
Показывать календарь даты доставки. |
delivery_variant[delivery_date_required] необязательныйлогический |
Дата доставки обязательна. |
delivery_variant[forbid_weekends] необязательныйлогический |
Запретить выходные. |
delivery_variant[estimated_delivery_period] необязательныйчисло |
Срок в днях. |
delivery_variant[order_time_is_later] необязательныйстрока |
Время отсечки, например 15:00. |
delivery_variant[forbidden_days] необязательныйстрока |
Запрещённые дни: 01.01,09.05. |
POST /admin/delivery_variants.json
Authorization: Basic API_KEY:API_PASSWORD
Accept: application/json
Content-Type: application/json
{
"delivery_variant": {
"type": "DeliveryVariant::PriceDepend",
"title": "docs-api интервалы",
"min_price": 0,
"rules_attributes": [
{"order_price": 1, "price": 100}
],
"show_calendar_in_checkout": true,
"delivery_date_required": true,
"forbid_weekends": true,
"estimated_delivery_period": 2,
"order_time_is_later": "15:00",
"forbidden_days": "01.01,09.05",
"show_time_intervals_in_checkout": true,
"time_intervals_required": true,
"time_intervals": "10-14,14-18"
}
}
Ответ · 201
{
"id": 105,
"type": "DeliveryVariant::PriceDepend",
"show_calendar_in_checkout": true,
"delivery_date_required": true,
"forbid_weekends": true,
"estimated_delivery_period": 2,
"order_time_is_later": "15:00",
"forbidden_days": "01.01,09.05",
"show_time_intervals_in_checkout": true,
"time_intervals_required": true,
"delivery_time_intervals": [
{
"time_from": "10:00",
"time_to": "14:00",
"monday": true,
"tuesday": true,
"wednesday": true,
"thursday": true,
"friday": true,
"saturday": true,
"sunday": true
},
{
"time_from": "14:00",
"time_to": "18:00",
"monday": true,
"tuesday": true,
"wednesday": true,
"thursday": true,
"friday": true,
"saturday": true,
"sunday": true
}
]
}
Фиксированная
Для DeliveryVariant::Fixed обязательно поле price. Допускается ноль и положительные значения. Поле charge_up_to задаёт сумму товаров, начиная с которой доставка становится бесплатной.
| Параметр | Описание |
|---|---|
delivery_variant[type] обязательныйстрока |
DeliveryVariant::Fixed. |
delivery_variant[title] обязательныйстрока |
Название в чекауте и в бэк-офисе. |
delivery_variant[price] обязательныйчисло |
Цена доставки. Ноль и больше. |
delivery_variant[description] необязательныйстрока |
Описание. Сохраняется как переданный текст. |
delivery_variant[charge_up_to] необязательныйчисло |
Сумма товаров, с которой доставка бесплатна. |
delivery_variant[add_payment_gateways] необязательныйлогический |
Привязать все текущие способы оплаты. |
delivery_variant[delivery_locations_attributes] необязательныймассив |
Локации. У элемента country и region. |
POST /admin/delivery_variants.json
Authorization: Basic API_KEY:API_PASSWORD
Accept: application/json
Content-Type: application/json
{
"delivery_variant": {
"type": "DeliveryVariant::Fixed",
"title": "docs-api фиксированная",
"price": 350,
"description": "По городу",
"charge_up_to": "5000.0",
"add_payment_gateways": true,
"delivery_locations_attributes": [
{"country": "RU", "region": "Москва", "city": "Москва"}
]
}
}
Ответ · 201
{
"id": 49,
"position": 3,
"type": "DeliveryVariant::Fixed",
"title": "docs-api фиксированная",
"description": "По городу",
"price": "350.0",
"charge_up_to": "5000.0",
"inverted": false,
"show_zip_code": false,
"min_order_sum": null,
"javascript": null,
"payment_delivery_variants": [
{"id": 4, "payment_gateway_id": 6101770}
],
"delivery_locations": [
{"id": 1, "country": "RU", "region": "Москва", "city": "Москва"}
],
"delivery_time_intervals": []
}
Без price ответ 422, тело {"price":["Не заполнены обязательные поля"]}.
Внешняя
Способ DeliveryVariant::External получает расчёт стоимости от сервиса по адресу url. Чтобы выбрать вторую версию протокола, передайте api_version: v2. Пустое значение включает первую версию. Поле api_version не возвращается в ответе, поэтому сохраняйте выбранную версию в приложении. Поля javascript и customer_pickup возвращаются; javascript сохраняется строкой.
Для непубличного URL сервиса API возвращает 422 и тело {"url":["Недопустимый URL"]}.
| Параметр | Описание |
|---|---|
delivery_variant[type] обязательныйстрока |
DeliveryVariant::External. |
delivery_variant[title] обязательныйстрока |
Название способа. |
delivery_variant[url] обязательныйстрока |
Публичный URL сервиса расчёта доставки со схемой http или https. |
delivery_variant[api_version] необязательныйстрока |
v2 — вторая версия расчёта. Пусто — первая. В ответ ключ не входит. |
delivery_variant[javascript] необязательныйстрока |
Скрипт способа. Возвращается как передан. |
delivery_variant[customer_pickup] необязательныйлогический |
Самовывоз. Есть в ответе внешней доставки. |
POST /admin/delivery_variants.json
Authorization: Basic API_KEY:API_PASSWORD
Accept: application/json
Content-Type: application/json
{
"delivery_variant": {
"type": "DeliveryVariant::External",
"title": "docs-api внешняя",
"url": "https://example.com/delivery",
"api_version": "v2",
"javascript": "console.log('docs-api')",
"customer_pickup": false
}
}
Ответ · 201
{
"id": 65,
"type": "DeliveryVariant::External",
"title": "docs-api внешняя",
"url": "https://example.com/delivery",
"javascript": "console.log('docs-api')",
"customer_pickup": false,
"payment_delivery_variants": [],
"delivery_locations": [],
"delivery_time_intervals": []
}
В первой версии InSales отправляет GET-запрос на url, добавляя параметры price (сумма товаров со скидкой), weight, region, city, zip, kladr_code, вложенный location и callback=external. Дополнительные поля заказа и адреса не передаются.
Сервис должен вернуть текст с вызовом external(...), внутри которого находится JSON с delivery_price. Для ошибки используйте error или массив errors. Строка Current carrier is not available! делает способ недоступным. InSales ожидает ответ не более 4 секунд.
Во второй версии InSales отправляет POST-запрос на url с заголовком Content-Type: application/json; charset=UTF-8 и телом {"order": ...}. Объект order содержит account_id, currency_iso_code, delivery_variant_id, warehouse_id, items_price, total_weight, адрес shipping_address (full_locality_name, delivery_address, location) и строки order_lines (product_id, variant_id, quantity, weight, dimensions). Дополнительные поля заказа не передаются.
Сервис должен вернуть JSON-массив тарифов. У каждого тарифа InSales читает price, tariff_id, title, description, delivery_interval, shipping_company, shipping_company_handle, warnings, errors, fields_values и outlet. Пустой массив, невалидный JSON или HTTP-ошибка означают, что стоимость не рассчитана. InSales ожидает ответ не более 6 секунд. При повторном расчёте среди нескольких тарифов магазин ищет ранее выбранный по tariff_id.
outlet в тарифе второй версии — пункт выдачи: адрес и описание приходят из ответа сервиса. Пустые address и description в заказе означают, что сервис прислал их пустыми.
Выбранный тариф записывается в заказ ключом order[delivery_info_attributes]. В объекте сохраняются tariff_id, price, title, shipping_company_handle, delivery_interval и outlet. В заказе они возвращаются в delivery_info. Создание заказа описано в заказах.
От локации
DeliveryVariant::LocationDepend требует хотя бы одну зону. Пустой способ отвечает 422, тело {"delivery_zones":["не может быть пустым"]}.
У зоны есть название title, массив тарифов tariffs_attributes и массив локаций locations_attributes. Для тарифа обязательны max_weight, price, step и step_price.
Поля step и step_price задают доплату за каждый следующий шаг веса после max_weight. Если их не передать, API вернёт 422 с сообщениями «Не заполнены обязательные поля» и «не является числом» для обоих полей.
| Параметр | Описание |
|---|---|
delivery_variant[type] обязательныйстрока |
DeliveryVariant::LocationDepend. |
delivery_variant[title] обязательныйстрока |
Название способа. |
delivery_variant[delivery_zones_attributes] обязательныймассив |
Хотя бы одна зона с тарифом и локацией. |
delivery_zones_attributes[][title] необязательныйстрока |
Название зоны. |
delivery_zones_attributes[][tariffs_attributes] необязательныймассив |
Тарифы: max_weight, price, step, step_price. |
delivery_zones_attributes[][locations_attributes] необязательныймассив |
Локации зоны: country, region, city. |
POST /admin/delivery_variants.json
Authorization: Basic API_KEY:API_PASSWORD
Accept: application/json
Content-Type: application/json
{
"delivery_variant": {
"type": "DeliveryVariant::LocationDepend",
"title": "docs-api от локации",
"delivery_zones_attributes": [
{
"title": "Москва",
"tariffs_attributes": [
{"max_weight": 5, "price": 300, "step": 1, "step_price": 50}
],
"locations_attributes": [
{"country": "RU", "region": "Москва", "city": "Москва"}
]
}
]
}
}
Ответ · 201
{
"id": 57,
"type": "DeliveryVariant::LocationDepend",
"title": "docs-api от локации",
"delivery_zones": [
{
"id": 1,
"title": "Москва",
"tariffs": [
{
"id": 1,
"max_weight": "5.0",
"price": "300.0",
"step": "1.0",
"step_price": "50.0"
}
],
"locations": [
{"id": 9, "country": "RU", "region": "Москва", "city": "Москва"}
]
}
]
}
От суммы
Для DeliveryVariant::PriceDepend обязательно поле min_price — стоимость доставки, если ни одно правило не подошло. Правила передаются в rules_attributes. У каждого правила order_price должен быть строго больше нуля. Нулевой порог отклоняется со статусом 422 и телом {"rules.order_price":["Стоимость заказа должна быть больше нуля"]}.
Вместе с порогом суммы можно указать order_weight. Поле price задаёт стоимость доставки при достижении порога.
| Параметр | Описание |
|---|---|
delivery_variant[type] обязательныйстрока |
DeliveryVariant::PriceDepend. |
delivery_variant[title] обязательныйстрока |
Название способа. |
delivery_variant[min_price] обязательныйчисло |
Цена, если правило не подошло. Ноль допустим. |
delivery_variant[rules_attributes] необязательныймассив |
Пороги. order_price больше нуля, price — цена доставки, order_weight необязателен. |
POST /admin/delivery_variants.json
Authorization: Basic API_KEY:API_PASSWORD
Accept: application/json
Content-Type: application/json
{
"delivery_variant": {
"type": "DeliveryVariant::PriceDepend",
"title": "docs-api от суммы",
"min_price": 200,
"rules_attributes": [
{"order_price": 1, "price": 500},
{"order_price": 3000, "price": 0}
]
}
}
Ответ · 201
{
"id": 81,
"type": "DeliveryVariant::PriceDepend",
"title": "docs-api от суммы",
"min_price": "200.0",
"rules": [
{"id": 1, "order_price": "1.0", "price": "500.0", "order_weight": null},
{"id": 9, "order_price": "3000.0", "price": "0.0", "order_weight": null}
]
}
Правило с весом возвращает order_weight строкой, например "2.0".
Самовывоз
При создании DeliveryVariant::PickUp InSales также создаёт способ оплаты PaymentGateway::PickUp с названием «Оплата в точке самовывоза», если его ещё нет. В ответе создания связь с этой оплатой может отсутствовать; проверьте её следующим GET-запросом. Для чтения и создания точек используйте методы раздела «Точки самовывоза».
Точка внешнего пункта передаётся в заказ тем же order[delivery_info_attributes], внутри outlet. Для этого типа у точки нужны latitude и longitude. Без координат ответ 422:
{
"delivery_variant_id": ["Не выбрана точка самовывоза"],
"base": ["Не выбрана точка самовывоза"]
}
С координатами заказ сохраняется, а delivery_info.outlet содержит id, external_id, latitude, longitude, title, address и source_id.
В объекте есть пустые массивы pick_up_sources и pick_up_source_delivery_variants.
| Параметр | Описание |
|---|---|
delivery_variant[type] обязательныйстрока |
DeliveryVariant::PickUp. |
delivery_variant[title] обязательныйстрока |
Название способа. |
delivery_variant[add_payment_gateways] необязательныйлогический |
Привязать текущие способы оплаты. |
POST /admin/delivery_variants.json
Authorization: Basic API_KEY:API_PASSWORD
Accept: application/json
Content-Type: application/json
{
"delivery_variant": {
"type": "DeliveryVariant::PickUp",
"title": "docs-api самовывоз",
"add_payment_gateways": true
}
}
Ответ · 201
{
"id": 73,
"type": "DeliveryVariant::PickUp",
"title": "docs-api самовывоз",
"payment_delivery_variants": [
{"id": 5, "payment_gateway_id": 6101770}
],
"pick_up_sources": [],
"pick_up_source_delivery_variants": [],
"delivery_locations": [],
"delivery_time_intervals": []
}
Точки самовывоза
GET /admin/outlets.json возвращает точки самовывоза способов DeliveryVariant::PickUp. Если точек нет, ответ содержит []. При создании точки InSales находит способ этого типа. Если его нет, InSales создаёт способ «Доставка в точки самовывоза».
Обязательны title, address, price и пара координат latitude, longitude. Цена ноль допустима.
| Параметр | Описание |
|---|---|
outlet[title] обязательныйстрока |
Название точки. |
outlet[address] обязательныйстрока |
Адрес. |
outlet[description] необязательныйстрока |
Как найти точку. |
outlet[price] обязательныйчисло |
Цена выдачи. Ноль допустим. |
outlet[latitude] обязательныйчисло |
Широта. |
outlet[longitude] обязательныйчисло |
Долгота. |
POST /admin/outlets.json
Authorization: Basic API_KEY:API_PASSWORD
Accept: application/json
Content-Type: application/json
{
"outlet": {
"title": "docs-api пункт",
"address": "Москва, ул. Пример, 1",
"description": "Вход со двора",
"price": 0,
"latitude": "55.755800",
"longitude": "37.617300"
}
}
Ответ · 201
{
"id": 1,
"account_id": 233686,
"delivery_variant_id": 73,
"title": "docs-api пункт",
"description": "Вход со двора",
"address": "Москва, ул. Пример, 1",
"price": "0.0",
"latitude": "55.7558",
"longitude": "37.6173",
"title_translations": ["docs-api пункт"],
"description_translations": ["Вход со двора"]
}
Название и описание приходят и строкой, и массивом переводов. PUT с price и description отвечает 200 и обновлённым объектом.
Без адреса и координат ответ 422:
{
"address": ["Не заполнены обязательные поля"],
"coordinates": ["Не валидный формат координаты точки"]
}
Адрес без координат отвечает 422 только по coordinates.
DELETE /admin/outlets/1.json отвечает 200, тело пустое.