Stores

A store represents a subset of the DJUST platform that enables the management of multiple e-commerce sites or commercial divisions independently from a single back office.

It is used to segment products, users, and offers based on specific criteria.

A store can be used to manage:

  • Different business entities (e.g., distinct brands, countries, or regions).
  • Different customer personas (e.g., premium vs. basic, independents vs. retail chains).

Key Characteristics

  • Your platform must be configured in multi-store mode in order to create and manage multiple stores.
  • Each store is identified by a unique ID and has its own set of configuration parameters.
  • A store allows you to:
    • Customize the user experience based on commercial or regional context.
    • Separate stock and offers based on defined rules (e.g., one store per country).
    • Filter products and offers according to access rights and the organizational structure.

Some elements are shared across all stores, while others are store-specific:


Reading a store through the API

The detail of a store is read with STORE-500 (GET /v1/shop/stores/{storeId}). The response returns, in a single call, the whole configuration of the store: its identifiers, its activation status, its locales (storeLocales) and its store views (storeViews).

Store views on the store detail

storeViews lists every store view of the store, active and inactive, each with:

FieldDescription
idDJUST identifier of the store view — the value to send in the dj-store-view header
externalIdExternal identifier of the store view
nameDisplay name of the store view
activeWhether the store view is active

A store with no store view returns an empty array.

📘

Note: storeLocales and storeViews are two distinct notions. A locale is a language available on the store; a store view is a browsing context (dj-store-view). Both are returned, and neither replaces the other.

{
  "id": "e1b7f8a2-9c34-4d51-8f10-7a2c6d9e4b33",
  "externalId": "STORE-FR",
  "name": "France",
  "active": true,
  "storeLocales": [
    { "code": "fr_FR", "default": true },
    { "code": "en_US", "default": false }
  ],
  "storeViews": [
    {
      "id": "4c2a91d7-6b08-4f3e-9a55-1d8e72c0b461",
      "externalId": "VIEW-FR-B2B",
      "name": "France B2B",
      "active": true
    },
    {
      "id": "8f5d30b1-27ac-4e69-b0d2-6e94a3f18c57",
      "externalId": "VIEW-FR-B2C",
      "name": "France B2C",
      "active": false
    }
  ]
}
✅

Tip: A front-end can position its dj-store-view context straight from the store detail, without a second call and without hard-coding store view identifiers.


Listing the stores of the authenticated customer user

A single sign-in page placed in front of several stores needs to know, right after authentication, which stores the customer user belongs to — to open the session directly when there is only one, or to display a selection screen otherwise.

The storefront list route GET /v1/shop/stores (operationId: STORE-550) answers exactly that question.

CharacteristicBehaviour
Client typedj-client: ACCOUNT only — an OPERATOR or SUPPLIER call is rejected with 403
dj-store headerNot required. The route is callable before any store has been chosen. A dj-store sent anyway is ignored and does not alter the list
PerimeterOnly the stores the authenticated customer user is attached to, active and inactive
No attachment200 with an empty list
ResponsePaginated StoreResponse, storeViews[] included
⚠️

Warning: A store of the tenant the customer user is not attached to never appears in the response — even when it is explicitly requested through a filter. The filters narrow the user's own perimeter; they never widen it.

Filtering, sorting and pagination

  • Filters — on the activation status, on the DJUST identifiers, or on the externalIds. Different criteria are combined with a logical AND, several values of the same criterion with a logical OR.
  • Sorting — on name, externalId or active. Default: name:asc. Invalid sort entries are silently ignored, the valid ones still apply.
  • Pagination — standard DJUST paginated envelope.
  • A 400 is returned when the activation filter value or the pagination parameters are malformed.
GET /v1/shop/stores?active=true&sort=name:asc&page=0&size=20
dj-client: ACCOUNT
dj-api-key: <your-api-key>
{
  "content": [
    {
      "id": "e1b7f8a2-9c34-4d51-8f10-7a2c6d9e4b33",
      "externalId": "STORE-FR",
      "name": "France",
      "active": true,
      "storeLocales": [{ "code": "fr_FR", "default": true }],
      "storeViews": [
        {
          "id": "4c2a91d7-6b08-4f3e-9a55-1d8e72c0b461",
          "externalId": "VIEW-FR-B2B",
          "name": "France B2B",
          "active": true
        }
      ]
    },
    {
      "id": "b93c71e4-08af-42d6-91cc-5a0f3d8e2617",
      "externalId": "STORE-BE",
      "name": "Belgium",
      "active": true,
      "storeLocales": [{ "code": "fr_BE", "default": true }],
      "storeViews": []
    }
  ],
  "totalElements": 2,
  "totalPages": 1,
  "number": 0,
  "size": 20,
  "first": true,
  "last": true,
  "empty": false
}

Post-login store resolution

flowchart LR
  %% Styles (Readme)
  classDef create   fill:#e8f1ff,stroke:#2f6feb,stroke-width:2px,color:#0b3d91;
  classDef read     fill:#ede9fe,stroke:#7c3aed,stroke-width:2px,color:#1e1b4b;
  classDef update   fill:#e0f7fa,stroke:#06b6d4,stroke-width:2px,color:#0c4a6e;
  classDef add      fill:#ecfdf5,stroke:#10b981,stroke-width:2px,color:#064e3b;
  classDef remove   fill:#fee2e2,stroke:#ef4444,stroke-width:2px,color:#7f1d1d;
  classDef decision fill:#fff4e5,stroke:#f59e0b,stroke-width:2px,color:#7a3e00;
  classDef place    fill:#dcfce7,stroke:#16a34a,stroke-width:2px,color:#14532d;
  classDef sys      fill:#f2f4f7,stroke:#475569,stroke-width:2px,color:#111827;
  classDef stop     fill:#fee2e2,stroke:#ef4444,stroke-width:2px,color:#7f1d1d;

  A[🔑 Customer user<br>authenticated]:::sys --> B[📘 GET /v1/shop/stores<br>no dj-store header]:::read
  B --> C{How many stores<br>are returned}:::decision
  C -->|Zero| D[⛔ No attachment<br>empty list with 200]:::stop
  C -->|One| E[➕ Set dj-store<br>automatically]:::add
  C -->|Several| F[🧾 Show store<br>selection screen]:::update
  F --> E
  E --> G[📦 Pick a store view<br>from storeViews]:::read
  G --> H[✅ Session opened<br>on the right store]:::place

  style A rx:8,ry:8
  style B rx:8,ry:8
  style C rx:8,ry:8
  style D rx:8,ry:8
  style E rx:8,ry:8
  style F rx:8,ry:8
  style G rx:8,ry:8
  style H rx:8,ry:8

Common mistakes

MistakeSymptomFix
Calling the authenticated-user route before choosing a store403Call GET /v1/shop/stores first — it needs no dj-store
Sending dj-client: OPERATOR on STORE-550403The route is reserved to dj-client: ACCOUNT
Expecting a filter to reveal an unattached storeThe store is missing from the responseFilters narrow the user's perimeter, they never widen it
Treating an empty list as an errorThe selection screen breaksAn empty list with 200 means "attached to no store" — handle it as a functional case
Confusing storeLocales and storeViewsWrong dj-store-view sentLocales are languages, store views are browsing contexts

Custom fields on a store

Custom fields can be attached to the STORE target to extend a store with your own business data (a country code, an ERP reference, a go-live date…).

Their values are consulted and edited directly from the store detail page in the Back-Office, in a dedicated section aligned with the one already available on accounts, users, suppliers, offers, orders and quotes. Each value is presented in the input matching its type: TEXT, LONG_TEXT, DATE, BOOLEAN, NUMBER, LIST_TEXT.

Behaviour to keep in mind:

  • Clearing a value and saving deletes that value.
  • Saving the form without touching the custom fields leaves the existing values untouched.
  • If no custom field is configured on the STORE target, the section is not displayed at all.
  • The rest of the store detail page — general information, store views, locales, tax mode — is unchanged.

On the API side, values are read and written through the customFieldValues field already exposed by the store contract. No dedicated endpoint is needed.

✅

Tip: An integration can keep feeding store custom fields through the API, and an operator can still check or correct a value from the Back-Office without any technical intervention.

See Custom fields for how to create and configure them.


Did this page help you?