Quickstart
This page takes you from an empty ShopiMind shop to a connector that declares the shop and then pushes its first data. Budget about thirty minutes. The "inbound callbacks" and "tracking" channels come next, each in its own page.
Before you start
- A ShopiMind shop and access to the dashboard.
- Node.js 18+ if you follow the SDK examples. Otherwise every call is also given as raw HTTP: the REST API is the contract, the SDK is only a convenience.
1. Collect your credentials
Open Shop settings → API access. You will find two distinct things there:
| What it is | Confidentiality | |
|---|---|---|
| Shop identifier | Identifies the shop. Short format, e.g. SPM123456. | Public: it appears in plain text in your shop's HTML (tracking channel). |
| API key | Authenticates your calls. Format {prefix}.{secret}, shown once at creation. | Secret: environment variable or vault. Never in a repository, never in front-end code. |
Generate a key dedicated to your connector and note it down. We will call them SPM_SHOP_IDENTIFIER and SPM_API_KEY.
One key for the connector
The connection call (step 3) marks the key it used as the shop's primary key: the one that will then sign inbound callbacks. So never run that call with an exploratory or test key: you would break voucher signing. → Connection
2. Install the SDK (optional)
yarn add @shopimind/sdk-jsThe SDK is ESM-only (Node ≥ 18.17) and has a single dependency: axios. It provides hardened transport (verified TLS, redirects not followed so the key cannot leak, size caps), automatic retries, chunking and a uniform response envelope.
import { SpmClient } from '@shopimind/sdk-js';
const client = SpmClient.getClient('v1', process.env.SPM_API_KEY!);3. Connect the shop
This is the call that declares your shop to ShopiMind: currency, languages, timezone, and above all url_client, the root of inbound callbacks. Run it once at install, then whenever the configuration changes.
Four headers are mandatory. Forgetting the last one is the most common mistake.
curl -X POST 'https://core.shopimind.com/v1/shop/connection' \
-H "spm-api-key: $SPM_API_KEY" \
-H "client-id: $SPM_SHOP_IDENTIFIER" \
-H 'client-version: 1.0.0' \
-H 'current-build: 1' \
-H 'Content-Type: application/json' \
-d '{
"default_currency": "EUR",
"default_lang": "fr",
"langs": ["fr", "en"],
"timezone": "Europe/Paris",
"url_client": "https://connector.my-shop.com/shopimind",
"ecommerce_version": "1.0.0",
"module_version": "1.0.0"
}'With the SDK, connection headers go through the client options:
import { SpmClient, SpmShopConnection } from '@shopimind/sdk-js';
const client = SpmClient.getClient('v1', process.env.SPM_API_KEY!, {
headers: {
'client-id': process.env.SPM_SHOP_IDENTIFIER!,
'client-version': '1.0.0',
'current-build': '1',
},
});
const res = await SpmShopConnection.saveConfiguration(client, {
default_currency: 'EUR',
default_lang: 'fr',
langs: ['fr', 'en'],
timezone: 'Europe/Paris',
url_client: 'https://connector.my-shop.com/shopimind',
ecommerce_version: '1.0.0',
module_version: '1.0.0',
});
if (!res.ok) throw new Error(res.error.message);A 200 means the shop is declared. → Full contract
4. Push your first data
Order matters: an entity cannot reference something that does not exist yet. For a first run, push categories, then products, then customers.
import { SpmProductsCategories, SpmProducts, SpmCustomers } from '@shopimind/sdk-js';
// 1) Categories, before the products that reference them
await SpmProductsCategories.bulkSave(client, [
{
category_id: 'CAT-1',
name: 'Starter kits',
is_active: true,
created_at: '2026-01-15T10:00:00.000000+01:00',
updated_at: '2026-01-15T10:00:00.000000+01:00',
},
], { chunk: true });
// 2) Products
await SpmProducts.bulkSave(client, [
{
product_id: 'P-4471',
name: 'Starter kit',
price: 49.9,
category_ids: ['CAT-1'],
is_active: true,
created_at: '2026-01-15T10:00:00.000000+01:00',
updated_at: '2026-02-01T09:12:00.000000+01:00',
},
], { chunk: true });
// 3) Customers
const res = await SpmCustomers.bulkSave(client, [
{
customer_id: '4212',
email: 'marie@example.com',
first_name: 'Marie',
last_name: 'Dupont',
is_active: true,
created_at: '2025-11-02T14:30:00.000000+01:00',
updated_at: '2026-02-01T09:12:00.000000+01:00',
},
], { chunk: true });
console.log(res.data); // { sent_count, rejected_count, rejected_items }In raw HTTP the body is the same, an array of objects:
curl -X POST 'https://core.shopimind.com/v1/customers' \
-H "spm-api-key: $SPM_API_KEY" \
-H 'Content-Type: application/json' \
-d '[{ "customer_id": "4212", "email": "marie@example.com", "first_name": "Marie",
"last_name": "Dupont", "is_active": true,
"created_at": "2025-11-02T14:30:00.000000+01:00",
"updated_at": "2026-02-01T09:12:00.000000+01:00" }]'A 200 does not mean "everything went through"
Bulk writes are asynchronous and partially tolerant: a 200 confirms queueing, and invalid objects are rejected individually without failing the batch. Always check rejected_count and rejected_items: each rejection hands you back the original payload and the offending fields. → Handling rejections
5. Verify
Read back what ShopiMind actually stored:
curl -s 'https://core.shopimind.com/v1/customers?limit=5' -H "spm-api-key: $SPM_API_KEY"Allow a few seconds between the write and the read: processing is asynchronous.
In the dashboard the data shows up in the Contacts and Catalog screens. A pushed customer also materialises a contact: the unified profile that scenarios target.
What next
| You want to… | Go to |
|---|---|
| Understand entity order and cursors | Pushing data |
| Get abandoned-cart recovery working | Tracking script |
| Generate personalised vouchers from a scenario | Inbound callbacks |
| The entity list and the target scope | Reference |