API configuration and the Scalar playground

The API module comes with interactive documentation: Scalar, an OpenAPI playground in the browser where you can read every endpoint, authorise with a token and send real requests. There is one playground for each API - the Backend API (v1) for integrations and the Frontend API (v2) for headless and mobile frontends. This article explains the settings and walks through both.

The settings

All in App_Data/appsettings.json, or as environment variables (BackendAPI__SecretKey and so on).

"FeatureManagement": {
  "Grand.Module.Api": true
},
"BackendAPI": {
  "Enabled": true,
  "SecretKey": "at least 32 random characters",
  "ValidateIssuer": false,
  "ValidIssuer": "",
  "ValidateAudience": false,
  "ValidAudience": "",
  "ValidateLifetime": true,
  "ValidateIssuerSigningKey": true,
  "ExpiryInMinutes": 1440
},
"FrontendAPI": {
  "Enabled": true,
  "JsonContentType": false,
  "SecretKey": "another 32+ character secret",
  "ValidateIssuer": false,
  "ValidIssuer": "",
  "ValidateAudience": false,
  "ValidAudience": "",
  "ValidateLifetime": true,
  "ValidateIssuerSigningKey": true,
  "ExpiryInMinutes": 1440,
  "RefreshTokenExpiryInMinutes": 1440
},
"AllowedHostOrigins": [ "https://shop-frontend.example.com" ]
SettingWhat it does
FeatureManagement:Grand.Module.ApiLoads the API module at all. Off by default; restart after changing it.
EnabledSwitches each API on or off independently.
SecretKeySigns the tokens (HMAC-SHA256). Use a different key per API and per environment. Outside Development the application does not start while an enabled API has an empty key, the shipped placeholder, or one shorter than 32 characters. Changing it invalidates every issued token.
ExpiryInMinutesLifetime of an access token.
RefreshTokenExpiryInMinutesFrontend API only: how long a refresh token can be exchanged for a new access token.
ValidateIssuer + ValidIssuer, ValidateAudience + ValidAudienceWhen set, tokens are issued with this issuer/audience and only tokens carrying them are accepted - useful when several systems share a signing key.
ValidateLifetime, ValidateIssuerSigningKeyKeep both true. Turning them off accepts expired or forged tokens.
JsonContentTypeFrontend API: lets storefront actions bind request bodies sent as JSON (Content-Type: application/json) instead of form data.
AllowedHostOriginsOrigins allowed to call the API from a browser (CORS) in production. In Development every origin is allowed.
SystemModelPresent in the Backend API section but not used by the current code.

Where the playgrounds are

AddressWhat
/scalar/v1Scalar for the Backend API
/scalar/v2Scalar for the Frontend API
/openapi/v1.json, /openapi/v2.jsonThe OpenAPI 3.0 documents - import them into Postman, Insomnia or a client generator

They exist only when the application runs in the Development environment and the module and API are enabled. Use them on a development or staging copy; production does not publish the documents.

Backend API in Scalar (v1)

Scalar for the Grandnode Backend API v1 with the endpoint groups Brand, Category, Collection, Country, Customer and more in the sidebar, the Authentication box and client libraries
/scalar/v1 - the Backend API: one group per entity, with GET, POST, PUT, PATCH and DELETE.
  1. Create an API user under System → Developer tools → Manage API Users. Its e-mail must belong to an existing, active customer account with admin access; the API acts with that customer's permissions.
  2. In Scalar open Token → POST /Api/Token/Create and send { "email": "...", "password": "<password in Base64>" }. The response is the token as a JSON string.
  3. In the Authentication box choose Bearer and paste the token (without the quotes).
  4. Open, for example, Product → GET /api/Product, add query parameters and send:
    $top=2
    $select=Name,Price,Sku
    $orderby=Price desc
    $filter=Price > 300 and Name.Contains("Aurora")
    $filter uses C#-like expressions (==, >, and, or, Contains, StartsWith...), not OData words such as gt.

Scalar shows the request as code for many clients (C# HttpClient is the default, also cURL, JavaScript, Python, PHP...) - copy it into your integration.

Frontend API in Scalar (v2)

Scalar for the Grandnode Frontend API v2 with the Create token group (Guest, Login, Refresh, Antiforgery) and storefront groups such as Account, Catalog, Checkout and Order
/scalar/v2 - the Frontend API: the storefront's own actions, grouped by area.
  1. Get a token from Create token: POST /TokenWeb/Guest for an anonymous shopper, or POST /TokenWeb/Login with a customer's e-mail and Base64 password. The response contains AccessToken and RefreshToken.
  2. Put the AccessToken into Authentication → Bearer.
  3. Try a call, for example GET /Account/Info: it returns the signed-in customer's data as JSON. Without a token the same call returns 403.
  4. Operations in this document take an X-CSRF-TOKEN header: get its value from GET /TokenWeb/Antiforgery and send it with requests that change data.
  5. When the access token expires, call POST /TokenWeb/Refresh with both tokens.

The Frontend API is the storefront itself: the same controllers serve HTML to browsers and JSON to API clients, so whatever the storefront can do - catalog, cart, checkout, account, blog, knowledgebase - is in v2.

Tips

  • 401 everywhere: the module flag is off, the token was signed with another key, or it expired.
  • "User not exists or password is wrong": the password was not Base64-encoded, the API user is inactive, or there is no customer with that e-mail.
  • Keep the Scalar instance away from production data: it sends real requests.

Question not answered here? Ask the community on GitHub Discussions ↗