API achats manuels

Un canal, un vendeur, une commande d’achat

Une commande d’achat peut contenir plusieurs produits ou SKU, mais tous les articles doivent appartenir au même canal et au même vendeur.

Si votre client achète des articles auprès de vendeurs ou de canaux différents, votre application doit les répartir en commandes d’achat distinctes avant d’appeler l’API de commande HIOBuy.

HIOBuy ne scinde pas automatiquement les commandes d’achat et ne propose pas d’API de commande par lots pour ce parcours.

Identifier le canal et le vendeur

  • Utilisez le champ channel de la commande. Le canal du raccourci, du corps de requête et des lignes doit être identique. Ne mélangez pas les canaux dans lines[] ou items[].
  • Pour regrouper les articles côté client, utilisez le véritable seller.id de l’API Produits lorsqu’il est disponible : il provient de sellerOpenId pour 1688 et de shop_id pour les détails Taobao. Une valeur de repli générée seller_1688_* / seller_taobao_*, un ID absent, un titre de produit ou un nom de boutique ne prouvent pas l’identité du vendeur. Les ID de boutique Taobao et les ID de vendeur du rendu appartiennent à des espaces d’identifiants différents et ne doivent pas être comparés.
  • Aucun nouveau champ vendeur obligatoire n’est ajouté à la requête standard. En mode self, la passerelle vérifie l’appartenance des produits 1688 à partir des détails d’origine ; pour Taobao, elle utilise render_item_list[].seller_id et vérifie la couverture de tous les produits et SKU demandés avant la création officielle. Une preuve absente ou ambiguë entraîne un refus.
  • En mode achat Warehouse, y compris les achats manuels, l’entrepôt doit vérifier le vendeur avant toute création de commande, tout achat, tout débit du portefeuille ou toute réussite partielle. La passerelle contrôle les conflits de canal de la requête d’origine et transmet les erreurs de l’entrepôt sans refaire les recherches sur les plateformes. Une recette de l’entrepôt est nécessaire ; le déploiement de la passerelle ne certifie pas cette vérification chez un entrepôt externe.
  • Les achats manuels utilisent channel=manual et tous les articles doivent également partager le même source_platform. seller_name est uniquement une déclaration d’affichage. L’entrepôt doit vérifier le véritable vendeur de chaque produit sur la plateforme ou renvoyer SELLER_ID_UNAVAILABLE. Un nom ou un ID déclaré par l’appelant ne remplace pas cette vérification. N’activez pas la création manuelle avant la recette du contrat de l’entrepôt.

Erreurs et mesures correctives

Ces trois erreurs utilisent HTTP 400 et la catégorie VALIDATION_ERROR :

CodeMesure corrective
MULTIPLE_CHANNELS_NOT_ALLOWEDSéparez les articles par canal et alignez les canaux du raccourci, du corps et des lignes.
MULTIPLE_SELLERS_NOT_ALLOWEDDans chaque canal, séparez les articles selon leur véritable vendeur et créez les commandes séparément.
SELLER_ID_UNAVAILABLEObtenez des identifiants de produit/SKU valides ou un mécanisme fiable de résolution du vendeur par l’entrepôt. Ne relancez pas une requête inchangée et ne déduisez pas l’identité d’un nom.

Texte anglais exact renvoyé par l’API en cas de commande mixte :

A purchase order must contain products from the same channel and seller. Please split the items into separate orders by channel and seller.

Un refus lié au vendeur ne doit créer aucune commande d’achat ni tâche d’approvisionnement, débiter aucun portefeuille ni produire de réussite partielle. Les règles d’idempotence existantes restent applicables. Chaque achat volontairement séparé doit avoir sa propre référence métier/clé ; réutilisez la clé d’origine pour relancer un achat inchangé.

Achats et expédition groupée

Les commandes d’achat correspondent à des achats nationaux auprès de vendeurs individuels. Les articles de commandes distinctes peuvent être réceptionnés comme colis séparés puis regroupés dans une expédition internationale, sous réserve des conditions de l’entrepôt et du transport. Ce regroupement ne fusionne ni les numéros d’achat d’origine, ni les frais nationaux, ni les états de paiement, d’annulation ou de remboursement.

Requête valide : plusieurs SKU d’un vendeur vérifié

L’entrepôt doit établir indépendamment que les deux URL produit appartiennent à un seul vendeur stable de la plateforme. Les URL d’exemple sont illustratives et ne constituent ni une preuve d’identité ni une recette de production.

{
  "channel": "manual",
  "external_order_id": "MANUAL-SELLER-A-001",
  "source_platform": "jd",
  "seller_name": "Seller A",
  "domestic_shipping_fee": 800,
  "currency": "CNY",
  "monetary_unit": "CNY_minor",
  "items": [
    {
      "product_url": "https://example.com/seller-A/shoe",
      "product_name": "Shoes",
      "specification": "Size 40",
      "unit_price": 5000,
      "quantity": 1
    },
    {
      "product_url": "https://example.com/seller-A/shoe",
      "product_name": "Shoes",
      "specification": "Size 41",
      "unit_price": 5000,
      "quantity": 1
    }
  ]
}

Exemple invalide : les propriétaires réels diffèrent

Si items[0].product_url appartient au vendeur A et items[1].product_url au vendeur B, l’entrepôt doit renvoyer MULTIPLE_SELLERS_NOT_ALLOWED, même si la requête déclare seller_name: "Seller A". Si l’appartenance ne peut pas être vérifiée, renvoyez SELLER_ID_UNAVAILABLE au lieu d’accepter le nom déclaré.

{
  "channel": "manual",
  "external_order_id": "INVALID-MIXED-001",
  "source_platform": "jd",
  "seller_name": "Seller A",
  "domestic_shipping_fee": 800,
  "currency": "CNY",
  "monetary_unit": "CNY_minor",
  "items": [
    {
      "product_url": "https://example.com/seller-A/shoe",
      "product_name": "Shoes",
      "specification": "Size 40",
      "unit_price": 5000,
      "quantity": 1
    },
    {
      "product_url": "https://example.com/seller-B/shirt",
      "product_name": "Shirt",
      "specification": "M",
      "unit_price": 3000,
      "quantity": 1
    }
  ]
}

Le refus vendeur de l’entrepôt doit être rejoué selon le contrat existant de référence métier/idempotence, sans création de commande ni débit. Les commandes déjà créées conservent leurs comportements de rejeu, consultation, paiement et annulation.

POST /v1/orders/manual

Une requête crée une commande pour une plateforme et un vendeur, avec plusieurs articles de ce vendeur. Seuls jd, pinduoduo et poizon sont ouverts ; seller_name est obligatoire. Séparez les autres vendeurs ou plateformes avec des numéros distincts.

Production API Key, droit order:create, mode warehouse et liaison active au dépôt sont requis. Aucun OAuth de marketplace. Sandbox indisponible. Le dépôt doit implémenter et vérifier son API manuelle avant utilisation.

Requête

Authorization: Bearer <PRODUCTION_API_KEY>
Content-Type: application/json
Idempotency-Key: 6c14ce20-cf29-4c25-a9ee-3d36aac94c16
{
  "channel": "manual",
  "external_order_id": "EXT-10001",
  "source_platform": "jd",
  "seller_name": "Seller A",
  "domestic_shipping_fee": 800,
  "currency": "CNY",
  "monetary_unit": "CNY_minor",
  "language": "fr",
  "remark": "Please ship together",
  "items": [
    {
      "item_ref": "I001",
      "product_url": "https://example.com/item1",
      "product_name": "Wireless Mouse",
      "specification": "Black",
      "unit_price": 3500,
      "quantity": 2,
      "product_image": null,
      "remark": ""
    }
  ]
}

external_order_id est obligatoire et unique pour les commandes manuelles de l’application. Même numéro et mêmes données : commande existante ; données modifiées : HTTP 409 IDEMPOTENCY_CONFLICT. Nouvel achat : nouveau numéro. Idempotency-Key est obligatoire pour créer, payer et annuler. HIOBuy génère order_sn ; item_ref est facultatif. Les tableaux sellers et les vendeurs définis par article sont refusés.

ChampValeur requise ou limite
channelmanual
external_order_id1–200
source_platformjd / pinduoduo / poizon
seller_name1–200
currency / monetary_unitCNY / CNY_minor
domestic_shipping_fee / items[].unit_priceinteger ≥ 0
items / items[].quantity1–100 / 1–9999

Montants du dépôt

Les montants sont des entiers en fen CNY : 3500 = CNY 35.00. Le dépôt calcule les articles, le port intérieur, les frais existants de 5 % et le total. L’exemple ne définit ni base, ni minimum, ni arrondi. HIOBuy enregistre les montants sans ajouter 5 %. Des montants ou associations incomplets bloquent le paiement.

{
  "channel": "manual",
  "success": true,
  "order_id": "WH10001",
  "order_sn": "HB202610160001",
  "external_order_id": "EXT-10001",
  "source_platform": "jd",
  "seller_name": "Seller A",
  "status": "wait_payment",
  "currency": "CNY",
  "monetary_unit": "CNY_minor",
  "total": {
    "merchandise": {
      "amount": 7000,
      "currency": "CNY"
    },
    "shipping": {
      "amount": 800,
      "currency": "CNY"
    },
    "procurement_fee": {
      "amount": 390,
      "currency": "CNY"
    },
    "payment": {
      "amount": 8190,
      "currency": "CNY"
    }
  },
  "order_list": [
    {
      "order_id": "WH10001",
      "shipping": {
        "amount": 800,
        "currency": "CNY"
      },
      "lines": [
        {
          "item_ref": "I001",
          "sub_order_id": "WI10001",
          "title": "Wireless Mouse",
          "spec_title": "Black",
          "quantity": 2,
          "unit_price": {
            "amount": 3500,
            "currency": "CNY"
          },
          "line_total": {
            "amount": 7000,
            "currency": "CNY"
          }
        }
      ]
    }
  ],
  "failed_offers": [],
  "request_id": "req_example"
}

Opérations existantes

La création ne débite pas le portefeuille et ne lance pas les achats. Utilisez order_id et channel=manual avec les API existantes de paiement, annulation, détail et suivi intérieur. Ne transmettez pas pay_amount. Après comparaison des montants enregistrés, le dépôt effectue le paiement existant puis lance l’achat après confirmation. Annuler ne signifie pas être remboursé.

{
  "channel": "manual",
  "order_id": "WH10001"
}
{
  "channel": "manual",
  "order_id": "WH10001",
  "cancel_reason": "buyer_request"
}

Relances et limites

Après un délai dépassé ou un résultat inconnu, conservez le numéro et la clé puis consultez les détails. Ne changez pas automatiquement de clé pour repayer. Le détail inclut payment_status, références et frais. Les listes et remboursements des marketplaces ne prennent pas en charge manual. Limites : 1–100 lignes, quantité 1–9999, vendeur 200 caractères, nom et spécification 500, remarques 1000, URL HTTP/HTTPS 2048. Les montants textuels ou décimaux sont refusés.

400 VALIDATION_ERROR · 403 FULFILLMENT_MODE_NOT_SUPPORTED / WAREHOUSE_AUTH_INVALID · 409 IDEMPOTENCY_CONFLICT / ORDER_AMOUNT_CHANGED / ORDER_OPERATION_UNRESOLVED · 502 WAREHOUSE_INVALID_RESPONSE · 503 WAREHOUSE_UNAVAILABLE

Webhooks

procurement.failed / procurement.out_of_stock

{
  "type": "procurement.failed",
  "data": {
    "channel": "manual",
    "order_id": "WH10001",
    "order_sn": "HB202610160001",
    "external_order_id": "EXT-10001",
    "source_platform": "jd",
    "seller_name": "Seller A",
    "status": "partial_failure",
    "reason_code": "OUT_OF_STOCK",
    "items": [
      {
        "item_ref": "I001",
        "sub_order_id": "WI10001",
        "quantity": 1,
        "reason_code": "OUT_OF_STOCK"
      }
    ]
  }
}

Get Support

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

Email support