Shipping quotes API

POST /v1/fulfillment/shipping/quotes estimates international shipping from a destination, weight, dimensions, item attributes, and services.

Use the single-package shorthand when the warehouse split is unknown. Use packages[] when the package count and per-package measurements are already known.

This endpoint uses the same channel, region, service, billing, and money terminology as the Shipping channels API.

POSThttps://api.hiobuy.com/v1/fulfillment/shipping/quotes

Quotes are budgets, not locked prices. Warehouse weighing, volume measurement, re-packing, and service review can change the final amount. A COMPLETE quote is still not a price lock.

Compatibility alias: POST /v1/fulfillment/shipments/freight/estimate (same behavior). Prefer /v1/fulfillment/shipping/quotes.

Money and units {#units}

  • All money amount values are integer CNY fen. 5000 means ¥50.00.
  • Top-level monetary_unit is always CNY_minor.
  • Money objects use { "amount": 5000, "currency": "CNY" }.
  • Request weight is always KG. Package dimensions are always CM.
  • Identify channels and services by stable code, not name.

Request headers {#request}

POST /v1/fulfillment/shipping/quotes
Authorization: Bearer hio_live_xxx
Content-Type: application/json
Language: en

Display language is the Language header only. Supported values: en (default), en-US, zh, zh-CN, zh-TW, cn, hk. Do not put language in the JSON body or query string.

Two request formats {#request-formats}

Do not combine the single-package shorthand fields (weight_kg, length_cm, width_cm, height_cm) with packages[]. The API rejects a mixed request with 400 VALIDATION_ERROR.

Format A — single-package shorthand {#format-a}

Use this when you know the destination and estimated total weight, but not how the warehouse will split boxes.

Minimal request:

{
  "destination": {
    "country_code": "KR"
  },
  "weight_kg": 2.05
}

Single package with dimensions:

{
  "destination": {
    "country_code": "KR",
    "postal_code": "04524"
  },
  "weight_kg": 2.05,
  "length_cm": 30,
  "width_cm": 20,
  "height_cm": 10,
  "attributes": []
}
  • weight_kg is the estimated shipment weight in KG.
  • length_cm, width_cm, and height_cm are CM. Provide all three or omit all three.
  • Prefer this format when the final warehouse split is unknown. Missing dimensions may produce PARTIAL or REVIEW_REQUIRED for volumetric channels.

Format B — known packages {#format-b}

Use packages[] when you already know the box count and each box’s data.

Single declared package:

{
  "destination": {
    "country_code": "KR"
  },
  "packages": [
    {
      "reference": "box-1",
      "weight": {
        "value": 2.05,
        "unit": "KG"
      },
      "dimensions": {
        "length": 30,
        "width": 20,
        "height": 10,
        "unit": "CM"
      }
    }
  ]
}

Multiple packages:

{
  "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[] rules (OpenAPI):

  • 1–200 packages.
  • One element is an explicit single package. Multiple elements are an explicit multi-package shipment.
  • reference is optional, but must be unique within the request.
  • packages[].weight is required. packages[].weight.unit must be KG.
  • packages[].dimensions is optional. When present, length, width, height, and unit are all required. unit must be CM.

The Gateway maps format A to a single warehouse package. Format B is validated and mapped as declared. Final split and measured dimensions are still determined after warehouse processing.

Shared request fields {#shared-fields}

Both formats may include the following.

destination

FieldRequiredDescription
country_codeYesISO 3166-1 alpha-2, two letters
subdivision_codeNoFor example US-CA. The country prefix must match country_code.
regionNoSubdivision display name. A valid subdivision_code takes precedence.
postal_codeNoString. Keep leading zeroes.

declared_value

{
  "amount": 5000,
  "currency": "CNY"
}

Shipment-level declared value in integer CNY fen. Omit the field when unknown. Do not send 0 to mean unknown.

attributes

Array of stable item-attribute codes from GET /v1/fulfillment/shipments/item-attributes. Unique strings, max 100.

Quotes are first limited to channels applicable to destination.country_code; channels for other countries are omitted. Each remaining channel evaluates the declared attributes independently. Unsupported attributes produce UNAVAILABLE with ATTRIBUTE_NOT_SUPPORTED, while other applicable channels may still return quotes.

services

{
  "services": {
    "channel": [
      {
        "code": "LINE_INSURANCE",
        "quantity": 1
      }
    ],
    "outbound": [
      {
        "code": "VACUUM_PACKING",
        "quantity": 1
      }
    ],
    "inbound": [
      {
        "code": "PHOTO",
        "quantity": 3
      }
    ]
  }
}
GroupMeaning
channelChannel value-added services. Codes come from channels value_added_services[].code.
outboundOutbound warehouse processing
inboundInbound warehouse processing

Each item requires code and quantity. OpenAPI: quantity is an integer from 1 to 999. Codes must be unique within each group.

channel_codes

Stable channel codes that restrict the quote set. Omit to quote all candidate channels. Do not send an empty array. An unknown or inaccessible code returns 400 INVALID_SHIPPING_CHANNEL for the whole request.

Complete request example {#complete-request}

Format A with destination, dimensions, declared value, attributes, services, and a channel filter:

{
  "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 {#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."
}

Top-level fields

FieldDescription
successtrue on a successful estimate, including when some quotes are UNAVAILABLE.
estimate_typeDECLARED — based on declared data, not warehouse measurement.
completenessHow complete the input is. Not a deliverability guarantee.
warningsShipment-level warnings.
quotesPer-channel results: complete first, then partial/review, then unavailable.
monetary_unitAlways CNY_minor.
generated_atResponse timestamp.
request_idCorrelate with x-request-id.
disclaimerHuman-readable estimate disclaimer.

completeness

FieldMeaning
levelOverall input coverage, for example HIGH.
destinationHow complete the destination is (COMPLETE when country is present).
package_dimensionsWhether length/width/height were provided.
package_splitDECLARED when you sent packages[]; shorthand is an assumed single package.
declared_valuePROVIDED or omitted/unknown.
attributesWhether item attributes were declared.
servicesREQUESTED_ONLY when you sent selected services; warehouse may still add more.

Quote status {#quote-status}

Do not decide from available alone. Always read quote_status.

quote_statusavailabletotalMeaning
COMPLETEtrueMoney objectFull budget you may display. Still not locked.
PARTIALtrueusually nullMissing inputs. Read warnings and add dimensions, postal code, or declared value.
REVIEW_REQUIREDtrueusually nullWarehouse measurement or human review is required.
UNAVAILABLEfalsenullThis channel cannot quote. The HTTP request still succeeded.
  • total is the complete budget when known.
  • known_total is the sum of fees that can be calculated now.
  • When total is null, do not treat known_total as a complete quote.
  • unavailable_reason.code is for programmatic handling.
  • unavailable_reason.message is display-only.

UNAVAILABLE on one quote is not an HTTP error.

Quote object {#quotes}

FieldDescription
channel{ code, name, description, tags, capabilities } — same identity as the channel catalog.
channel.capabilities.delivery_methodsOptional additive array of stable last-mile codes: DOOR_DELIVERY, PICKUP, POST_OFFICE_PICKUP. It may be present for every quote status. Existing clients may ignore it.
availableWhether this channel produced a usable estimate. Pair with quote_status.
quote_statusCOMPLETE · PARTIAL · REVIEW_REQUIRED · UNAVAILABLE.
unavailable_reason{ code, message } or null.
attribute_evaluationOptional per-channel result: SUPPORTED, UNSUPPORTED, or NOT_DECLARED, with declared, accepted, and unsupported attribute lists.
matched_region{ code, name, match_type } or null.
packagesDeclared or mapped packages plus per-package weights.
weightsShipment-level actual / volumetric / chargeable in KG.
billing_quantityQuantity the channel actually bills, with unit KG, M3, or KG_PER_M3.
pricing_selectorHow that quantity hit a rate-card band (type, value, unit, scope).
transit_timeReference transit time.
chargesFee groups. See below.
display_chargesOptional UI-only rows. If included_in_total is false, do not add them to total.
total / known_totalComplete budget vs currently known fees.
warningsChannel-level warnings.
service_adjustment_possibletrue if warehouse processing may still change services and fees.

Weights and billing quantity {#weights}

  • actual — declared or measured weight.
  • volumetric — dimensional weight.
  • chargeable — weight used for freight.
  • billing_quantity — quantity the channel bills (may be weight, volume, or density).
  • pricing_selector — how that quantity selected a rate row. Types match catalog WEIGHT / VOLUME / DENSITY.
  • Multi-package channels may round per box and then sum. When pricing_selector.scope is PER_PACKAGE, read each packages[].pricing_selector.

Charges {#charges}

GroupMeaning
base_freightBase international freight
channel_servicesMandatory and developer-selected channel services
channel_rulesOversize, overweight, declared-value, and other route rules
outbound_servicesValue-added services performed during shipment preparation / outbound processing
inbound_servicesValue-added services performed during warehouse receiving / inbound processing
adjustmentsAdjustments

Inbound vs outbound services

Inbound and outbound services represent different stages of warehouse value-added services. Inbound services are performed during warehouse receiving, while outbound services are performed during shipment preparation. Both groups may legitimately appear in the same quote and may both be charged when different services are performed at each stage.

The amounts shown in a shipping quote are estimates of the applicable services only. Requesting a quote does not create or settle a service charge. Final charges are determined by the services actually performed and their final package/shipment service pricing and settlement.

Use both groups when estimating total fulfillment cost, then reconcile each estimated service against its corresponding final actual charge. Do not add a quote estimate again on top of the final charge for the same individual service.

Illustrative quote amounts (all amounts use CNY minor units):

StageExample serviceEstimated amount
InboundPackage photos50 fen (¥0.50)
InboundInspection100 fen (¥1.00)
OutboundVacuum packing150 fen (¥1.50)
OutboundPackage reinforcement200 fen (¥2.00)

All four estimates may coexist because they are different services performed at different fulfillment stages. Other inbound examples include video recording and receiving-related services requested by the customer; other outbound examples include wooden-frame / wooden-crate packing and outbound handling services.

Each group typically includes:

FieldMeaning
amountGroup total in fen, or null if unknown
currencyCNY
known_amountSum of items that can be calculated now
calculation_statusFor example CALCULATED
itemsLine items

channel_rules may also include aggregation and cap. Use the group subtotal — do not replace it by summing raw rule items.

aggregation=SUM_ALL accumulates every matched charge. HIGHEST_ONLY sorts by amount and selects only the highest; equal-priced rules are equivalent. cap limits the aggregated subtotal, and null means uncapped.

Charge items

FieldMeaning
codeStable fee or service code
nameLocalized display name
categoryFee category
sourceMANDATORY · DEVELOPER_SELECTED · RULE_ENGINE
pricing_basisHow the line was priced
quantityBillable quantity for the line
unit_priceUnit price in fen when known
amountLine total. null means unknown, not zero.
estimatedWhether the line is still an estimate
calculation_statusCalculation state
affected_by_packagesWhether package count/size can change this line
included_in_totalIf false, do not add it again to total
reasonDisplay-only explanation; do not use it for program logic
condition_matchALL requires every condition; ANY requires at least one
matched_conditionsConditions with shipment actual_value and configured threshold_value
rule_typePer-shipment, per-box, weight-based, order/dispatch restriction, or advanced rule
charge_mode / charge_valueFixed, percentage, or formula configuration and potential rate
outcomeEvaluated result, for example CHARGE
missing_fieldsInputs required when the rule cannot yet be evaluated

display_charges may exist only for frontend presentation.

PENDING_INPUT, REVIEW_REQUIRED, and other uncalculated rules are excluded from the known total. amount=null is not zero, and a configured charge_value is not an incurred charge.

Unavailable reasons {#unavailable-reasons}

Common unavailable_reason.code values:

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

Unavailable channels stay in quotes[] so you can explain why they were rejected.

Catalog terminology {#catalog-terminology}

Shipping channelsThis APIMeaning
items[].code/name/description/tagsquotes[].channel.*Same channel
items[].capabilities.delivery_methodsquotes[].channel.capabilities.delivery_methodsSame stable last-mile delivery-method codes
regions[].code/name/match_typequotes[].matched_region.*Region selected by the quote
value_added_services[].codeservices.channel[].code and charge codeStable service code
billing.quantity_unitbilling_quantity.unit / pricing_selector.unitBilling unit
rule_summary.aggregationcharges.channel_rules.aggregationRule aggregation
rule_summary.capcharges.channel_rules.capCap after aggregation; null means uncapped

Item attributes {#item-attributes}

GET /v1/fulfillment/shipments/item-attributes returns the valid attributes[] codes for quotes.

Errors {#errors}

HTTPerror.codeWhen
400VALIDATION_ERRORInvalid structure, mixed request formats, KG/CM units, duplicate codes, or empty channel_codes
400INVALID_SHIPPING_CHANNELA requested channel_codes value is unknown or not visible to the app
401INVALID_API_KEYMissing or invalid Bearer token
403FULFILLMENT_MODE_NOT_SUPPORTEDApp uses self fulfillment
403WAREHOUSE_AUTH_INVALIDWarehouse authorization is missing, rejected, or expired
422INVALID_COUNTRY_CODEDestination country is invalid
422INVALID_ITEM_ATTRIBUTEAn attribute code is invalid
502WAREHOUSE_UPSTREAM_ERRORWarehouse service failed; retry with backoff

There is no distinct public AUTHENTICATION_ERROR, WAREHOUSE_AUTH_REQUIRED, or WAREHOUSE_SERVICE_UNAVAILABLE code. Use 401 INVALID_API_KEY, 403 WAREHOUSE_AUTH_INVALID, and 502 WAREHOUSE_UPSTREAM_ERROR.

A channel that cannot carry this shipment is an UNAVAILABLE quote, not an HTTP failure.

Get Support

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

Email support