Pousser les données
Votre connecteur décide quand synchroniser et pousse vers l'API. Vous gardez la main sur le curseur, la fréquence et la reprise sur erreur, et vous n'avez aucune route à exposer : un backfill complet à la première connexion, puis des passes incrémentales à votre rythme.
Les treize entités
| Entité | Endpoints | Clé métier |
|---|---|---|
| Groupes de clients | POST · PUT · DELETE | group_id |
| Clients | POST · PUT · DELETE | customer_id |
| Adresses clients | POST · DELETE | address_id |
| Abonnés newsletter | POST · PUT | email |
| Commandes | POST · DELETE | order_id |
| Statuts de commande | POST · DELETE | status_id |
| Transporteurs | POST · DELETE | carrier_id |
| Produits | POST · PUT · DELETE | product_id |
| Déclinaisons | POST · DELETE | variation_id |
| Images produits | POST · DELETE | image_id |
| Catégories | POST · PUT · DELETE | category_id |
| Fabricants | POST · PUT · DELETE | manufacturer_id |
| Bons de réduction | POST · PUT · DELETE | voucher_id |
Les paniers n'y figurent pas : ils ne se créent pas par l'API de données. → Script de tracking
L'ordre des dépendances
Une entité qui en référence une autre doit être poussée après elle, sinon la référence est orpheline. ShopiMind applique cet ordre en trois vagues, et vous devriez faire de même pour un backfill initial :
Vague 1 ─ aucune dépendance
groupes de clients · abonnés newsletter · statuts · transporteurs
catégories · fabricants
Vague 2 ─ dépend de la vague 1
clients (← groupes) produits (← catégories, fabricants)
Vague 3 ─ dépend de la vague 2
adresses (← clients) commandes (← clients, produits)
déclinaisons (← produits) images (← produits) bons (← clients)À l'intérieur d'une vague, les entités sont indépendantes : parallélisez librement.
Écrire en lot
Toutes les écritures bulk* prennent un tableau et sont asynchrones : un 200 confirme la mise en file, pas la visibilité en lecture. Comptez quelques secondes.
import { SpmProducts } from '@shopimind/sdk-js';
const res = await SpmProducts.bulkSave(client, products, { chunk: true });
if (!res.ok) throw new Error(res.error.message);{ chunk: true } découpe automatiquement selon la taille maximale de lot propre à chaque ressource et agrège les compteurs. Sans le SDK, respectez les tailles indiquées dans la référence API de chaque endpoint : au-delà, le lot entier est refusé en 400.
Idempotence
Poussez toujours par upsert sur une clé métier stable. Un bulkSave avec un customer_id déjà connu met à jour ; il ne duplique pas. C'est ce qui rend une resynchronisation sûre, et vous en aurez besoin le jour où un backfill échoue à mi-parcours.
Conséquence : votre clé métier doit être stable dans le temps. N'utilisez pas un identifiant qui change quand le marchand renomme un produit ou fusionne deux fiches.
Synchronisation incrémentale
Le schéma qui marche :
- Backfill complet à la première connexion, dans l'ordre des vagues.
- Ensuite, des passes incrémentales filtrées sur votre date de dernière modification.
- Gardez un curseur par entité, côté votre service.
N'avancez le curseur qu'après une passe entièrement réussie
Si vous avancez le curseur alors qu'une page a échoué, les objets de cette page ne seront jamais resynchronisés, vous perdez des données silencieusement. Le curseur ne doit avancer qu'après un succès complet ; en cas d'échec partiel, rejouez à partir du curseur précédent (c'est sans risque, l'upsert est idempotent).
Une marge de recouvrement de quelques minutes sur le curseur évite de rater les objets modifiés pendant la passe elle-même.
Rejets partiels
Un lot dont certains objets sont invalides renvoie quand même 200 : les objets valides passent, les autres sont rejetés individuellement.
{
"statusCode": 200,
"sent_count": 18,
"rejected_count": 2,
"rejected_items": [
{
"index": 4,
"item": { /* l'objet EXACT que vous avez envoyé */ },
"errors": [
{ "field": "email", "message": "Validation failed: email must be an email" }
]
}
]
}Le payload d'origine est renvoyé dans item : c'est lui qu'il faut journaliser pour rejouer ou corriger, pas seulement l'index.
Le cas « tout le lot est invalide »
Si tous les objets d'un lot sont refusés, la réponse reste 200 avec sent_count: 0 et le détail complet, il n'y a pas de 400. C'est délibéré : cela évite qu'une synchronisation boucle indéfiniment sur la même page. Ne traitez donc pas « HTTP 200 » comme « rien à faire ».
Conventions de format
Ces conventions sont celles des modules officiels. Les respecter vous évite l'essentiel des rejets.
| Sujet | Convention |
|---|---|
| Dates | ISO 8601 avec microsecondes et décalage réel : 2026-08-04T11:42:07.000000+02:00. Le décalage doit être celui de la boutique, pas Z, sauf si la boutique est réellement en UTC. |
| Identifiants | Toujours transmis en chaînes, jamais en nombres, même quand votre base stocke des entiers. |
| Montants | Nombres à la précision de la devise (2 pour EUR/USD, 0 pour JPY, 3 pour BHD). |
| Langues | ISO 639-1 (fr, en). |
| Devises | ISO 4217 (EUR, USD). |
| Booléens | Booléens JSON, pas 0/1 ni "true". |
Rythme et volumétrie
- Quota : par clé API, partagé entre tous les endpoints
/v1. Le compteur se réinitialise à chaque minute civile. - Préférez les lots : un
bulkSavede 50 objets consomme une requête, pas cinquante. - En cas de dépassement, appliquez un backoff exponentiel. Le SDK le fait par défaut (3 relances sur 408/429/5xx et erreurs réseau).
Étape suivante
→ Script de tracking : pour les paniers et le comportement visiteur.