API des devis d’expédition
POST /v1/fulfillment/shipping/quotes estime l’expédition internationale à partir d’une destination, du poids, des dimensions, des attributs d’articles et des services.
Utilisez le raccourci colis unique lorsque le fractionnement en entrepôt est inconnu. Utilisez packages[] lorsque le nombre de colis et les mesures par colis sont déjà connus.
Cet endpoint utilise la même terminologie de canal, région, service, facturation et argent que l’API des canaux d’expédition.
https://api.hiobuy.com/v1/fulfillment/shipping/quotesLes devis sont des budgets, pas des prix verrouillés. Le pesage en entrepôt, la mesure du volume, le reconditionnement et la revue des services peuvent modifier le montant final. Un devis
COMPLETEn’est toujours pas un verrouillage de prix.
Alias de compatibilité : POST /v1/fulfillment/shipments/freight/estimate (même comportement). Préférez /v1/fulfillment/shipping/quotes.
Argent et unités {#units}
- Tous les
amountmonétaires sont des fen CNY entiers.5000signifie ¥50.00. - Le
monetary_unitde premier niveau est toujoursCNY_minor. - Les objets monétaires utilisent
{ "amount": 5000, "currency": "CNY" }. - Le poids de la requête est toujours
KG. Les dimensions de colis sont toujoursCM. - Identifiez les canaux et services par code stable, pas par
name.
En-têtes de requête {#request}
POST /v1/fulfillment/shipping/quotes
Authorization: Bearer hio_live_xxx
Content-Type: application/json
Language: enLa langue d’affichage est uniquement l’en-tête Language. Valeurs prises en charge : en (défaut), en-US, zh, zh-CN, zh-TW, cn, hk. Ne placez pas language dans le corps JSON ni dans la chaîne de requête.
Deux formats de requête {#request-formats}
Ne combinez pas les champs du raccourci colis unique (
weight_kg,length_cm,width_cm,height_cm) avecpackages[]. L’API rejette une requête mixte avec400 VALIDATION_ERROR.
Format A — raccourci colis unique {#format-a}
Utilisez ce format lorsque vous connaissez la destination et le poids total estimé, mais pas comment l’entrepôt fractionnera les cartons.
Requête minimale :
{
"destination": {
"country_code": "KR"
},
"weight_kg": 2.05
}Colis unique avec dimensions :
{
"destination": {
"country_code": "KR",
"postal_code": "04524"
},
"weight_kg": 2.05,
"length_cm": 30,
"width_cm": 20,
"height_cm": 10,
"attributes": []
}weight_kgest le poids estimé de l’expédition enKG.length_cm,width_cmetheight_cmsont enCM. Fournissez les trois ou omettez les trois.- Préférez ce format lorsque le fractionnement final en entrepôt est inconnu. Des dimensions manquantes peuvent produire
PARTIALouREVIEW_REQUIREDpour les canaux volumétriques.
Format B — colis connus {#format-b}
Utilisez packages[] lorsque vous connaissez déjà le nombre de cartons et les données de chaque carton.
Colis déclaré unique :
{
"destination": {
"country_code": "KR"
},
"packages": [
{
"reference": "box-1",
"weight": {
"value": 2.05,
"unit": "KG"
},
"dimensions": {
"length": 30,
"width": 20,
"height": 10,
"unit": "CM"
}
}
]
}Plusieurs colis :
{
"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"
}
}
]
}Règles packages[] (OpenAPI) :
- 1 à 200 colis.
- Un élément est un colis unique explicite. Plusieurs éléments constituent une expédition multi-colis explicite.
referenceest optionnel, mais doit être unique dans la requête.packages[].weightest obligatoire.packages[].weight.unitdoit êtreKG.packages[].dimensionsest optionnel. Lorsqu’il est présent,length,width,heightetunitsont tous obligatoires.unitdoit êtreCM.
La Gateway mappe le format A vers un colis d’entrepôt unique. Le format B est validé et mappé tel que déclaré. Le fractionnement final et les dimensions mesurées sont encore déterminés après le traitement en entrepôt.
Champs de requête partagés {#shared-fields}
Les deux formats peuvent inclure les éléments suivants.
destination
| Champ | Obligatoire | Description |
|---|---|---|
country_code | Oui | ISO 3166-1 alpha-2, deux lettres |
subdivision_code | Non | Par exemple US-CA. Le préfixe pays doit correspondre à country_code. |
region | Non | Nom d’affichage de la subdivision. Un subdivision_code valide a priorité. |
postal_code | Non | Chaîne. Conservez les zéros initiaux. |
declared_value
{
"amount": 5000,
"currency": "CNY"
}Valeur déclarée au niveau de l’expédition en fen CNY entiers. Omettez le champ lorsqu’elle est inconnue. N’envoyez pas 0 pour signifier « inconnu ».
attributes
Tableau de codes d’attributs d’article stables issus de GET /v1/fulfillment/shipments/item-attributes. Chaînes uniques, 100 max.
Les devis sont d’abord limités aux canaux applicables à destination.country_code ; les canaux des autres pays sont omis. Chaque canal restant évalue séparément les attributs déclarés. Un attribut non pris en charge produit UNAVAILABLE avec ATTRIBUTE_NOT_SUPPORTED, tandis que les autres canaux applicables peuvent toujours renvoyer un devis.
services
{
"services": {
"channel": [
{
"code": "LINE_INSURANCE",
"quantity": 1
}
],
"outbound": [
{
"code": "VACUUM_PACKING",
"quantity": 1
}
],
"inbound": [
{
"code": "PHOTO",
"quantity": 3
}
]
}
}| Groupe | Signification |
|---|---|
channel | Services à valeur ajoutée du canal. Les codes proviennent des canaux value_added_services[].code. |
outbound | Traitement sortant en entrepôt |
inbound | Traitement entrant en entrepôt |
Chaque élément exige code et quantity. OpenAPI : quantity est un entier de 1 à 999. Les codes doivent être uniques au sein de chaque groupe.
channel_codes
Codes de canal stables qui restreignent l’ensemble des devis. Omettez-les pour coter tous les canaux candidats. N’envoyez pas un tableau vide. Un code inconnu ou inaccessible renvoie 400 INVALID_SHIPPING_CHANNEL pour toute la requête.
Exemple de requête complète {#complete-request}
Format A avec destination, dimensions, valeur déclarée, attributs, services et un filtre de canal :
{
"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"
]
}Réponse {#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."
}Champs de premier niveau
| Champ | Description |
|---|---|
success | true pour une estimation réussie, y compris lorsque certains devis sont UNAVAILABLE. |
estimate_type | DECLARED — basé sur des données déclarées, pas sur une mesure d’entrepôt. |
completeness | Degré de complétude de l’entrée. Ce n’est pas une garantie de livrabilité. |
warnings | Avertissements au niveau de l’expédition. |
quotes | Résultats par canal : complets d’abord, puis partiels/revue, puis indisponibles. |
monetary_unit | Toujours CNY_minor. |
generated_at | Horodatage de la réponse. |
request_id | Corréler avec x-request-id. |
disclaimer | Clause de non-responsabilité lisible de l’estimation. |
completeness
| Champ | Signification |
|---|---|
level | Couverture globale de l’entrée, par exemple HIGH. |
destination | Degré de complétude de la destination (COMPLETE lorsque le pays est présent). |
package_dimensions | Indique si longueur/largeur/hauteur ont été fournies. |
package_split | DECLARED lorsque vous avez envoyé packages[] ; le raccourci suppose un colis unique. |
declared_value | PROVIDED ou omis/inconnu. |
attributes | Indique si les attributs d’article ont été déclarés. |
services | REQUESTED_ONLY lorsque vous avez envoyé des services sélectionnés ; l’entrepôt peut encore en ajouter. |
Statut du devis {#quote-status}
Ne décidez pas à partir de available seul. Lisez toujours quote_status.
quote_status | available | total | Signification |
|---|---|---|---|
COMPLETE | true | Objet monétaire | Budget complet que vous pouvez afficher. Toujours non verrouillé. |
PARTIAL | true | généralement null | Entrées manquantes. Lisez les avertissements et ajoutez dimensions, code postal ou valeur déclarée. |
REVIEW_REQUIRED | true | généralement null | Une mesure d’entrepôt ou une revue humaine est requise. |
UNAVAILABLE | false | null | Ce canal ne peut pas coter. La requête HTTP a tout de même réussi. |
totalest le budget complet lorsqu’il est connu.known_totalest la somme des frais calculables maintenant.- Lorsque
totalestnull, ne traitez pasknown_totalcomme un devis complet. unavailable_reason.codeest destiné au traitement programmatique.unavailable_reason.messageest uniquement destiné à l’affichage.
UNAVAILABLE sur un devis n’est pas une erreur HTTP.
Objet devis {#quotes}
| Champ | Description |
|---|---|
channel | { code, name, description, tags, capabilities } — même identité que le catalogue de canaux. |
channel.capabilities.delivery_methods | Tableau optionnel et rétrocompatible de codes de livraison stables : DOOR_DELIVERY, PICKUP, POST_OFFICE_PICKUP. Il peut être présent pour tout statut ; les clients existants peuvent l’ignorer. |
available | Indique si ce canal a produit une estimation utilisable. À coupler avec quote_status. |
quote_status | COMPLETE · PARTIAL · REVIEW_REQUIRED · UNAVAILABLE. |
unavailable_reason | { code, message } ou null. |
attribute_evaluation | Résultat facultatif par canal : SUPPORTED, UNSUPPORTED ou NOT_DECLARED, avec les attributs déclarés, acceptés et non pris en charge. |
matched_region | { code, name, match_type } ou null. |
packages | Colis déclarés ou mappés plus poids par colis. |
weights | actual / volumetric / chargeable au niveau de l’expédition, en KG. |
billing_quantity | Quantité réellement facturée par le canal, avec l’unité KG, M3 ou KG_PER_M3. |
pricing_selector | Comment cette quantité a atteint une tranche de grille (type, value, unit, scope). |
transit_time | Délai de transit de référence. |
charges | Groupes de frais. Voir ci-dessous. |
display_charges | Lignes optionnelles destinées uniquement à l’UI. Si included_in_total est false, ne les ajoutez pas à total. |
total / known_total | Budget complet vs frais actuellement connus. |
warnings | Avertissements au niveau du canal. |
service_adjustment_possible | true si le traitement en entrepôt peut encore modifier les services et les frais. |
Poids et quantité facturable {#weights}
actual— poids déclaré ou mesuré.volumetric— poids volumétrique.chargeable— poids utilisé pour le fret.billing_quantity— quantité facturée par le canal (peut être le poids, le volume ou la densité).pricing_selector— comment cette quantité a sélectionné une ligne tarifaire. Les types correspondent au catalogueWEIGHT/VOLUME/DENSITY.- Les canaux multi-colis peuvent arrondir par carton puis sommer. Lorsque
pricing_selector.scopeestPER_PACKAGE, lisez chaquepackages[].pricing_selector.
Frais {#charges}
| Groupe | Signification |
|---|---|
base_freight | Fret international de base |
channel_services | Services de canal obligatoires et sélectionnés par le développeur |
channel_rules | Règles de surcharge, surpoids, valeur déclarée et autres règles d’itinéraire |
outbound_services | Services à valeur ajoutée lors de la préparation / sortie de l’expédition |
inbound_services | Services à valeur ajoutée lors de la réception / entrée en entrepôt |
adjustments | Ajustements |
Services entrants et sortants
inbound_services et outbound_services correspondent à deux étapes distinctes des services à valeur ajoutée de l’entrepôt. Les services entrants sont exécutés à la réception, par exemple les photos du colis, l’enregistrement vidéo ou l’inspection. Les services sortants sont exécutés pendant la préparation de l’expédition, par exemple le renforcement, l’emballage sous vide ou l’emballage sur cadre/en caisse en bois. Les deux étapes peuvent légitimement s’appliquer et être facturées au même colis ou à la même expédition.
Les montants du devis ne sont que des estimations ; demander un devis ne crée pas de frais de service supplémentaires. Les frais définitifs dépendent des services réellement exécutés et de leur tarification et règlement finaux. Utilisez les deux groupes pour estimer le coût total, puis rapprochez chaque estimation des frais réels correspondants. N’ajoutez pas de nouveau l’estimation d’un service individuel à ses frais définitifs.
Exemple en unités mineures CNY : photos du colis 50 fen (¥0,50), inspection 100 fen (¥1,00), emballage sous vide 150 fen (¥1,50) et renforcement du colis 200 fen (¥2,00). Les quatre peuvent coexister car il s’agit de services différents exécutés à des étapes différentes.
Chaque groupe inclut généralement :
| Champ | Signification |
|---|---|
amount | Total du groupe en fen, ou null si inconnu |
currency | CNY |
known_amount | Somme des éléments calculables maintenant |
calculation_status | Par exemple CALCULATED |
items | Lignes de détail |
channel_rules peut aussi inclure aggregation et cap. Utilisez le sous-total du groupe — ne le remplacez pas en sommant les lignes de règles brutes.
SUM_ALL cumule tous les frais correspondants. HIGHEST_ONLY ne retient que le montant le plus élevé après tri décroissant ; les règles de même prix sont équivalentes. cap=null signifie sans plafond. reason est réservé à l’affichage. Pour la logique, utilisez condition_match, matched_conditions, rule_type, charge_mode, charge_value, outcome et missing_fields. Les règles PENDING_INPUT, REVIEW_REQUIRED et autres règles non calculées sont exclues du total connu. amount=null n’est pas zéro et un charge_value configuré n’est pas un frais réellement facturé.
Lignes de frais
| Champ | Signification |
|---|---|
code | Code de frais ou de service stable |
name | Nom d’affichage localisé |
category | Catégorie de frais |
source | MANDATORY · DEVELOPER_SELECTED · RULE_ENGINE |
pricing_basis | Comment la ligne a été tarifée |
quantity | Quantité facturable de la ligne |
unit_price | Prix unitaire en fen lorsqu’il est connu |
amount | Total de la ligne. null signifie inconnu, pas zéro. |
estimated | Indique si la ligne est encore une estimation |
calculation_status | État du calcul |
affected_by_packages | Indique si le nombre/la taille des colis peut modifier cette ligne |
included_in_total | Si false, ne l’ajoutez pas une seconde fois à total |
display_charges peut n’exister que pour la présentation frontend.
Motifs d’indisponibilité {#unavailable-reasons}
Valeurs courantes de 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_ERRORLes canaux indisponibles restent dans quotes[] afin que vous puissiez expliquer pourquoi ils ont été rejetés.
Terminologie du catalogue {#catalog-terminology}
| Canaux d’expédition | Cette API | Signification |
|---|---|---|
items[].code/name/description/tags | quotes[].channel.* | Même canal |
regions[].code/name/match_type | quotes[].matched_region.* | Région sélectionnée par le devis |
value_added_services[].code | services.channel[].code et code des frais | Code de service stable |
billing.quantity_unit | billing_quantity.unit / pricing_selector.unit | Unité de facturation |
rule_summary.aggregation | charges.channel_rules.aggregation | Agrégation des règles |
rule_summary.cap | charges.channel_rules.cap | Plafond après agrégation ; null signifie sans plafond |
Attributs d’article {#item-attributes}
GET /v1/fulfillment/shipments/item-attributes renvoie les codes attributes[] valides pour les devis.
Erreurs {#errors}
| HTTP | error.code | Quand |
|---|---|---|
| 400 | VALIDATION_ERROR | Structure invalide, formats de requête mixtes, unités KG/CM, codes dupliqués ou channel_codes vide |
| 400 | INVALID_SHIPPING_CHANNEL | Une valeur channel_codes demandée est inconnue ou non visible pour l’app |
| 401 | INVALID_API_KEY | Jeton Bearer manquant ou invalide |
| 403 | FULFILLMENT_MODE_NOT_SUPPORTED | L’app utilise le self fulfillment |
| 403 | WAREHOUSE_AUTH_INVALID | L’autorisation d’entrepôt est manquante, rejetée ou expirée |
| 422 | INVALID_COUNTRY_CODE | Le pays de destination est invalide |
| 422 | INVALID_ITEM_ATTRIBUTE | Un code d’attribut est invalide |
| 502 | WAREHOUSE_UPSTREAM_ERROR | Le service d’entrepôt a échoué ; réessayez avec backoff |
Il n’existe pas de code public distinct AUTHENTICATION_ERROR, WAREHOUSE_AUTH_REQUIRED ou WAREHOUSE_SERVICE_UNAVAILABLE. Utilisez 401 INVALID_API_KEY, 403 WAREHOUSE_AUTH_INVALID et 502 WAREHOUSE_UPSTREAM_ERROR.
Un canal qui ne peut pas transporter cette expédition est un devis UNAVAILABLE, pas un échec HTTP.
Voir aussi {#related}
- Canaux d’expédition — capacités, couverture et codes de service
- Expéditions — créer une expédition après l’entrée des colis
- Vue d’ensemble du fulfillment
Get Support
Need integration help? Contact Developer Support at support@hiobuy.com · Response within 1–2 business days