TypeScript
@shopimind/sdk-js est écrit en TypeScript et publie ses déclarations .d.ts directement dans le paquet. Vous n'avez rien à installer en plus : pas de paquet @types/..., pas de stubs. Dès l'import, votre IDE vous propose l'autocomplétion des ressources, des méthodes et des champs de chaque DTO.
ESM uniquement
Le SDK est ESM only (Node.js 18+). Importez-le avec import ; require() n'est pas supporté. Voir → Installation.
import {
SpmClient,
SpmCustomers,
type SpmCustomerData,
type SpmEnvelope,
type SpmChunkedEnvelope,
SpmHelpers,
} from '@shopimind/sdk-js';
// Le client est authentifié par la clé API de la boutique (en-tête spm-api-key)
const client = SpmClient.getClient('v1', process.env.SHOPIMIND_API_KEY!);
const items: SpmCustomerData[] = [/* … */];
const res: SpmEnvelope | SpmChunkedEnvelope =
await SpmCustomers.bulkSave(client, items, { chunk: true });
if (res.ok) {
const counts = SpmHelpers.extractCounts(res);
console.log(`${counts.sent} envoyés, ${counts.rejected} rejetés`);
}L'enveloppe typée SpmEnvelope<T>
Toutes les méthodes du SDK renvoient la même enveloppe, en succès comme en échec — le SDK ne lève jamais d'exception sur une erreur HTTP. Elle est générique : SpmEnvelope<T> vous laisse typer le corps de réponse attendu.
interface SpmEnvelope<T = unknown> {
ok: boolean; // true sur HTTP 2xx
statusCode: number; // statut HTTP ; 0 en cas d'échec réseau
data: T | null; // corps de l'API (ou null)
error: SpmEnvelopeError | null;
}
interface SpmEnvelopeError {
message: string;
code: string; // 'HTTP_503', 'ETIMEDOUT', 'PARTIAL_FAILURE'…
retryable: boolean;
attempts: number;
details?: unknown;
}Payload métier double-niché
L'API ShopiMind enveloppe déjà ses réponses dans { statusCode, data }. Le SDK place ce corps entier dans envelope.data. Le payload métier se trouve donc à res.data.data, pas à res.data. Pensez-y quand vous paramétrez le générique T.
Le découpage automatique (chunk: true) renvoie une variante typée de l'enveloppe, SpmChunkedEnvelope, dont le data agrège les compteurs de tous les lots :
type SpmChunkedEnvelope = SpmEnvelope<SpmChunkedData>;
interface SpmChunkedData {
sent_count: number;
rejected_count: number;
failed_count: number;
rejected_items: unknown[];
chunks: SpmChunkSummary[];
}Les options du client, typées
SpmClient.getClient(apiVersion, apiKey, options) accepte un troisième argument typé SpmClientOptions :
interface SpmClientOptions {
headers?: Record<string, string>;
baseUrl?: string; // défaut https://core.shopimind.com (ou env SHOPIMIND_CORE_API_BASE)
timeout?: number; // défaut 30000 (ms)
labelSource?: string | null; // défaut 'web' ; null désactive l'injection de label_source
retry?: SpmRetryOptions | false; // défaut 3 retries ; false désactive
}DTOs réels (interfaces de données)
Chaque entité synchronisable expose une interface dédiée, exportée par le SDK. Les noms de champs correspondent exactement au corps attendu par l'API. Toutes ces interfaces héritent de SpmDataSourceAttributes (id_data_source?, source_label?) pour rattacher une donnée à une source.
interface SpmDataSourceAttributes {
id_data_source?: number;
source_label?: string;
}SpmCustomerData
interface SpmCustomerData extends SpmDataSourceAttributes {
customer_id: string;
shop_id?: string | null;
email: string;
phone_number?: string | null;
first_name: string;
last_name: string;
birth_date?: string | null;
is_opt_in: boolean;
is_newsletter_subscribed: boolean;
lang: string;
group_ids?: string[] | null;
is_active: boolean;
created_at: string;
updated_at: string;
}SpmProductData
interface SpmProductData extends SpmDataSourceAttributes {
product_id: number;
shop_id?: string | null;
lang: string;
name: string;
reference?: string | null;
ean13?: string | null;
description: string;
description_short?: string | null;
link: string;
image_link?: string | null;
category_ids?: number[] | null;
manufacturer_id?: string | null;
currency: string;
price: number;
price_discount?: number | null;
quantity_remaining: number;
is_active: boolean;
created_at: string;
updated_at: string;
}SpmOrderData
Une commande embarque son client (SpmOrderCustomer) et ses lignes (SpmOrderProduct[]) :
interface SpmOrderData extends SpmDataSourceAttributes {
order_id: string;
shop_id?: string | null;
lang: string;
reference?: string | null;
carrier_id?: string | null;
status_id: string;
address_delivery_id?: string | null;
address_invoice_id?: string | null;
customer: SpmOrderCustomer;
products: SpmOrderProduct[];
cart_id: string;
cart_updated_at: string;
amount: number;
amount_without_tax: number;
shipping_costs: number;
shipping_costs_without_tax: number;
shipping_number?: string | null;
currency: string;
voucher_used?: string | null;
voucher_value?: string | null;
is_confirmed: boolean;
created_at: string;
updated_at: string;
}
interface SpmOrderCustomer {
customer_id: string;
email: string;
created_at: string;
}
interface SpmOrderProduct {
product_id: number;
product_variation_id?: number | null;
price: number;
price_without_tax: number;
manufacturer_id?: string | null;
quantity: number;
}Autres interfaces exportées
Le SDK exporte un DTO par entité. Toutes sont importables comme types depuis @shopimind/sdk-js :
| Domaine | Interfaces |
|---|---|
| Boutique | SpmShopConnectionData |
| Clients | SpmCustomerData, SpmCustomerAddressData, SpmBulkCustomerAddressData, SpmCustomerGroupData |
| Produits | SpmProductData, SpmProductCategoryData, SpmProductImageData, SpmBulkProductImageData, SpmProductManufacturerData, SpmProductVariationData, SpmBulkProductVariationData |
| Commandes | SpmOrderData, SpmOrderCustomer, SpmOrderProduct, SpmOrderCarrierData, SpmOrderStatusData |
| Bons | SpmVoucherData |
| Sources de données | SpmDataSourceData, SpmCreateDataSourceData |
| Custom data | SpmCustomDataFieldDef, SpmCustomDataRelationshipDef, SpmCreateCustomDataDefinitionData, SpmExtendCustomDataDefinitionData, SpmCustomDataRecord |
| Événements | SpmCreateEventData, SpmUpdateEventData, SpmTriggerEventPayload |
| Listes / Contacts | SpmCreateListData, SpmUpdateListData, SpmContactGetParams |
| Infra SDK | SpmEnvelope<T>, SpmEnvelopeError, SpmChunkedEnvelope, SpmChunkedData, SpmClientOptions, SpmBulkOptions, SpmRetryOptions, SpmHttpClient, SpmApiError |
| Sécurité | SpmWebhookSignature (résultat SpmWebhookVerifyResult), SpmRequestValidator (résultat SpmValidationResult) |
→ La liste exhaustive des ressources et de leurs méthodes : Ressources.
Helpers et mode exception (unwrapOrThrow)
SpmHelpers.unwrapOrThrow est un mode exception opt-in : il déballe le double-niché (res.data.data) et lève SpmApiError si l'enveloppe n'est pas ok. SpmApiError porte statusCode, code et l'enveloppe d'origine (envelope), et n'est levée que par unwrapOrThrow.
import { SpmClient, SpmCustomers, SpmHelpers, SpmApiError } from '@shopimind/sdk-js';
const client = SpmClient.getClient('v1', process.env.SHOPIMIND_API_KEY!);
try {
// unwrapOrThrow déballe res.data.data et lève SpmApiError si !ok
const customer = SpmHelpers.unwrapOrThrow(await SpmCustomers.get(client, 'cust_1'));
console.log(customer.email);
} catch (err) {
if (err instanceof SpmApiError) {
console.error(err.statusCode, err.code, err.envelope);
}
}Primitives de sécurité, typées
Le SDK expose deux primitives de vérification de signature, chacune avec son type de résultat :
SpmWebhookSignature— canal intégration : HMAC-SHA256 horodaté avec fenêtre anti-rejeu (en-têtesx-shopimind-timestamp/x-shopimind-signature, helperverifyFromHeaders). Renvoie unSpmWebhookVerifyResult.SpmRequestValidator— canal connecteur : corps « imploded » trié + HMAC-SHA256 avec comparaison à temps constant (en-têtesShopimind-Token/Shopimind-Client-Identifiant), utilisé par les connecteurs CMS. Renvoie unSpmValidationResult.
Exemple typé de bout en bout
Le compilateur valide la forme de chaque commande, la clé API est lue depuis l'environnement, et le résultat est typé via SpmChunkedEnvelope :
import {
SpmClient,
SpmOrders,
type SpmOrderData,
type SpmChunkedEnvelope,
} from '@shopimind/sdk-js';
const client = SpmClient.getClient('v1', process.env.SHOPIMIND_API_KEY!, {
retry: { maxRetries: 5 },
});
const orders: SpmOrderData[] = [
{
order_id: 'ord_1',
lang: 'fr',
reference: 'CMD-2026-0001',
status_id: 'paid',
customer: { customer_id: 'cust_1', email: 'client@example.com', created_at: '2026-01-01T09:00:00Z' },
products: [
{ product_id: 42, price: 19.9, price_without_tax: 16.58, quantity: 2 },
],
cart_id: 'cart_1',
cart_updated_at: '2026-01-01T09:00:00Z',
amount: 39.8,
amount_without_tax: 33.16,
shipping_costs: 4.9,
shipping_costs_without_tax: 4.08,
currency: 'EUR',
is_confirmed: true,
created_at: '2026-01-01T09:05:00Z',
updated_at: '2026-01-01T09:05:00Z',
},
];
const res: SpmChunkedEnvelope = await SpmOrders.bulkSave(client, orders, { chunk: true });
if (!res.ok) {
throw new Error(res.error!.message); // rien n'est levé par le SDK : on teste res.ok
}
console.log(`Commandes envoyées : ${res.data!.sent_count}`);Configuration TypeScript
Comme le SDK est ESM, utilisez "module": "NodeNext" (ou ESNext) et "moduleResolution": "NodeNext" dans votre tsconfig.json. Les déclarations .d.ts sont résolues automatiquement via le champ exports du paquet.
Suite : Périmètre et versionnage.