ULTINEO

Votre premier appel

L'API Ultineo permet à vos propres outils de remplir votre boutique et de la relire : un script de migration, une synchronisation avec votre ERP ou un flux fournisseur envoie des éléments par lots, et relit n'importe quel élément pour vérifier ce qui a été enregistré. C'est une API JSON sur HTTPS. Vous vous authentifiez avec la clé API de votre boutique, vous appelez un chemin sous /v1/ et vous lisez le résultat dans une enveloppe de réponse unique.

Avant de commencer — Il vous faut une clé API pour votre boutique (elle commence par sk-project-) détenant les droits de lecture et/ou d'écriture des ressources que vous appelez, ainsi qu'un moyen d'envoyer une requête HTTP avec un corps JSON, par exemple curl.

URL de base

Toutes les requêtes sont envoyées à :

curl
https://api.ultineo.com/v1/

Seul HTTPS est servi. Une requête sur http:// reçoit une redirection 301 vers le même chemin en https://.

Important — Votre clé circule dans un en-tête de requête : une seule requête en clair la divulgue en entier. Appelez toujours directement l'adresse https:// au lieu de compter sur la redirection.

Un point d'accès ne demande aucune clé ; vous pouvez l'utiliser pour vérifier que l'hôte est joignable :

curl
curl https://api.ultineo.com/health
application/json
{
  "code": 200,
  "title": "OK",
  "response": "api gateway"
}

Authentification

Envoyez votre clé comme jeton Bearer à chaque appel :

En-têteValeur
AuthorizationBearer sk-project-…
Content-Typeapplication/json (uniquement lorsque vous envoyez un corps)

Une clé appartient à une seule boutique. Chaque lecture et chaque écriture est limitée à cette boutique, quoi que vous mettiez dans l'URL ou dans le corps : un élément d'une autre boutique répond 404, exactement comme un élément qui n'existe pas. Une clé peut aussi être désactivée ou porter une date d'expiration ; une clé désactivée ou expirée est refusée (voir Codes d'erreur).

Droits

Chaque ressource a un droit (scope) de lecture et un droit d'écriture. Un GET exige le droit :read de la ressource et un POST exige son droit :write.

RessourceDroit de lectureDroit d'écriture
Caractéristiquesattribute:readattribute:write
Catégoriescategory:readcategory:write
Groupes de produitsproduct_group:readproduct_group:write
Produitsproduct:readproduct:write
Avis produitsproduct_review:readproduct_review:write
Clientscustomer:readcustomer:write
Commandesorder:readorder:write
Paiementspayment:readpayment:write
Expéditionsshipment:readshipment:write
Réclamations transporteurshipment_claim:readshipment_claim:write
Colis refusésshipment_refused:readshipment_refused:write
Remboursementsrefund:readrefund:write
Retours de commandeorder_return:readorder_return:write
Portefeuille clientcustomer_wallet:readcustomer_wallet:write
Demandes d'assistancesupport_request:readsupport_request:write
Bons de réductionpromotion:readpromotion:write

Une clé peut aussi détenir <resource>:*, qui accorde les deux actions sur cette ressource, ou *, qui accorde tout. Un appel auquel il manque son droit est refusé avec 403 et un message nommant le droit manquant.

Remarque — Les bons de réduction utilisent les droits promotion:read et promotion:write, bien que leur chemin soit /v1/voucher/import.

Effectuer l'appel

Cet appel relit une catégorie de votre boutique par son nom :

curl
curl "https://api.ultineo.com/v1/category/import?name=Smartphones" \
  -H "Authorization: Bearer sk-project-YOUR_KEY"
application/json
{
  "code": 200,
  "title": "OK",
  "response": {
    "object": "category",
    "id": "cate_4be1a07f93c2d58e6a10",
    "name": "Smartphones",
    "slug": "smartphones-cate_4be1a07f93c2d58e6a10",
    "description": "Refurbished smartphones, tested and graded.",
    "parent": "",
    "image": "",
    "position": 1,
    "status": "activated",
    "seo_title": "",
    "seo_description": "",
    "seo_image": "",
    "reference": "",
    "warranty": "",
    "created_at": 1789143990,
    "updated_at": 1789143990
  }
}

L'enveloppe de réponse

Chaque point d'accès répond avec les trois mêmes clés, en cas de succès comme en cas d'échec. Lisez d'abord le code de statut HTTP, puis lisez response.

ChampTypeDescription
codeentierLe code de statut HTTP, répété dans le corps.
titlechaîneLe libellé court du statut, par exemple OK ou Not Found.
responseobjet ou chaîneL'élément ou le rapport d'import en cas de succès ; un message explicatif en cas d'échec.

Fonctionnement de chaque import

Chaque ressource s'écrit selon le même contrat POST : dès que vous avez importé une ressource, vous savez les importer toutes.

Le corps de la requête

application/json
{
  "dry_run": true,
  "items": [
    { "name": "Smartphones" },
    { "name": "Tablets" }
  ]
}
ChampTypeObligatoireDescription
itemstableauOuiLes éléments à importer, un objet chacun. Ce doit être une liste non vide, sans dépasser la limite de lot de la ressource.
dry_runbooléenNontrue vérifie tout le lot et indique ce qui se passerait, sans rien enregistrer. Vaut false par défaut.

Le corps doit être un JSON valide et ne pas dépasser 200 000 octets. Chaque ressource a sa propre limite de lot, de 25 à 500 éléments, indiquée dans son tableau de points d'accès. Les ensembles plus grands s'envoient en plusieurs lots.

Renvoyer sans créer de doublons

Chaque élément est reconnu par sa propre clé — sa référence d'origine dans votre ancien système (external_id), ou son SKU ou son nom pour le catalogue. Envoyer un élément déjà présent dans votre boutique le met à jour si quelque chose a changé, ou le signale comme unchanged ; il n'est jamais créé deux fois. Vous pouvez donc rejouer un import interrompu depuis le début. Une mise à jour ne modifie que les champs que vous avez envoyés ; les champs omis gardent leur valeur enregistrée.

Tester avec le mode essai

Avec "dry_run": true, vous obtenez le rapport complet — ce qui serait créé, mis à jour, laissé inchangé ou refusé — et rien n'est écrit. Vérifiez toujours le champ dry_run de la réponse avant de vous fier à un rapport.

Le rapport d'import

application/json
{
  "code": 200,
  "title": "OK",
  "response": {
    "object": "list",
    "resource": "category",
    "dry_run": false,
    "data": [
      {
        "index": 0,
        "external_id": "Smartphones",
        "action": "updated",
        "id": "cate_4be1a07f93c2d58e6a10",
        "code": null,
        "title": null,
        "reason": null,
        "notice": []
      },
      {
        "index": 1,
        "external_id": "Tablets",
        "action": "refused",
        "id": null,
        "code": 422,
        "title": "Unprocessable Entity",
        "reason": "status must be one of: activated, suspended.",
        "notice": []
      }
    ],
    "created": 0,
    "updated": 1,
    "unchanged": 0,
    "refused": 1,
    "total": 2
  }
}

data contient une entrée par élément, dans l'ordre où vous les avez envoyés :

ChampTypeDescription
indexentierLa position de l'élément dans votre tableau items, à partir de 0.
external_idchaîne ou nullLa clé par laquelle l'élément a été reconnu.
actionchaînecreated, updated, unchanged ou refused.
idchaîne ou nullL'identifiant de l'élément dans votre boutique. null en cas de refus, et pour une création en mode essai.
codeentier ou nullPour un élément refusé, le code de statut du refus.
titlechaîne ou nullPour un élément refusé, le libellé de statut du refus.
reasonchaîne ou nullPour un élément refusé, ce qu'il faut corriger.
noticetableauMessages d'information sur un élément accepté, par exemple une valeur qui a été ajustée.

Les compteurs created, updated, unchanged et refused totalisent total, le nombre d'éléments que vous avez envoyés. Un élément refusé ne bloque jamais les autres : l'appel répond 200 dès qu'au moins un élément a été accepté, et 422 uniquement lorsque tous les éléments ont été refusés. Lisez donc le rapport ligne par ligne, même sur un 200.

Certaines ressources ajoutent leurs propres champs à chaque entrée, comme les lignes d'une commande ou les codes d'un bon de réduction ; ils sont décrits dans la rubrique de chaque ressource.

Relire un élément

Chaque ressource relit UN élément à la fois avec un GET sur son chemin d'import, en désignant l'élément par sa clé (par exemple ?external_id=…) ou par son identifiant dans votre boutique (?id=…). Les paramètres acceptés par chaque ressource sont indiqués dans sa rubrique.

Remarque — L'API lit un élément à la fois : il n'y a ni liste, ni recherche, ni pagination. Elle ne supprime rien non plus : la suppression se fait dans votre espace de travail, et un import ne fait jamais revenir un élément supprimé.

Dates et montants

Les horodatages, comme created_at, sont envoyés et renvoyés sous forme de nombres entiers de secondes depuis l'epoch Unix, en UTC ; une date dans un autre format est refusée, pas convertie. Dans une réponse, 0 signifie que la date n'est pas renseignée. Les montants sont renvoyés sous forme de chaînes contenant un nombre décimal, par exemple "129.90", afin qu'aucune précision ne soit perdue.

Ordre d'import recommandé

Les éléments font référence les uns aux autres : importez d'abord ceux dont les autres dépendent.

  1. Catalogue : les caractéristiques, puis les catégories, puis les groupes de produits, puis les produits, puis les avis — voir Catalogue.
  2. Historique des ventes : les clients, puis les commandes, puis les paiements et les expéditions, puis les remboursements, les retours, les réclamations transporteur, les colis refusés, les mouvements de portefeuille et les demandes d'assistance — voir Commandes & logistique.
  3. Les bons de réduction, une fois importés les clients auxquels leurs codes sont réservés — voir Bons de réduction.