Skip to content

Collections

Les collections sont des groupes nommés de produits. L'assistant IA les utilise pour affiner ses recommandations à un sous-ensemble de votre catalogue, « montre-moi les bestsellers », « qu'est-ce qui est dans la collection été 2026 », « quelque chose dans le gift guide ». Poussez votre structure de merchandising une fois et l'assistant la respectera partout où il fait remonter des produits.

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

L'objet Collection

ChampTypeRequisDescription
external_idstringOui (à la création)Votre identifiant unique pour cette collection. Free-form, doit être unique par company. Utilisé comme clé d'upsert : reposter avec la même valeur met à jour la collection existante.
humind_idstringRenvoyé seulement24 caractères hex ObjectId qu'Humind assigne. Stable pendant toute la vie de la collection.
titlestringOuiTitre d'affichage dans default_language.
handlestringNonSlug URL-safe, minuscule, séparé par tirets. Unique par company quand défini — assigner un handle qui appartient déjà à une autre collection (matched sur un autre external_id) renvoie 409 handle_already_used. Les upserts sur le même external_id gardent leur handle existant.
descriptionstringNonDescription en texte brut.
description_htmlstringNonDescription HTML. Sanitizée côté serveur, voir HTML content.
status'active' | 'archived'NonDéfaut active. archived cache la collection à l'assistant.
default_languagestringNonCode ISO 639-1 de la langue des champs top-level.
source'public-api' | 'shopify' | 'supersmart'NonDéfaut public-api. Tagge la collection avec l'intégration qui possède cette donnée — utile quand vous poussez via cette API des données que vous maintenez aussi dans un autre système. La même valeur sert de clé de lookup pour l'upsert, donc re-poster avec le même source + external_id met à jour la même row. Toute autre valeur est rejetée avec une erreur 400 validation_failed sur source.
productsobject[]NonMemberships produits. Voir Lier les produits par external_id.
translationsobject[]NonOverrides par locale. Voir Translations.
created_atISO 8601Renvoyé seulementTimestamp de création (UTC).
updated_atISO 8601Renvoyé seulementTimestamp de dernière modification (UTC).

Membership produit

Chaque entrée dans products décrit un produit qui appartient à la collection.

ChampTypeRequisDescription
external_idstringOuiL'external_id d'un produit existant. Le serveur le résout en humind_id correspondant au moment de l'écriture. Voir Lier les produits par external_id.
include_all_variantsbooleanNonDéfaut true. Quand true, tous les variants du produit font partie de la collection.
included_variantsstring[]NonRequis si include_all_variants vaut false. Liste des external_id de variants à inclure. Les variants non listés sont exclus de la collection.

Translations

translations est une liste d'overrides par locale, keyée par language :

json
{
  "default_language": "fr",
  "title": "Nos meilleures ventes",
  "description": "Les produits les plus aimés de la saison.",
  "translations": [
    {
      "language": "en",
      "title": "Bestsellers",
      "description": "Our most-loved products this season."
    }
  ]
}

Champs par locale que vous pouvez override :

ChampType
titlestring
descriptionstring
description_htmlstring

Les locales non listées dans translations retombent sur la valeur top-level (en default_language).

Vous pouvez aussi patcher une locale à la fois sans renvoyer la collection complète via la sub-resource Translations dédiée.

HTML content

Le champ description_html accepte du HTML. Humind sanitize le HTML côté serveur avant de le stocker, avec 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 /collections crée une nouvelle collection, ou met à jour une existante 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/collections \
  -H "Authorization: Bearer hmd_live_..." \
  -H "Idempotency-Key: 3f1a8d92-7c4b-4e6f-b2a1-d5e9c8f7a3b4" \
  -H "Content-Type: application/json" \
  -d '{
    "external_id": "col-bestsellers",
    "handle": "bestsellers",
    "title": "Bestsellers",
    "description": "Our most-loved products this season.",
    "status": "active",
    "default_language": "en",
    "products": [
      { "external_id": "SKU-123", "include_all_variants": true },
      { "external_id": "SKU-456", "include_all_variants": false, "included_variants": ["SKU-456-A"] }
    ],
    "translations": [
      {
        "language": "fr",
        "title": "Nos meilleures ventes",
        "description": "Les produits les plus aimés de la saison."
      }
    ]
  }'

Response 201 Created (nouvelle collection) ou 200 OK (collection existante mise à jour)

json
{
  "external_id": "col-bestsellers",
  "humind_id": "65f1ab9c8e7d4a2b1c3d4e5f",
  "handle": "bestsellers",
  "title": "Bestsellers",
  "description": "Our most-loved products this season.",
  "status": "active",
  "default_language": "en",
  "products": [
    { "external_id": "SKU-123", "include_all_variants": true },
    { "external_id": "SKU-456", "include_all_variants": false, "included_variants": ["SKU-456-A"] }
  ],
  "translations": [
    {
      "language": "fr",
      "title": "Nos meilleures ventes",
      "description": "Les produits les plus aimés de la saison."
    }
  ],
  "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 une nouvelle collection (première fois que l'API voit cet external_id). Un 200 OK veut dire que la collection existait déjà et a été mise à jour en place. Les deux sont des succès.


List collections

GET /collections renvoie les collections 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 une seule collection par match exact de handle.

Request

bash
curl https://api.thehumind.com/public/v1/collections?limit=50 \
  -H "Authorization: Bearer hmd_live_..."

Pour récupérer la page suivante :

bash
curl "https://api.thehumind.com/public/v1/collections?limit=50&cursor=eyJpZCI6IjY1ZjEuLi4ifQ" \
  -H "Authorization: Bearer hmd_live_..."

Response 200 OK

json
{
  "data": [
    {
      "external_id": "col-bestsellers",
      "humind_id": "65f1ab9c8e7d4a2b1c3d4e5f",
      "handle": "bestsellers",
      "title": "Bestsellers",
      "status": "active",
      "default_language": "en",
      "products": [
        { "external_id": "SKU-123", "include_all_variants": true }
      ],
      "created_at": "2026-04-25T14:30:00Z",
      "updated_at": "2026-04-25T14:30:00Z"
    }
  ],
  "next_cursor": "eyJpZCI6IjY1ZjFjZDllOGU3ZDRhMmIxYzNkNGU2MCJ9"
}

Quand next_cursor vaut null ou est absent, vous êtes à la dernière page.


Retrieve a collection

GET /collections/{id} renvoie une seule collection. 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/collections/api:col-bestsellers \
  -H "Authorization: Bearer hmd_live_..."

Request, par humind_id

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

Response 200 OK

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


Replace a collection

PUT /collections/{id} fait un remplacement complet : le body de la requête devient la collection entière. Les champs que vous n'incluez pas sont reset à leurs défauts (ou unset là où c'est applicable). L'array products que vous envoyez remplace le membership courant en entier.

À utiliser quand vous avez une représentation complète de la collection 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/collections/api:col-bestsellers \
  -H "Authorization: Bearer hmd_live_..." \
  -H "Idempotency-Key: 7a2b3c4d-5e6f-4a8b-9c0d-1e2f3a4b5c6d" \
  -H "Content-Type: application/json" \
  -d '{
    "external_id": "col-bestsellers",
    "title": "Bestsellers, April 2026",
    "handle": "bestsellers",
    "status": "active",
    "default_language": "en",
    "products": [
      { "external_id": "SKU-123", "include_all_variants": true },
      { "external_id": "SKU-789", "include_all_variants": true }
    ]
  }'

Response 200 OK

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

Replace est destructif

PUT enlève tout champ, membership produit ou traduction non présent dans le body. Pour ajouter ou enlever un seul produit, utilisez plutôt PATCH.


Update a collection

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

Quand vous envoyez un array products en PATCH, il remplace la liste de membership en entier, il n'y a pas de merge par entrée. Pour ajouter un produit, envoyez la liste existante plus la nouvelle entrée. Pour en enlever un, envoyez la liste existante moins cette entrée.

Scope requis : catalog:write

Request, renommer sans toucher au membership

bash
curl -X PATCH https://api.thehumind.com/public/v1/collections/api:col-bestsellers \
  -H "Authorization: Bearer hmd_live_..." \
  -H "Idempotency-Key: 9b8a7c6d-5e4f-4a3b-2c1d-0e9f8a7b6c5d" \
  -H "Content-Type: application/json" \
  -d '{
    "title": "Bestsellers, April 2026"
  }'

Request, ajouter un produit à la collection

bash
curl -X PATCH https://api.thehumind.com/public/v1/collections/api:col-bestsellers \
  -H "Authorization: Bearer hmd_live_..." \
  -H "Idempotency-Key: 2c3d4e5f-6789-4abc-9def-0123456789ab" \
  -H "Content-Type: application/json" \
  -d '{
    "products": [
      { "external_id": "SKU-123", "include_all_variants": true },
      { "external_id": "SKU-456", "include_all_variants": false, "included_variants": ["SKU-456-A"] },
      { "external_id": "SKU-999", "include_all_variants": true }
    ]
  }'

Response 200 OK

Renvoie l'objet collection complet mis à jour.


Archiver (ou supprimer) une collection

DELETE /collections/{id} fait un soft delete par défaut : le status de la collection passe à archived et l'assistant arrête de l'utiliser pour ses recommandations. 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 la collection doit vraiment disparaître (ex. nettoyage d'un catalogue de test, collection créée 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 la collection. Défaut soft delete.

Request — soft delete (par défaut)

bash
curl -X DELETE https://api.thehumind.com/public/v1/collections/api:bestsellers \
  -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/collections/api:bestsellers?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 produits qui sont dans la collection restent intacts, vous pouvez désarchiver en un PATCH, et l'historique de chat qui ancrait ses recommandations sur cette collection reste cohérent.

Le hard delete (?force=true) sert au nettoyage de catalogue — typiquement une collection de test qu'on veut totalement enlevée. Le soft delete déclenche d'abord la routine d'archivage ; ?force=true supprime ensuite définitivement la ressource. Les produits qui étaient groupés par cette collection ne sont pas affectés ; seul le regroupement lui-même disparaît.


Batch upsert

POST /collections/batch accepte jusqu'à 500 collections dans un seul appel et renvoie une réponse 207 Multi-Status avec une entrée par item. À utiliser pour le sync initial de votre structure de merchandising ou n'importe quelle mise à jour bulk.

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/collections/batch \
  -H "Authorization: Bearer hmd_live_..." \
  -H "Idempotency-Key: 4d3c2b1a-9f8e-4d7c-6b5a-4f3e2d1c0b9a" \
  -H "Content-Type: application/json" \
  -d '{
    "items": [
      {
        "external_id": "col-bestsellers",
        "title": "Bestsellers",
        "default_language": "en",
        "products": [
          { "external_id": "SKU-123", "include_all_variants": true }
        ]
      },
      {
        "external_id": "col-new-arrivals",
        "title": "New arrivals",
        "default_language": "en",
        "products": [
          { "external_id": "SKU-456", "include_all_variants": true }
        ]
      },
      {
        "external_id": "col-bad",
        "default_language": "en"
      }
    ]
  }'

Response 207 Multi-Status

json
{
  "results": [
    {
      "external_id": "col-bestsellers",
      "status": "created",
      "humind_id": "65f1ab9c8e7d4a2b1c3d4e5f"
    },
    {
      "external_id": "col-new-arrivals",
      "status": "updated",
      "humind_id": "65f1cd9e8e7d4a2b1c3d4e60",
      "unresolved_products": ["SKU-456"]
    },
    {
      "external_id": "col-bad",
      "status": "failed",
      "error": {
        "code": "validation_failed",
        "message": "Invalid collection payload.",
        "details": {
          "issues": [
            { "path": ["title"], "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].unresolved_productsstring[]Optionnel. Liste les external_id produits qui ne correspondent à aucun produit qui appartient à votre company au moment de l'écriture. Pas une erreur. Voir ci-dessous.
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.


Linking products by external_id

Quand vous poussez une collection, chaque entrée dans products référence un produit par votre external_id, pas par humind_id. Le serveur résout la référence au moment de l'écriture :

  • Si l'external_id correspond à un produit qui appartient à votre company, le membership est enregistré avec le humind_id correspondant en interne.
  • Si l'external_id ne correspond à aucun produit, le membership est quand même enregistré, mais l'external_id non matché est rapporté dans unresolved_products dans la réponse. C'est un warning, pas une erreur : la requête réussit.

La collection lie automatiquement les produits non résolus dès que vous les poussez. Vous n'avez pas besoin de re-PATCH la collection, la prochaine fois que vous créez le produit manquant, Humind le rattache à la collection.

Poussez les produits avant les collections

L'ordre le plus propre c'est : poussez vos produits d'abord, puis vos collections. Ça évite unresolved_products complètement. Si vous ne pouvez pas (par exemple vous reconstruisez les deux d'un coup), c'est quand même safe, collections et produits convergent une fois que les deux côtés sont là.

Les endpoints mono-resource (POST, PUT, PATCH /collections/{id}) suivent la même règle. Le body de la réponse inclut unresolved_products: [...] à chaque fois qu'au moins une entrée n'a pas résolu, top-level à côté de l'objet collection :

json
{
  "external_id": "col-bestsellers",
  "humind_id": "65f1ab9c8e7d4a2b1c3d4e5f",
  "products": [
    { "external_id": "SKU-123", "include_all_variants": true },
    { "external_id": "SKU-DOES-NOT-EXIST-YET", "include_all_variants": true }
  ],
  "unresolved_products": ["SKU-DOES-NOT-EXIST-YET"]
}

Translations sub-resource

Pour les collections 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 /collections/{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.

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/collections/api:col-bestsellers/translations/fr \
  -H "Authorization: Bearer hmd_live_..." \
  -H "Idempotency-Key: 5f6a7b8c-9d0e-4f1a-2b3c-4d5e6f7a8b9c" \
  -H "Content-Type: application/json" \
  -d '{
    "title": "Nos meilleures ventes",
    "description": "Les produits les plus aimés de la saison."
  }'

Response 200 OK

Renvoie l'objet collection 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 /collections/{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/collections/api:col-bestsellers/translations/fr \
  -H "Authorization: Bearer hmd_live_..." \
  -H "Idempotency-Key: 6a7b8c9d-0e1f-4a2b-3c4d-5e6f7a8b9c0d"

Response 204 No Content

Pas de body.


Erreurs courantes

Les endpoints collections 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 à une collection qui appartient à votre company.Vérifiez l'external_id ou le humind_id. Les lookups cross-tenant renvoient aussi 404.
409idempotency_conflictMême Idempotency-Key réutilisée avec un body différent.Générez un UUID frais.
409handle_already_usedLe handle soumis est déjà utilisé par une autre collection dans cette company (matched sur un autre external_id).Choisissez un handle unique, ou faites un PATCH sur la collection existante (matched par external_id) au lieu d'en créer une nouvelle.
400validation_failedLe body a échoué le schéma Collection. 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.

unresolved_products n'est pas une erreur

Vous verrez ce champ sur les réponses 200/201/207 quand au moins une entrée dans products[] n'a pas pu être matchée à un produit existant. C'est un heads-up, pas un échec, le reste de la requête a été appliqué normalement et Humind lie les références manquantes au moment où ces produits arrivent.

Pour aller plus loin

  • Products : pousser les produits que les collections référencent.
  • Knowledge : pousser FAQ, articles et webpages sur lesquels l'assistant ancre ses réponses.
  • Errors : référence complète des codes d'erreur.

Released under the proprietary Humind license.