Skip to content
DevelopersConfigurators (Beta)

Cart and server checks ​

The cart line of a configurator, what your server checks before it charges, and which websites can show iJewel's prices.

The cart line says exactly which piece the shopper built. It comes from the browser, so your server checks it before you charge. This page shows the cart line, the checks on your server, what happens when the author publishes again, and which websites can show iJewel's prices.

SDK version

This page describes the configurator SDK 0.1.0-dev.2 (see Headless SDK). The server calls run in Node 18 or later, or in any server JavaScript that has fetch.

The cart line ​

session.configuration() returns the cart line. Store it with the order: it says exactly which ring the shopper built.

json
{
  "schema": "ijewel.configuration/2.0",
  "configurator": "cfgEngagement01",
  "revision": 1,
  "title": "Ring",
  "state": "v2.r1.shape-round.carat-2-00-ct.centerStone-diamond.head-halo.shank-classic.shankMetal-14k-white-gold.headMetal-14k-white-gold",
  "selection": { "shape": "round", "carat": "2-00-ct", "centerStone": "diamond", "head": "halo", "shank": "classic", "shankMetal": "14k-white-gold", "headMetal": "14k-white-gold" },
  "derived": {},
  "labels": [
    { "axis": "shape", "label": "Shape", "option": "round", "value": "Round" },
    { "axis": "carat", "label": "Carat", "option": "2-00-ct", "value": "2.00 ct" }
  ],
  "tags": [],
  "specs": {},
  "parts": {
    "head": { "variant": "round.2-00-ct.halo", "sha256": "b47214cb…" },
    "shank": { "variant": "classic", "sha256": "d6ac24bd…" }
  },
  "sku": "ENG-RD-200-HL-CL-W14",
  "price": { "amount": 3398200, "currency": "USD", "minorUnits": 2 }
}
FieldWhat it is
configurator, revisionThe folder id and the published revision.
stateThe key to open the same ring again.
selectionAxis key → option key, for every visible axis.
derivedAxes that the author derives from the others, for manufacturing.
labelsThe text of each choice, in the session's locale (open({ locale })).
tags, specsThe author's public tags and specs of the picked options.
partsThe 3D file of each part, pinned by its sha256: what the ring is made from.
sku, priceOnly when the session has a price answer for this configuration: call await session.price() first, or use await session.requestCart(), which prices and returns the line.

What to check on your server ​

The cart line comes from the browser, so the shopper can change any field, the price too. Before you charge, check the line on your server with the same SDK (Node 18 or later, or any server JavaScript with fetch):

Step 1 of 5
  1. Read the folder that you sell with loadPublished({ drive, id }). Use your own Drive name and folder id, not the line's.
  2. Check the line with verifyConfiguration(folder, line). It refuses another configurator, a newer revision, and a state, selection, labels or parts that are not what the configurator gives. A line of an older revision passes when it is still the same ring (A line of an older revision).
  3. Take the labels and parts from check.configuration, not from the line.
  4. Compute the price again for check.configuration.state: your own price function, or iJewel's price service. The price service answers only an Origin header from the allowed origins, and a server's fetch sends none, so set one. That header is not a secret (Allowed origins for prices).
  5. Charge the price that you computed. When it is not the line's price, show the shopper the new price first.
js
import { loadPublished, verifyConfiguration, createSession, appPrice } from './configurator-sdk.mjs'

const folder = await loadPublished({ drive: 'drive', id: MY_FOLDER_ID })
const check = await verifyConfiguration(folder, line)
if (!check.ok) throw new Error(`cart line refused: ${check.problems.join(', ')}`)

const withOrigin = (url, init = {}) => fetch(url, { ...init, headers: { ...init.headers, Origin: 'https://shop.example' } })
const session = await createSession({ ...folder, state: check.configuration.state, providers: { price: appPrice(folder.priceUrl, folder.manifest, { fetch: withOrigin }) } })
await session.price()                    // asks the price service for check.configuration
const trusted = session.configuration()  // the cart line of check.configuration, with its sku and price

session.price() returns the price answer (total, currency, minorUnits, the lines). The cart line keeps the price as { amount, currency, minorUnits }, so take the line from session.configuration() after the price, not the answer itself.

check.problems names the fields that do not match, such as ['revision'] or ['selection', 'labels', 'parts'].

The price service does not sign its answers, and the SDK has no signed quotes. Your server asks for the price itself at checkout, as above.

A line of an older revision ​

The author can publish the configurator again while a ring sits in a shopper's cart. The line then names an older revision. Option keys never change their meaning from one revision to the next, so verifyConfiguration checks the line against the current revision:

  • The same ring: every choice of the line is still there. The check passes, and check.migratedFrom is the line's revision. check.configuration is the ring in the current revision, with its current labels, files and state. Price it as above: the price can be new.
  • Another ring: the publish removed a choice of the line, added a choice, changed a rule that the ring follows, or made the ring impossible to build. The check fails with revision. Open the line's state in a new session (open({ …, state })), which moves it to the current revision, and ask the shopper to confirm the new ring and its price.

A line of a newer revision than the folder that you read also fails with revision: read the folder again.

Allowed origins for prices ​

iJewel's price service answers only pages on the configurator's allowed origins:

  • iJewel's own pages: https://ijewel3d.com and its subdomains, where the shared links and the embeds open;
  • every domain that is registered and active in the author's Drive (Settings › Apps, embed and API › Domains). This part of the list is set when the author publishes the configurator in the Drive.

To show iJewel's prices on your shop:

  1. Register your shop domain in the Drive, for example https://shop.example.com.
  2. Publish the configurator again. A domain that you add later reaches the list only with the next publish.

The page's origin must match exactly: https://www.shop.example.com and https://shop.example.com are two origins. Only https origins go on the list, so a page on http://localhost gets no iJewel price (E_PRICE). Your own price function needs no list: it runs on your page and asks your server.

The list is a gate for web pages, not a sign-in. A browser always sends the page's true origin, so the list decides which websites can show iJewel's prices. A program outside a browser can send any Origin header, so the list keeps no price secret. It does not need to: a price is what every shopper of the configurator sees. Your server trusts a price because it asks iJewel's price service itself over HTTPS, not because of the header. The daily request limit (below) protects the price service.