Skip to content

Products

Poussez votre catalogue produits vers Humind pour que l'assistant IA puisse recommander les bons items, ancrer ses réponses dans vos données et afficher des prix et disponibilités exacts.

Les endpoints ici couvrent create, read, update, replace, archive et batch sur les produits, y compris leurs variants et traductions embarquées.

L'objet Product

ChampTypeRequisDescription
external_idstringOui (à la création)Votre identifiant unique pour ce produit. Free-form, doit être unique par company. Utilisé comme clé d'upsert : reposter avec la même valeur met à jour le produit existant.
humind_idstringRenvoyé seulement24 caractères hex ObjectId qu'Humind assigne. Stable pendant toute la vie du produit.
titlestringOuiTitre d'affichage dans default_language.
descriptionstringNonDescription en texte brut.
description_htmlstringNonDescription HTML. Sanitizée côté serveur, voir HTML content.
handlestringNonSlug URL-safe, minuscule, séparé par tirets. Optionnel — quand absent, le serveur le dérive du title (ASCII en minuscule, les caractères non alphanumériques remplacés par des tirets). Pas obligé d'être unique dans le store ; les clés de lookup sont external_id / humind_id, pas le handle.
type'product' | 'kit'NonDéfaut product. Utilisez kit pour les articles qui regroupent plusieurs SKU vendus comme un ensemble (rare). Toute autre valeur est rejetée avec une erreur 400 validation_failed sur type.
status'active' | 'archived' | 'draft'NonDéfaut active. archived cache le produit à l'assistant. draft est pour stager les produits non publiés.
online_store_urlstringNonURL publique du produit sur votre storefront. L'assistant l'utilise pour deep-linker les acheteurs depuis le chat.
default_languagestringNonTag BCP 47 court (en, fr, pt-BR). Le sous-tag primaire de deux lettres est requis ; le sous-tag de région optionnel doit être en majuscules. Si omis, la langue principale de la company est utilisée. Les autres formes sont rejetées avec validation_failed.
available_for_salebooleanRenvoyé seulementCalculé automatiquement à partir des variants : true quand status vaut active ET qu'au moins un variant a available_for_sale: true. Toute valeur envoyée sur le produit lui-même est ignorée. Pour rendre un produit indisponible, mettez available_for_sale: false sur tous ses variants, ou archivez-le (status: archived).
brandobjectNonVoir Brand.
categoriesstring[]NonNoms de catégories free-form. Utilisé pour un soft-grouping ; n'a pas à correspondre aux collections Humind.
imagesobject[]NonVoir Image. La première image est la principale dans le chat.
variantsobject[]Oui (1–250)Voir Variant. Même les produits mono-SKU ont besoin d'un variant qui porte prix et currency. Les external_id de variants doivent être uniques au sein du tableau ; les doublons sont rejetés avec validation_failed.
translationsobjectNonMap de codes ISO 639-1 vers les overrides par locale. Voir Translations.
created_atISO 8601Renvoyé seulementTimestamp de création (UTC).
updated_atISO 8601Renvoyé seulementTimestamp de dernière modification (UTC).

Brand

ChampTypeRequisDescription
namestringOuiNom d'affichage de la marque.
domainstringNonDomaine web canonique de la marque (sans protocole). Utilisé pour la déduplication et le contexte assistant.

Image

ChampTypeRequisDescription
urlstringOuiURL HTTPS publiquement accessible. Humind récupère et cache l'image ; assurez-vous que l'URL est stable.
altstringNonTexte alt pour l'accessibilité et la compréhension de l'image par l'assistant.

Variant

ChampTypeRequisDescription
external_idstringOuiVotre identifiant unique de variant (par exemple SKU). Unique au sein du produit.
titlestringNonLabel du variant (par exemple "50 ml", "Black / Medium"). Optionnel — pour les produits mono-SKU vous pouvez l'omettre, le variant hérite alors du titre du produit. En pratique requis dès qu'un produit a plusieurs variants, sinon les acheteurs ne peuvent pas les distinguer.
skustringNonStock-keeping unit. À afficher aux acheteurs quand pertinent.
pricenumberOuiPrix de vente en décimal avec au plus 2 chiffres décimaux (par exemple 29.90). Doit être ≥ 0 et ≤ 1 000 000 000. Les valeurs comme 0.30000000000000004 (artefact de flottant JS de 0.1 + 0.2) sont rejetées avec validation_failed.
compare_at_pricenumberNonPrix « avant » barré pour les promotions. Même format que price. Doit être strictement supérieur à price si défini — compare_at_price <= price renvoie validation_failed.
currencystringOuiCode ISO 4217 (par exemple EUR, USD, GBP). Validé contre la liste ISO 4217 live — les codes inconnus sont rejetés avec validation_failed.
available_for_salebooleanNonDéfaut true.
inventory_quantityintegerNonStock. Omettez pour marquer comme non tracké.
regional_pricingobjectNonMap de codes pays ISO 3166-1 alpha-2 vers {currency, price, compare_at_price?} pour le pricing par région. Voir l'exemple ci-dessous.
cart_actionobjectNonCe qui se passe quand l'assistant propose un CTA « Add to cart » pour ce variant. Défaut { "type": "noop" } quand omis. Voir Cart action.

Cart action

cart_action est une union discriminée — choisissez le type qui correspond à votre storefront.

type: 'redirect' — envoie l'acheteur vers une URL

ChampTypeRequisDescription
type'redirect'OuiEnvoie l'acheteur vers url.
urlstringOuiL'URL vers laquelle envoyer l'acheteur (typiquement online_store_url avec un query param de variant, mais n'importe quoi de joignable marche).

type: 'noop' — affiche le variant sans CTA

ChampTypeRequisDescription
type'noop'OuiRemonte le variant dans le chat sans CTA actionnable (utile quand le checkout est gated, par exemple en B2B).

type: 'prestashop' — add-to-cart AJAX natif PrestaShop

Pour les boutiques PrestaShop 1.7+ / 8, poussez les id_product et id_product_attribute natifs pour que le widget puisse POST directement sur votre endpoint /cart en same-origin (pas de CORS, pas de nouvel onglet, mise à jour inline du cart drawer natif).

ChampTypeRequisDescription
type'prestashop'OuiAdd-to-cart natif PrestaShop.
id_productintegerOuiL'id_product PrestaShop.
id_product_attributeintegerOuiL'id_product_attribute PrestaShop pour le variant. Utilisez 0 pour les produits sans combinations.
product_urlstringOuiL'URL de la page produit. Utilisé comme fallback de redirection quand window.prestashop n'est pas disponible sur la page du visiteur.

Auto-dérivation

Si votre company est configurée avec catalogIntegrationType: prestashop, vous pouvez omettre cart_action complètement sur chaque variant — l'API auto-dérive l'action prestashop depuis vos champs external_id (produit) et external_id (variant). Poussez-le explicitement uniquement quand vous voulez override la dérivation pour des variants spécifiques.

Pourquoi PrestaShop est autorisé et pas Shopify/WooCommerce

Les id_product et id_product_attribute PrestaShop sont publics — visibles dans le markup HTML, les URLs et les data attributes. Les pousser via l'API ne leak aucun secret. À l'inverse, les GIDs Shopify et les variation IDs WooCommerce sont privés à la plateforme et ne sont jamais set que par nos adaptateurs internes, jamais acceptés sur la surface publique.

Translations

translations est une map de codes de langue vers des overrides de champs par locale :

json
{
  "default_language": "fr",
  "title": "Crème hydratante",
  "description": "Une crème légère pour le visage.",
  "handle": "creme-hydratante",
  "translations": {
    "en": {
      "title": "Hydrating cream",
      "description": "A lightweight face cream.",
      "handle": "hydrating-cream"
    }
  }
}

Champs par locale que vous pouvez override :

ChampType
titlestring
descriptionstring
description_htmlstring
handlestring
online_store_urlstring
ingredientsstring[]

Les clés non présentes dans translations retombent sur la valeur top-level (en default_language).

Vous pouvez aussi patcher une locale à la fois sans renvoyer le produit complet via la sub-resource Translations dédiée.

HTML content

Plusieurs champs acceptent du HTML, notamment description_html, plus content_html sur les traductions. Humind sanitize le HTML côté serveur avant de le stocker. Le sanitizer applique une allowlist fixe :

  • Tags préservés : p, a, br, hr, em, strong, b, i, u, ul, ol, li, h1h6, blockquote, pre, code, table, thead, tbody, tr, th, td, img, span, div.
  • Tags strippés : script, iframe, style, object, embed, form, input, et tout autre tag non listé ci-dessus.
  • Attributs strippés : event handlers (onclick, onerror, …), style, et toute URL javascript:.
  • Attributs préservés : href sur <a> (uniquement https, http, mailto et URIs data: valides), src, alt, width, height sur <img>, plus un set limité de valeurs class.

Le HTML est sanitizé en entrée

Ne comptez pas sur l'API pour préserver votre HTML brut. Les tags comme <script> ou les attributs comme onclick sont strippés silencieusement, votre markup stocké peut être un sous-ensemble strict de ce que vous avez envoyé. Relisez la ressource après une écriture si vous voulez voir ce qui a été retenu.


Create or upsert

POST /products crée un nouveau produit, ou met à jour un existant si l'external_id existe déjà pour votre company.

Scope requis : catalog:write

Request

bash
curl -X POST https://api.thehumind.com/public/v1/products \
  -H "Authorization: Bearer hmd_live_..." \
  -H "Idempotency-Key: 3f1a8d92-7c4b-4e6f-b2a1-d5e9c8f7a3b4" \
  -H "Content-Type: application/json" \
  -d '{
    "external_id": "SKU-123",
    "title": "Crème hydratante",
    "handle": "creme-hydratante",
    "description": "Une crème légère pour le visage.",
    "status": "active",
    "default_language": "fr",
    "online_store_url": "https://example.com/products/creme-hydratante",
    "brand": { "name": "Acme Skincare", "domain": "acme-skincare.com" },
    "categories": ["Soin", "Hydratation"],
    "images": [
      { "url": "https://cdn.example.com/creme.jpg", "alt": "Crème hydratante 50ml" }
    ],
    "variants": [
      {
        "external_id": "SKU-123-50ML",
        "title": "50 ml",
        "sku": "SKU-123-50ML",
        "price": 29.90,
        "compare_at_price": 34.90,
        "currency": "EUR",
        "available_for_sale": true,
        "inventory_quantity": 42,
        "regional_pricing": {
          "US": { "currency": "USD", "price": 32.00 }
        },
        "cart_action": {
          "type": "redirect",
          "url": "https://example.com/products/creme-hydratante?variant=50ml"
        }
      }
    ],
    "translations": {
      "en": {
        "title": "Hydrating cream",
        "description": "A lightweight face cream.",
        "handle": "hydrating-cream"
      }
    }
  }'

Response 201 Created (nouveau produit) ou 200 OK (produit existant mis à jour)

json
{
  "external_id": "SKU-123",
  "humind_id": "65f1ab9c8e7d4a2b1c3d4e5f",
  "title": "Crème hydratante",
  "handle": "creme-hydratante",
  "description": "Une crème légère pour le visage.",
  "status": "active",
  "default_language": "fr",
  "online_store_url": "https://example.com/products/creme-hydratante",
  "available_for_sale": true,
  "brand": { "name": "Acme Skincare", "domain": "acme-skincare.com" },
  "categories": ["Soin", "Hydratation"],
  "images": [
    { "url": "https://cdn.example.com/creme.jpg", "alt": "Crème hydratante 50ml" }
  ],
  "variants": [
    {
      "external_id": "SKU-123-50ML",
      "title": "50 ml",
      "sku": "SKU-123-50ML",
      "price": 29.90,
      "compare_at_price": 34.90,
      "currency": "EUR",
      "available_for_sale": true,
      "inventory_quantity": 42,
      "regional_pricing": {
        "US": { "currency": "USD", "price": 32.00 }
      },
      "cart_action": {
        "type": "redirect",
        "url": "https://example.com/products/creme-hydratante?variant=50ml"
      }
    }
  ],
  "translations": {
    "en": {
      "title": "Hydrating cream",
      "description": "A lightweight face cream.",
      "handle": "hydrating-cream"
    }
  },
  "created_at": "2026-04-25T14:30:00Z",
  "updated_at": "2026-04-25T14:30:00Z"
}

200 vs 201

Un 201 Created veut dire que c'est un nouveau produit (première fois que l'API voit cet external_id). Un 200 OK veut dire que le produit existait déjà et a été mis à jour en place. Les deux sont des succès.


List products

GET /products renvoie les produits qui appartiennent à la company à laquelle la clé API est rattachée.

Scope requis : catalog:read

Query parameterTypeDescription
cursorstringCursor opaque renvoyé comme next_cursor à la page précédente. Omettez-le au premier appel.
limitintegerItems par page (1100). Défaut 50.
handlestringFiltre sur un seul produit par match exact de handle.
status'active' | 'draft' | 'archived'Filtre par status. Les produits soft-deleted vivent sous archived.

Pagination par cursor

Les endpoints de liste renvoient jusqu'à limit items plus un next_cursor que vous pouvez passer pour récupérer la page suivante. Quand next_cursor est null, vous êtes à la fin. Le cursor est opaque — ne le parsez pas, le format peut changer dans une version future.

Request

bash
curl https://api.thehumind.com/public/v1/products \
  -H "Authorization: Bearer hmd_live_..."

Pour filtrer par handle :

bash
curl "https://api.thehumind.com/public/v1/products?handle=creme-hydratante" \
  -H "Authorization: Bearer hmd_live_..."

Response 200 OK

json
{
  "data": [
    {
      "external_id": "SKU-123",
      "humind_id": "65f1ab9c8e7d4a2b1c3d4e5f",
      "title": "Crème hydratante",
      "handle": "creme-hydratante",
      "status": "active",
      "default_language": "fr",
      "variants": [
        {
          "external_id": "SKU-123-50ML",
          "title": "50 ml",
          "price": 29.90,
          "currency": "EUR"
        }
      ],
      "created_at": "2026-04-25T14:30:00Z",
      "updated_at": "2026-04-25T14:30:00Z"
    }
  ]
}

Retrieve a product

GET /products/{id} renvoie un seul produit. Le {id} accepte l'une ou l'autre forme documentée dans Identifiants.

Scope requis : catalog:read

Request, par external_id

bash
curl https://api.thehumind.com/public/v1/products/api:SKU-123 \
  -H "Authorization: Bearer hmd_live_..."

Request, par humind_id

bash
curl https://api.thehumind.com/public/v1/products/65f1ab9c8e7d4a2b1c3d4e5f \
  -H "Authorization: Bearer hmd_live_..."

Response 200 OK

Même forme que la réponse de création.


Replace a product

PUT /products/{id} fait un remplacement complet : le body de la requête devient le produit entier. Les champs que vous n'incluez pas sont reset à leurs défauts (ou unset là où c'est applicable).

À utiliser quand vous avez une représentation complète du produit de votre côté et voulez la mirorrer exactement. Pour des updates partiels, utilisez plutôt PATCH.

Scope requis : catalog:write

Request

bash
curl -X PUT https://api.thehumind.com/public/v1/products/api:SKU-123 \
  -H "Authorization: Bearer hmd_live_..." \
  -H "Idempotency-Key: 7a2b3c4d-5e6f-4a8b-9c0d-1e2f3a4b5c6d" \
  -H "Content-Type: application/json" \
  -d '{
    "external_id": "SKU-123",
    "title": "Crème hydratante (édition limitée)",
    "handle": "creme-hydratante",
    "status": "active",
    "default_language": "fr",
    "variants": [
      { "external_id": "SKU-123-50ML", "title": "50 ml", "price": 32.00, "currency": "EUR" }
    ]
  }'

Response 200 OK

Renvoie l'objet produit complet, même forme que la réponse de création.

Replace est destructif

PUT enlève tout champ, variant, image ou traduction non présent dans le body. Si vous voulez juste bumper le prix d'un variant, utilisez plutôt PATCH.


Update a product

PATCH /products/{id} fait un update partiel : seuls les champs présents dans le body sont modifiés. Le reste reste comme avant.

Scope requis : catalog:write

Request, bumper le prix d'un seul variant

bash
curl -X PATCH https://api.thehumind.com/public/v1/products/api:SKU-123 \
  -H "Authorization: Bearer hmd_live_..." \
  -H "Idempotency-Key: 9b8a7c6d-5e4f-4a3b-2c1d-0e9f8a7b6c5d" \
  -H "Content-Type: application/json" \
  -d '{
    "variants": [
      { "external_id": "SKU-123-50ML", "price": 32.00 }
    ]
  }'

Quand vous envoyez un array variants en PATCH, chaque entrée est matchée sur external_id et mergée avec le variant existant du même external ID. Les variants que vous ne listez pas sont laissés intouchés. Pour supprimer un variant, utilisez PUT (full replace) sans ce variant dans l'array.

Response 200 OK

Renvoie l'objet produit complet mis à jour.


Archiver (ou supprimer) un produit

DELETE /products/{id} fait un soft delete par défaut : le status du produit passe à archived, available_for_sale bascule à false, et l'assistant arrête de proposer le produit. Le record reste en base, donc vous pouvez le restaurer plus tard en PATCH-ant le statut à active.

Passez ?force=true pour faire un hard delete : le document est supprimé physiquement de la base après la cascade d'archivage. Il n'y a pas d'un-delete ; à n'utiliser que quand le SKU doit vraiment disparaître (ex. nettoyage d'un catalogue de test, SKU créé par erreur).

Scope requis : catalog:write

Query parameters

NomTypeRequisDescription
forcebooleanNonValeurs truthy (insensibles à la casse) : true, 1, yes, on. Valeurs falsy : false, 0, no, off, ou omis. Toute autre valeur renvoie 400 validation_failed. Quand truthy, supprime définitivement le produit. Défaut soft delete.

Request — soft delete (par défaut)

bash
curl -X DELETE https://api.thehumind.com/public/v1/products/api:SKU-123 \
  -H "Authorization: Bearer hmd_live_..." \
  -H "Idempotency-Key: 1a2b3c4d-5e6f-4789-9abc-def012345678"

Request — hard delete

bash
curl -X DELETE 'https://api.thehumind.com/public/v1/products/api:SKU-123?force=true' \
  -H "Authorization: Bearer hmd_live_..." \
  -H "Idempotency-Key: 1a2b3c4d-5e6f-4789-9abc-def012345678"

Response 204 No Content

Pas de body.

Soft vs. hard delete

Le soft delete est recommandé pour les opérations marchandes normales : les conversations qui référençaient le produit restent cohérentes, vous pouvez désarchiver en un PATCH, et les caches downstream (vector index, dashboards) se nettoient via la cascade d'archivage.

Le hard delete (?force=true) sert au nettoyage de catalogue — typiquement des produits de test qu'on veut totalement enlevés. Le soft delete déclenche d'abord la routine d'archivage ; ?force=true supprime ensuite définitivement la ressource. Les collections qui référençaient le produit sautent simplement la référence absente ; on ne cascade pas plus loin.


Batch upsert

POST /products/batch accepte jusqu'à 500 produits dans un seul appel et renvoie une réponse 207 Multi-Status avec une entrée par item. À utiliser pour le backfill initial d'un catalogue ou n'importe quelle mise à jour bulk, c'est largement plus rapide que 500 POST séquentiels.

Scope requis : catalog:write

ContrainteValeur
Max items par batch500
Max taille body5 MB
ComportementChaque item est traité indépendamment ; un échec ne bloque pas les autres.

Request

bash
curl -X POST https://api.thehumind.com/public/v1/products/batch \
  -H "Authorization: Bearer hmd_live_..." \
  -H "Idempotency-Key: 4d3c2b1a-9f8e-4d7c-6b5a-4f3e2d1c0b9a" \
  -H "Content-Type: application/json" \
  -d '{
    "items": [
      {
        "external_id": "SKU-123",
        "title": "Crème hydratante",
        "handle": "creme-hydratante",
        "default_language": "fr",
        "variants": [
          { "external_id": "SKU-123-50ML", "title": "50 ml", "price": 29.90, "currency": "EUR" }
        ]
      },
      {
        "external_id": "SKU-456",
        "title": "Sérum éclat",
        "handle": "serum-eclat",
        "default_language": "fr",
        "variants": [
          { "external_id": "SKU-456-30ML", "title": "30 ml", "price": 49.00, "currency": "EUR" }
        ]
      },
      {
        "external_id": "SKU-789",
        "title": "Bad data",
        "default_language": "fr"
      }
    ]
  }'

Response 207 Multi-Status

json
{
  "results": [
    {
      "external_id": "SKU-123",
      "status": "created",
      "humind_id": "65f1ab9c8e7d4a2b1c3d4e5f"
    },
    {
      "external_id": "SKU-456",
      "status": "updated",
      "humind_id": "65f1cd9e8e7d4a2b1c3d4e60"
    },
    {
      "external_id": "SKU-789",
      "status": "failed",
      "error": {
        "code": "validation_failed",
        "message": "Invalid product payload.",
        "details": {
          "issues": [
            { "path": ["handle"], "message": "Required", "code": "invalid_type" }
          ]
        }
      }
    }
  ]
}
ChampTypeDescription
results[i].external_idstringL'external_id de l'item d'entrée, écho pour matching.
results[i].statusstringUne valeur parmi created, updated, failed.
results[i].humind_idstringPrésent en cas de succès, l'id Humind 24-hex assigné.
results[i].errorobjectPrésent en cas d'échec. Même forme qu'un objet d'erreur top-level.

Doublons d'external_id au sein d'un batch

Si le même external_id apparaît plusieurs fois dans items, la première occurrence est traitée et les doublons suivants reviennent avec status: "failed" et le code duplicate_external_id_in_batch. Dédupliquez côté client avant l'envoi.

Wrapper ou tableau bare

Le body peut être un tableau JSON comme montré ci-dessus, ou wrappé : { "items": [ ... ] }. L'API normalise les deux vers la même réponse results.

Idempotency sur les batches

L'Idempotency-Key s'applique au batch entier. Un retry du même batch avec la même clé rejoue toute la réponse 207 : aucun item n'est traité deux fois. Générez un nouveau UUID pour un autre batch.


Translations sub-resource

Pour les produits qui existent déjà, vous pouvez patcher une seule locale sans renvoyer le payload complet. Utilisez le champ translations embarqué sur POST / PUT / PATCH pour le seed initial, puis pilotez les updates suivants via ces endpoints.

{lang} est un tag court BCP 47, en, fr, de, pt-BR, zh-CN, etc. La regex de validation est ^[a-z]{2}(-[A-Z]{2})?$. Une valeur invalide renvoie 422 avec code: invalid_lang_format.

Set or update a translation

PUT /products/{id}/translations/{lang} upserte la traduction pour une seule locale. Les champs que vous omettez sont laissés intouchés sur un update ; à la première écriture, ils défaulent à unset.

Scope requis : catalog:write

ChampTypeDescription
titlestringTitre d'affichage localisé.
descriptionstringDescription texte brut localisée.
description_htmlstringDescription HTML localisée. Sanitizée, voir HTML content.
handlestringSlug URL-safe localisé.
online_store_urlstringURL publique localisée sur votre storefront.
ingredientsstring[]Liste d'ingrédients localisée.

Tous les champs sont optionnels individuellement, mais le body doit contenir au moins un. Un body vide renvoie 400 validation_failed.

Request

bash
curl -X PUT https://api.thehumind.com/public/v1/products/api:SKU-123/translations/en \
  -H "Authorization: Bearer hmd_live_..." \
  -H "Idempotency-Key: 5f6a7b8c-9d0e-4f1a-2b3c-4d5e6f7a8b9c" \
  -H "Content-Type: application/json" \
  -d '{
    "title": "Hydrating cream",
    "description": "A lightweight face cream.",
    "handle": "hydrating-cream",
    "online_store_url": "https://example.com/en/products/hydrating-cream"
  }'

Response 200 OK

Renvoie l'objet produit complet, même forme que la réponse de création, pour que vous voyiez toutes les locales actuellement stockées, pas juste celle que vous avez écrite.

Remove a translation

DELETE /products/{id}/translations/{lang} enlève la traduction pour une seule locale. Idempotent : supprimer une locale qui n'existe pas est un no-op, pas une erreur.

Scope requis : catalog:write

Request

bash
curl -X DELETE https://api.thehumind.com/public/v1/products/api:SKU-123/translations/en \
  -H "Authorization: Bearer hmd_live_..." \
  -H "Idempotency-Key: 6a7b8c9d-0e1f-4a2b-3c4d-5e6f7a8b9c0d"

Response 204 No Content

Pas de body.


Variants sub-resource

Pour les produits qui existent déjà, vous pouvez gérer un seul variant sans renvoyer le produit complet. Le variant est identifié par son external_id dans le path de l'URL.

{variant_external_id} est le même identifiant que celui que vous mettez sur le champ external_id du variant, typiquement votre SKU.

Set or update a variant

PUT /products/{id}/variants/{variant_external_id} upserte un seul variant. Le body match le schéma Variant, sans external_id : cette valeur est prise depuis l'URL.

Scope requis : catalog:write

Request

bash
curl -X PUT https://api.thehumind.com/public/v1/products/api:SKU-123/variants/SKU-123-50ML \
  -H "Authorization: Bearer hmd_live_..." \
  -H "Idempotency-Key: 7b8c9d0e-1f2a-4b3c-4d5e-6f7a8b9c0d1e" \
  -H "Content-Type: application/json" \
  -d '{
    "title": "50 ml",
    "sku": "SKU-123-50ML",
    "price": 29.90,
    "compare_at_price": 34.90,
    "currency": "EUR",
    "available_for_sale": true,
    "inventory_quantity": 42
  }'

Response 200 OK

Renvoie l'objet produit complet pour que vous voyiez le variant mis à jour à côté du reste du produit.

Remove a variant

DELETE /products/{id}/variants/{variant_external_id} enlève un seul variant du produit. Idempotent : supprimer un variant qui n'existe pas est un no-op, pas une erreur.

Scope requis : catalog:write

Un produit a besoin d'au moins un variant

Vous ne pouvez pas enlever le dernier variant d'un produit, ça le laisserait sans prix ni currency. Pour retirer un produit complètement, archivez-le plutôt.

Request

bash
curl -X DELETE https://api.thehumind.com/public/v1/products/api:SKU-123/variants/SKU-123-50ML \
  -H "Authorization: Bearer hmd_live_..." \
  -H "Idempotency-Key: 8c9d0e1f-2a3b-4c4d-5e6f-7a8b9c0d1e2f"

Response 204 No Content

Pas de body.


Erreurs courantes

Les endpoints products peuvent renvoyer n'importe lequel des statuts HTTP standards, mais voici ceux que vous verrez le plus souvent :

StatutCodeQuandFix
401missing_credentials, invalid_key_format, invalid_key, revokedLe header d'auth manque, est malformé, ou la clé n'est plus active.Voir Authentication.
403insufficient_scopeLa clé n'a pas catalog:read (pour GET) ou catalog:write (pour POST/PUT/PATCH/DELETE).Créez une nouvelle clé avec le bon scope.
404not_foundLe {id} ne correspond pas à un produit qui appartient à votre company.Vérifiez l'external_id ou le humind_id. Les lookups cross-tenant renvoient aussi 404.
404variant_not_foundLe {variant_external_id} sur un appel à la sub-resource variants ne correspond à aucun variant de ce produit.Vérifiez l'external_id du variant. Le DELETE est idempotent, voir les notes là-bas avant de retenter.
409idempotency_conflictMême Idempotency-Key réutilisée avec un body différent.Générez un UUID frais.
400validation_failedLe body a échoué le schéma Product. details pointe sur le mauvais champ.Corrigez le champ et renvoyez.
422invalid_lang_formatLe segment {lang} d'une URL de sub-resource translations ne match pas ^[a-z]{2}(-[A-Z]{2})?$.Utilisez un tag court BCP 47 comme en, fr, pt-BR.

Pour aller plus loin

Released under the proprietary Humind license.