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" ]
| Setting | What it does |
|---|---|
FeatureManagement:Grand.Module.Api | Loads the API module at all. Off by default; restart after changing it. |
Enabled | Switches each API on or off independently. |
SecretKey | Signs 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. |
ExpiryInMinutes | Lifetime of an access token. |
RefreshTokenExpiryInMinutes | Frontend API only: how long a refresh token can be exchanged for a new access token. |
ValidateIssuer + ValidIssuer, ValidateAudience + ValidAudience | When set, tokens are issued with this issuer/audience and only tokens carrying them are accepted - useful when several systems share a signing key. |
ValidateLifetime, ValidateIssuerSigningKey | Keep both true. Turning them off accepts expired or forged tokens. |
JsonContentType | Frontend API: lets storefront actions bind request bodies sent as JSON (Content-Type: application/json) instead of form data. |
AllowedHostOrigins | Origins allowed to call the API from a browser (CORS) in production. In Development every origin is allowed. |
SystemModel | Present in the Backend API section but not used by the current code. |
Where the playgrounds are
| Address | What |
|---|---|
/scalar/v1 | Scalar for the Backend API |
/scalar/v2 | Scalar for the Frontend API |
/openapi/v1.json, /openapi/v2.json | The 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)

- 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.
- In Scalar open Token → POST /Api/Token/Create and send
{ "email": "...", "password": "<password in Base64>" }. The response is the token as a JSON string. - In the Authentication box choose Bearer and paste the token (without the quotes).
- 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")$filteruses C#-like expressions (==,>,and,or,Contains,StartsWith...), not OData words such asgt.
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)

- Get a token from Create token:
POST /TokenWeb/Guestfor an anonymous shopper, orPOST /TokenWeb/Loginwith a customer's e-mail and Base64 password. The response containsAccessTokenandRefreshToken. - Put the
AccessTokeninto Authentication → Bearer. - 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. - Operations in this document take an
X-CSRF-TOKENheader: get its value fromGET /TokenWeb/Antiforgeryand send it with requests that change data. - When the access token expires, call
POST /TokenWeb/Refreshwith 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.
Related
Question not answered here? Ask the community on GitHub Discussions ↗