API расчёта стоимости доставки
POST /v1/fulfillment/shipping/quotes оценивает международную доставку по направлению, весу, габаритам, атрибутам товара и услугам.
Используйте сокращённую форму одного места, если разбиение на складе неизвестно. Используйте packages[], если число мест и измерения каждого места уже известны.
Этот эндпоинт использует ту же терминологию каналов, регионов, услуг, тарификации и денежных сумм, что и API каналов доставки.
https://api.hiobuy.com/v1/fulfillment/shipping/quotesПредложения — это бюджеты, а не зафиксированные цены. Взвешивание на складе, обмер объёма, переупаковка и проверка услуг могут изменить итоговую сумму. Предложение со статусом
COMPLETEпо-прежнему не фиксирует цену.
Совместимый псевдоним: POST /v1/fulfillment/shipments/freight/estimate (то же поведение). Предпочитайте /v1/fulfillment/shipping/quotes.
Деньги и единицы {#units}
- Все денежные значения
amount— целые фэни CNY.5000означает ¥50.00. - Поле верхнего уровня
monetary_unitвсегда равноCNY_minor. - Денежные объекты имеют вид
{ "amount": 5000, "currency": "CNY" }. - Вес в запросе всегда в
KG. Габариты места всегда вCM. - Идентифицируйте каналы и услуги по стабильному code, а не по
name.
Заголовки запроса {#request}
POST /v1/fulfillment/shipping/quotes
Authorization: Bearer hio_live_xxx
Content-Type: application/json
Language: enЯзык отображения задаётся только заголовком Language. Поддерживаемые значения: en (по умолчанию), en-US, zh, zh-CN, zh-TW, cn, hk. Не передавайте language в JSON-теле или в строке запроса.
Два формата запроса {#request-formats}
Не сочетайте поля сокращённой формы одного места (
weight_kg,length_cm,width_cm,height_cm) сpackages[]. API отклоняет смешанный запрос с400 VALIDATION_ERROR.
Формат A — сокращённая форма одного места {#format-a}
Используйте его, когда известны направление и оценочный суммарный вес, но неизвестно, как склад разобьёт коробки.
Минимальный запрос:
{
"destination": {
"country_code": "KR"
},
"weight_kg": 2.05
}Одно место с габаритами:
{
"destination": {
"country_code": "KR",
"postal_code": "04524"
},
"weight_kg": 2.05,
"length_cm": 30,
"width_cm": 20,
"height_cm": 10,
"attributes": []
}weight_kg— оценочный вес отправления вKG.length_cm,width_cmиheight_cmзадаются вCM. Укажите все три или не указывайте ни одного.- Предпочитайте этот формат, если итоговое складское разбиение неизвестно. Отсутствующие габариты могут дать
PARTIALилиREVIEW_REQUIREDдля каналов с объёмным весом.
Формат B — известные места {#format-b}
Используйте packages[], когда уже известны число коробок и данные каждой коробки.
Одно заявленное место:
{
"destination": {
"country_code": "KR"
},
"packages": [
{
"reference": "box-1",
"weight": {
"value": 2.05,
"unit": "KG"
},
"dimensions": {
"length": 30,
"width": 20,
"height": 10,
"unit": "CM"
}
}
]
}Несколько мест:
{
"destination": {
"country_code": "KR",
"postal_code": "04524"
},
"packages": [
{
"reference": "box-1",
"weight": {
"value": 1.25,
"unit": "KG"
},
"dimensions": {
"length": 30,
"width": 20,
"height": 10,
"unit": "CM"
}
},
{
"reference": "box-2",
"weight": {
"value": 0.8,
"unit": "KG"
},
"dimensions": {
"length": 20,
"width": 15,
"height": 8,
"unit": "CM"
}
}
]
}Правила packages[] (OpenAPI):
- 1–200 мест.
- Один элемент — явное одно место. Несколько элементов — явная многоместная отправка.
referenceнеобязателен, но должен быть уникален в пределах запроса.packages[].weightобязателен.packages[].weight.unitдолжен бытьKG.packages[].dimensionsнеобязателен. Если указан, обязательныlength,width,heightиunit.unitдолжен бытьCM.
Шлюз сопоставляет формат A с одним складским местом. Формат B проверяется и сопоставляется как заявленный. Итоговое разбиение и измеренные габариты по-прежнему определяются после обработки на складе.
Общие поля запроса {#shared-fields}
Оба формата могут включать следующее.
destination
| Поле | Обязательно | Описание |
|---|---|---|
country_code | Да | ISO 3166-1 alpha-2, две буквы |
subdivision_code | Нет | Например US-CA. Префикс страны должен совпадать с country_code. |
region | Нет | Отображаемое имя подразделения. Действительный subdivision_code имеет приоритет. |
postal_code | Нет | Строка. Сохраняйте ведущие нули. |
declared_value
{
"amount": 5000,
"currency": "CNY"
}Заявленная стоимость на уровне отправления в целых фэнях CNY. Не передавайте поле, если значение неизвестно. Не отправляйте 0 в значении «неизвестно».
attributes
Массив стабильных кодов атрибутов товара из GET /v1/fulfillment/shipments/item-attributes. Уникальные строки, не более 100.
Сначала расчёт ограничивается каналами, применимыми к destination.country_code; каналы других стран исключаются. Каждый оставшийся канал отдельно оценивает заявленные атрибуты. Неподдерживаемый атрибут даёт UNAVAILABLE с ATTRIBUTE_NOT_SUPPORTED, при этом другие подходящие каналы могут продолжить возвращать расчёты.
services
{
"services": {
"channel": [
{
"code": "LINE_INSURANCE",
"quantity": 1
}
],
"outbound": [
{
"code": "VACUUM_PACKING",
"quantity": 1
}
],
"inbound": [
{
"code": "PHOTO",
"quantity": 3
}
]
}
}| Группа | Значение |
|---|---|
channel | Дополнительные услуги канала. Коды берутся из каналов value_added_services[].code. |
outbound | Исходящая обработка на складе |
inbound | Входящая обработка на складе |
Каждый элемент требует code и quantity. OpenAPI: quantity — целое от 1 до 999. Коды должны быть уникальны внутри каждой группы.
channel_codes
Стабильные коды каналов, ограничивающие набор расчётов. Опустите поле, чтобы рассчитать все кандидатные каналы. Не отправляйте пустой массив. Неизвестный или недоступный код возвращает 400 INVALID_SHIPPING_CHANNEL для всего запроса.
Полный пример запроса {#complete-request}
Формат A с направлением, габаритами, заявленной стоимостью, атрибутами, услугами и фильтром канала:
{
"destination": {
"country_code": "US",
"subdivision_code": "US-CA",
"region": "California",
"postal_code": "90001"
},
"weight_kg": 2.05,
"length_cm": 30,
"width_cm": 20,
"height_cm": 10,
"declared_value": {
"amount": 5000,
"currency": "CNY"
},
"attributes": [
"GENERAL_CARGO"
],
"services": {
"channel": [
{
"code": "LINE_INSURANCE",
"quantity": 1
}
],
"outbound": [
{
"code": "VACUUM_PACKING",
"quantity": 1
}
],
"inbound": [
{
"code": "PHOTO",
"quantity": 3
}
]
},
"channel_codes": [
"US-SEA"
]
}Ответ {#response}
{
"success": true,
"estimate_type": "DECLARED",
"completeness": {
"level": "HIGH",
"destination": "COMPLETE",
"package_dimensions": "COMPLETE",
"package_split": "DECLARED",
"declared_value": "PROVIDED",
"attributes": "DECLARED",
"services": "REQUESTED_ONLY"
},
"warnings": [
{
"code": "WAREHOUSE_REVIEW_REQUIRED",
"message": "Final charges require warehouse measurement, packing and service review.",
"affects": [
"FINAL_CHARGES"
]
}
],
"quotes": [
{
"channel": {
"code": "US-SEA",
"name": "US Ocean",
"description": "General cargo line",
"tags": [
"GREAT_VALUE"
],
"capabilities": {
"delivery_methods": [
"DOOR_DELIVERY",
"PICKUP"
]
}
},
"available": true,
"quote_status": "COMPLETE",
"unavailable_reason": null,
"attribute_evaluation": {
"status": "SUPPORTED",
"declared_attributes": [
{
"code": "GENERAL",
"name": "General cargo"
}
],
"accepted_attributes": [
{
"code": "GENERAL",
"name": "General cargo"
}
],
"unsupported_attributes": []
},
"matched_region": {
"code": "US-WEST",
"name": "US West",
"match_type": "COUNTRY_REGION"
},
"packages": [
{
"reference": "box-1",
"weight": {
"value": 2.05,
"unit": "KG"
},
"dimensions": {
"length": 30,
"width": 20,
"height": 10,
"unit": "CM"
},
"weights": {
"actual": {
"value": 2.05,
"unit": "KG"
},
"volumetric": {
"value": 1,
"unit": "KG"
},
"chargeable": {
"value": 2.5,
"unit": "KG"
}
}
}
],
"weights": {
"actual": {
"value": 2.05,
"unit": "KG"
},
"volumetric": {
"value": 1,
"unit": "KG"
},
"chargeable": {
"value": 2.5,
"unit": "KG"
}
},
"billing_quantity": {
"value": 2.5,
"unit": "KG"
},
"pricing_selector": {
"type": "WEIGHT",
"value": 2.5,
"unit": "KG",
"scope": "SHIPMENT"
},
"transit_time": {
"text": "15-18 business days",
"min_business_days": 15,
"max_business_days": 18
},
"charges": {
"base_freight": {
"amount": 10000,
"currency": "CNY"
},
"channel_services": {
"amount": 550,
"currency": "CNY",
"known_amount": 550,
"calculation_status": "CALCULATED",
"items": []
},
"channel_rules": {
"amount": 0,
"currency": "CNY",
"known_amount": 0,
"calculation_status": "CALCULATED",
"items": [],
"aggregation": "SUM_ALL",
"cap": null
},
"outbound_services": {
"amount": 800,
"currency": "CNY",
"known_amount": 800,
"calculation_status": "CALCULATED",
"items": []
},
"inbound_services": {
"amount": 300,
"currency": "CNY",
"known_amount": 300,
"calculation_status": "CALCULATED",
"items": []
},
"adjustments": {
"amount": 0,
"currency": "CNY",
"known_amount": 0,
"calculation_status": "CALCULATED",
"items": []
}
},
"display_charges": {
"addition": {
"amount": 0,
"currency": "CNY",
"included_in_total": false
},
"floor": {
"amount": 0,
"currency": "CNY",
"included_in_total": false
}
},
"total": {
"amount": 11650,
"currency": "CNY"
},
"known_total": {
"amount": 11650,
"currency": "CNY"
},
"warnings": [],
"service_adjustment_possible": true
}
],
"monetary_unit": "CNY_minor",
"generated_at": "2026-09-07T08:00:00Z",
"request_id": "req_xxx",
"disclaimer": "Estimated charges based on declared data."
}Поля верхнего уровня
| Поле | Описание |
|---|---|
success | true при успешной оценке, в том числе если часть предложений имеет статус UNAVAILABLE. |
estimate_type | DECLARED — на основе заявленных данных, а не складских измерений. |
completeness | Насколько полны входные данные. Не гарантия доставляемости. |
warnings | Предупреждения на уровне отправления. |
quotes | Результаты по каналам: сначала полные, затем частичные/на проверке, затем недоступные. |
monetary_unit | Всегда CNY_minor. |
generated_at | Метка времени ответа. |
request_id | Сопоставляйте с x-request-id. |
disclaimer | Человекочитаемая оговорка оценки. |
completeness
| Поле | Значение |
|---|---|
level | Общая полнота ввода, например HIGH. |
destination | Насколько полно указано направление (COMPLETE, если страна присутствует). |
package_dimensions | Были ли переданы длина/ширина/высота. |
package_split | DECLARED, если вы отправили packages[]; сокращённая форма — предполагаемое одно место. |
declared_value | PROVIDED либо опущено/неизвестно. |
attributes | Были ли заявлены атрибуты товара. |
services | REQUESTED_ONLY, если вы передали выбранные услуги; склад всё ещё может добавить другие. |
Статус предложения {#quote-status}
Не принимайте решение только по available. Всегда читайте quote_status.
quote_status | available | total | Значение |
|---|---|---|---|
COMPLETE | true | Денежный объект | Полный бюджет, который можно показать. По-прежнему не зафиксирован. |
PARTIAL | true | обычно null | Не хватает входных данных. Прочитайте предупреждения и добавьте габариты, почтовый индекс или заявленную стоимость. |
REVIEW_REQUIRED | true | обычно null | Требуется складское измерение или ручная проверка. |
UNAVAILABLE | false | null | Этот канал не может рассчитать стоимость. HTTP-запрос при этом успешен. |
total— полный бюджет, когда он известен.known_total— сумма сборов, которые можно рассчитать сейчас.- Если
totalравенnull, не считайтеknown_totalполным расчётом. unavailable_reason.codeпредназначен для программной обработки.unavailable_reason.messageтолько для отображения.
UNAVAILABLE у одного предложения — не HTTP-ошибка.
Объект предложения {#quotes}
| Поле | Описание |
|---|---|
channel | { code, name, description, tags, capabilities } — та же идентичность, что в каталоге каналов. |
channel.capabilities.delivery_methods | Необязательный обратно совместимый массив стабильных кодов доставки: DOOR_DELIVERY, PICKUP, POST_OFFICE_PICKUP. Возможен при любом статусе; существующие клиенты могут его игнорировать. |
available | Сформировал ли канал пригодную оценку. Читайте вместе с quote_status. |
quote_status | COMPLETE · PARTIAL · REVIEW_REQUIRED · UNAVAILABLE. |
unavailable_reason | { code, message } или null. |
attribute_evaluation | Необязательный результат по каналу: SUPPORTED, UNSUPPORTED или NOT_DECLARED, со списками заявленных, принятых и неподдерживаемых атрибутов. |
matched_region | { code, name, match_type } или null. |
packages | Заявленные или сопоставленные места плюс веса по каждому месту. |
weights | actual / volumetric / chargeable на уровне отправления в KG. |
billing_quantity | Количество, которое канал фактически тарифицирует, с единицей KG, M3 или KG_PER_M3. |
pricing_selector | Как это количество попало в диапазон тарифной карты (type, value, unit, scope). |
transit_time | Справочный срок доставки. |
charges | Группы сборов. См. ниже. |
display_charges | Необязательные строки только для UI. Если included_in_total равно false, не добавляйте их к total. |
total / known_total | Полный бюджет vs. уже известные сборы. |
warnings | Предупреждения на уровне канала. |
service_adjustment_possible | true, если обработка на складе всё ещё может изменить услуги и сборы. |
Веса и тарифицируемое количество {#weights}
actual— заявленный или измеренный вес.volumetric— объёмный вес.chargeable— вес, используемый для фрахта.billing_quantity— количество, которое тарифицирует канал (вес, объём или плотность).pricing_selector— как это количество выбрало строку тарифа. Типы совпадают с каталогомWEIGHT/VOLUME/DENSITY.- Многоместные каналы могут округлять по коробке, затем суммировать. Если
pricing_selector.scopeравенPER_PACKAGE, читайте каждоеpackages[].pricing_selector.
Начисления {#charges}
| Группа | Значение |
|---|---|
base_freight | Базовый международный фрахт |
channel_services | Обязательные и выбранные разработчиком услуги канала |
channel_rules | Негабарит, перевес, заявленная стоимость и другие правила маршрута |
outbound_services | Дополнительные услуги при подготовке отправления / исходящей обработке |
inbound_services | Дополнительные услуги при приёмке / входящей обработке на складе |
adjustments | Корректировки |
Входящие и исходящие услуги
inbound_services и outbound_services относятся к разным этапам дополнительных складских услуг. Входящие услуги выполняются при приёмке на складе, например фото посылки, видеозапись или проверка. Исходящие услуги выполняются при подготовке отправления, например усиление упаковки, вакуумная упаковка или упаковка в деревянную раму/ящик. Услуги обоих этапов могут применяться и правомерно оплачиваться для одной посылки или отправления.
Суммы в Shipping Quote являются только оценками; запрос расчёта сам по себе не создаёт дополнительную плату за услугу. Итоговые начисления определяются фактически выполненными услугами, их окончательной ценой и расчётом. Используйте обе группы для оценки общей стоимости и сверяйте каждую оценку с соответствующим фактическим начислением. Не прибавляйте оценку одной и той же услуги повторно к её окончательной стоимости.
Пример в минимальных единицах CNY: фото посылки 50 фэней (¥0,50), проверка 100 фэней (¥1,00), вакуумная упаковка 150 фэней (¥1,50), усиление упаковки 200 фэней (¥2,00). Все четыре позиции могут присутствовать одновременно, поскольку это разные услуги на разных этапах обработки.
Каждая группа обычно включает:
| Поле | Значение |
|---|---|
amount | Итог группы в фэнях или null, если неизвестно |
currency | CNY |
known_amount | Сумма позиций, которые можно рассчитать сейчас |
calculation_status | Например CALCULATED |
items | Строки начислений |
channel_rules может также включать aggregation и cap. Используйте промежуточный итог группы — не заменяйте его суммой сырых позиций правил.
SUM_ALL суммирует все совпавшие сборы. HIGHEST_ONLY выбирает только максимальный после сортировки по убыванию; правила с одинаковой ценой равнозначны. cap=null означает отсутствие лимита. reason предназначен только для показа. Для логики используйте condition_match, matched_conditions, rule_type, charge_mode, charge_value, outcome и missing_fields. Правила PENDING_INPUT, REVIEW_REQUIRED и другие нерассчитанные правила исключаются из известной суммы. amount=null — не ноль, а настроенный charge_value — не фактическое начисление.
Позиции начислений
| Поле | Значение |
|---|---|
code | Стабильный код сбора или услуги |
name | Локализованное отображаемое имя |
category | Категория сбора |
source | MANDATORY · DEVELOPER_SELECTED · RULE_ENGINE |
pricing_basis | Как была рассчитана строка |
quantity | Тарифицируемое количество строки |
unit_price | Цена за единицу в фэнях, если известна |
amount | Итог строки. null означает «неизвестно», а не ноль. |
estimated | Является ли строка ещё оценкой |
calculation_status | Состояние расчёта |
affected_by_packages | Может ли число/размер мест изменить эту строку |
included_in_total | Если false, не добавляйте её повторно к total |
display_charges может существовать только для отображения на фронтенде.
Причины недоступности {#unavailable-reasons}
Частые значения unavailable_reason.code:
OUTSIDE_PRICING_RANGE
POSTAL_CODE_REQUIRED
POSTAL_CODE_NOT_SUPPORTED
DESTINATION_NOT_SUPPORTED
ATTRIBUTE_NOT_SUPPORTED
SERVICE_NOT_SUPPORTED
DIMENSIONS_REQUIRED
DECLARED_VALUE_REQUIRED
MULTI_PACKAGE_NOT_SUPPORTED
PRICING_MODE_UNSUPPORTED
CHANNEL_RULE_REJECTED
CHANNEL_PRICING_ERRORНедоступные каналы остаются в quotes[], чтобы вы могли объяснить причину отклонения.
Терминология каталога {#catalog-terminology}
| Каналы доставки | Этот API | Значение |
|---|---|---|
items[].code/name/description/tags | quotes[].channel.* | Тот же канал |
regions[].code/name/match_type | quotes[].matched_region.* | Регион, выбранный расчётом |
value_added_services[].code | services.channel[].code и code начисления | Стабильный код услуги |
billing.quantity_unit | billing_quantity.unit / pricing_selector.unit | Единица тарификации |
rule_summary.aggregation | charges.channel_rules.aggregation | Агрегация правил |
rule_summary.cap | charges.channel_rules.cap | Лимит после агрегации; null означает без лимита |
Атрибуты товара {#item-attributes}
GET /v1/fulfillment/shipments/item-attributes возвращает допустимые коды attributes[] для расчёта.
Ошибки {#errors}
| HTTP | error.code | Когда |
|---|---|---|
| 400 | VALIDATION_ERROR | Неверная структура, смешанные форматы запроса, единицы KG/CM, дублирующиеся коды или пустой channel_codes |
| 400 | INVALID_SHIPPING_CHANNEL | Запрошенное значение в channel_codes неизвестно или недоступно приложению |
| 401 | INVALID_API_KEY | Отсутствует или недействителен Bearer-токен |
| 403 | FULFILLMENT_MODE_NOT_SUPPORTED | Приложение использует самостоятельный фулфилмент |
| 403 | WAREHOUSE_AUTH_INVALID | Авторизация склада отсутствует, отклонена или истекла |
| 422 | INVALID_COUNTRY_CODE | Страна назначения недействительна |
| 422 | INVALID_ITEM_ATTRIBUTE | Код атрибута недействителен |
| 502 | WAREHOUSE_UPSTREAM_ERROR | Складской сервис недоступен; повторите с отступом |
Отдельных публичных кодов AUTHENTICATION_ERROR, WAREHOUSE_AUTH_REQUIRED или WAREHOUSE_SERVICE_UNAVAILABLE нет. Используйте 401 INVALID_API_KEY, 403 WAREHOUSE_AUTH_INVALID и 502 WAREHOUSE_UPSTREAM_ERROR.
Канал, который не может перевезти это отправление, — это предложение со статусом UNAVAILABLE, а не сбой HTTP.
Связанные разделы {#related}
- Каналы доставки — возможности, покрытие и коды услуг
- Отправления — создать отправление после приёма посылок
- Обзор фулфилмента
Get Support
Need integration help? Contact Developer Support at support@hiobuy.com · Response within 1–2 business days