Crystallize has four APIs a frontend could call, and a storefront needs two of them. This page gives the rule, the credential each API takes and where it may run, and a table of the common storefront tasks with the API and call for each.
publicationState: draft, and it is eventually consistent (see Caching and revalidation).priceFor(customerIdentifiers) resolves it on the server. Everything else it does, Discovery does too.Every build that called Core from a page ran into rate limits or slow pages. Carts, orders, customers and subscription contracts belong on the Shop API, which is edge-distributed and syncs to Core in the background. If a page seems to need Core, the data is usually in Discovery already, or it belongs in a back-office tool.
API | Endpoint | Credential | From the browser? |
|---|---|---|---|
Discovery |
| None when open (the default). When restricted, the static token in | Yes, if it is open. Then everything it serves is public, including every price variant, every market price and every draft. |
Shop API |
| A JWT from | No. Call it from your server. |
Catalogue |
| Open, static token or token pair, depending on the tenant setting | Server, for contract prices |
Core |
| Access token pair | Never |
The server exchanges the access token pair for a JWT, with one scope per route it calls: cart, order, customer, subscription-contract, booking, lock, and the matching :admin scopes for admin routes. See Shop API: Authentication for the request.
{ "success": false } and no errors list, so handle the status code.subscription-contract scope on a token of its own.The Shop API also reads products from the Catalogue with the request's credentials. If your Catalogue API is not open, send its credentials on every Shop API call as well.
Task | API | Call |
|---|---|---|
Item by path (product, category, article) | Discovery |
|
Category listing | Discovery |
|
Facets and filters | Discovery |
|
One card per colour on a listing | Discovery |
|
Variant pick on the product page | Discovery |
|
Search results and typeahead | Discovery |
|
Translated paths and hreflang | Discovery | One aliased query per language by |
Draft preview for editors | Discovery |
|
List price, sale price, price tiers | Discovery |
|
Public market price | Discovery |
|
Contract price for a signed-in buyer | Shop API or Catalogue | A cart hydrated with the customer, or Catalogue |
Stock on the page | Discovery |
|
Personal ranking, "more like this" | Discovery |
|
Create or change the cart | Shop |
|
Price the cart for the customer and market | Shop |
|
Lock the cart before payment | Shop |
|
Order from the cart | Shop |
|
Order without a cart (accepted quote, point of sale) | Shop |
|
Record payments, move through stages | Shop |
|
Shopper's order history | Shop |
|
Booking availability, hold, confirm | Shop |
|
Cache revalidation on publish | Core (setup) | A webhook on |
Seeding, model changes, publishing, imports | Core, mass operations | Scripts only. See Mass operations. |
The Shop API keeps its own order store, which syncs to Core. Changes made in Core come back in a way that can duplicate or overwrite a Shop API order. If your storefront lists orders through the Shop API, create and change them through the Shop API too: createFromCart, create, setMeta, addToStage. Keep Core order mutations for orders no storefront reads, such as an import into a back office.
When Discovery is open, anyone who knows your tenant identifier can read every price variant and every market's price list. Contract prices and markets created for a single customer don't belong there. Resolve them on the server through the Shop API or the Catalogue API, and cache them per organisation. Drafts are public too: publicationState: draft needs no credentials on an open Discovery. If drafts must stay private, restrict Discovery and send the static token from your server, and don't keep confidential or embargoed content in drafts on an open tenant.