API расчёта стоимости доставки

POST /v1/fulfillment/shipping/quotes оценивает международную доставку по направлению, весу, габаритам, атрибутам товара и услугам.

Используйте сокращённую форму одного места, если разбиение на складе неизвестно. Используйте packages[], если число мест и измерения каждого места уже известны.

Этот эндпоинт использует ту же терминологию каналов, регионов, услуг, тарификации и денежных сумм, что и API каналов доставки.

POSThttps://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."
}

Поля верхнего уровня

ПолеОписание
successtrue при успешной оценке, в том числе если часть предложений имеет статус UNAVAILABLE.
estimate_typeDECLARED — на основе заявленных данных, а не складских измерений.
completenessНасколько полны входные данные. Не гарантия доставляемости.
warningsПредупреждения на уровне отправления.
quotesРезультаты по каналам: сначала полные, затем частичные/на проверке, затем недоступные.
monetary_unitВсегда CNY_minor.
generated_atМетка времени ответа.
request_idСопоставляйте с x-request-id.
disclaimerЧеловекочитаемая оговорка оценки.

completeness

ПолеЗначение
levelОбщая полнота ввода, например HIGH.
destinationНасколько полно указано направление (COMPLETE, если страна присутствует).
package_dimensionsБыли ли переданы длина/ширина/высота.
package_splitDECLARED, если вы отправили packages[]; сокращённая форма — предполагаемое одно место.
declared_valuePROVIDED либо опущено/неизвестно.
attributesБыли ли заявлены атрибуты товара.
servicesREQUESTED_ONLY, если вы передали выбранные услуги; склад всё ещё может добавить другие.

Статус предложения {#quote-status}

Не принимайте решение только по available. Всегда читайте quote_status.

quote_statusavailabletotalЗначение
COMPLETEtrueДенежный объектПолный бюджет, который можно показать. По-прежнему не зафиксирован.
PARTIALtrueобычно nullНе хватает входных данных. Прочитайте предупреждения и добавьте габариты, почтовый индекс или заявленную стоимость.
REVIEW_REQUIREDtrueобычно nullТребуется складское измерение или ручная проверка.
UNAVAILABLEfalsenullЭтот канал не может рассчитать стоимость. 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_statusCOMPLETE · PARTIAL · REVIEW_REQUIRED · UNAVAILABLE.
unavailable_reason{ code, message } или null.
attribute_evaluationНеобязательный результат по каналу: SUPPORTED, UNSUPPORTED или NOT_DECLARED, со списками заявленных, принятых и неподдерживаемых атрибутов.
matched_region{ code, name, match_type } или null.
packagesЗаявленные или сопоставленные места плюс веса по каждому месту.
weightsactual / 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_possibletrue, если обработка на складе всё ещё может изменить услуги и сборы.

Веса и тарифицируемое количество {#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, если неизвестно
currencyCNY
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Категория сбора
sourceMANDATORY · 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/tagsquotes[].channel.*Тот же канал
regions[].code/name/match_typequotes[].matched_region.*Регион, выбранный расчётом
value_added_services[].codeservices.channel[].code и code начисленияСтабильный код услуги
billing.quantity_unitbilling_quantity.unit / pricing_selector.unitЕдиница тарификации
rule_summary.aggregationcharges.channel_rules.aggregationАгрегация правил
rule_summary.capcharges.channel_rules.capЛимит после агрегации; null означает без лимита

Атрибуты товара {#item-attributes}

GET /v1/fulfillment/shipments/item-attributes возвращает допустимые коды attributes[] для расчёта.

Ошибки {#errors}

HTTPerror.codeКогда
400VALIDATION_ERRORНеверная структура, смешанные форматы запроса, единицы KG/CM, дублирующиеся коды или пустой channel_codes
400INVALID_SHIPPING_CHANNELЗапрошенное значение в channel_codes неизвестно или недоступно приложению
401INVALID_API_KEYОтсутствует или недействителен Bearer-токен
403FULFILLMENT_MODE_NOT_SUPPORTEDПриложение использует самостоятельный фулфилмент
403WAREHOUSE_AUTH_INVALIDАвторизация склада отсутствует, отклонена или истекла
422INVALID_COUNTRY_CODEСтрана назначения недействительна
422INVALID_ITEM_ATTRIBUTEКод атрибута недействителен
502WAREHOUSE_UPSTREAM_ERRORСкладской сервис недоступен; повторите с отступом

Отдельных публичных кодов AUTHENTICATION_ERROR, WAREHOUSE_AUTH_REQUIRED или WAREHOUSE_SERVICE_UNAVAILABLE нет. Используйте 401 INVALID_API_KEY, 403 WAREHOUSE_AUTH_INVALID и 502 WAREHOUSE_UPSTREAM_ERROR.

Канал, который не может перевезти это отправление, — это предложение со статусом UNAVAILABLE, а не сбой HTTP.

Get Support

Need integration help? Contact Developer Support at support@hiobuy.com · Response within 1–2 business days

Email support