Settings Module — Storefront
HTTP surface for the storefront to read public, platform-wide settings (branding, contact details, currency hints, store toggles, etc.). The whole storefront-public configuration…
HTTP surface for the storefront to read public, platform-wide settings (branding, contact details, currency hints, store toggles, etc.). The whole storefront-public configuration is keyed by a registry that flags each setting as either public: true (exposed here) or admin-only (never exposed here, regardless of group).
Source:
api-modules/settings/src/controllers/store-settings.controller.ts.Admin and vendor settings (key registration, scoped overrides, secrets) live in sibling docs.
Conventions
Authentication
| Endpoint | Auth |
|---|---|
GET /store/settings | none (public) |
GET /store/settings/payment | none (public) |
GET /store/settings/:group | none (public) |
GET /store/settings/:group/:key | none (public) |
There is no auth on this surface — the only safety is the registry's public flag. Keys without that flag are never exposed here. Unknown groups and keys deliberately return 404 rather than empty payloads so an attacker can't probe for the existence of admin-only configuration.
The one exception is the derived payment group (and its dedicated GET /store/settings/payment route): it is not registry-backed but a curated read exposing only the publishable Razorpay key id — the same value already shipped to the SDK on every payment. Never the key secret or webhook secret.
Response envelope
{
"data": <payload>,
"message": "Success",
"statusCode": 200
}Error envelope
statusCode | errorCode examples |
|---|---|
| 404 | NOT_FOUND |
| 500 | INTERNAL_SERVER_ERROR, DATABASE_ERROR |
Domain types
ScopeSettingsResponse
/** Full-scope response — nested by group, with unknown-typed values. */
type ScopeSettingsResponse = Record<string, Record<string, unknown>>;GroupSettingsResponse
/** Single-group response — flat key→value. */
type GroupSettingsResponse = Record<string, unknown>;SettingValueResponse
/** Single-key response — uniform { value } wrapper regardless of underlying type. */
type SettingValueResponse = { value: unknown };Consumers narrow on known keys at the call site; the response surface keeps unknown because typing every key would drift as the registry evolves.
Endpoints
GET /store/settings — All public settings
Returns the entire public storefront configuration as { <group>: { <key>: <value> } }. Use this for the initial app bootstrap so the storefront has a consistent snapshot of branding, currency, etc. Admin-only keys are filtered out at the service layer.
Response 200
{
"data": {
"store_config": {
"currency_name": "INR",
"currency_symbol": "₹"
},
"branding": {
"name": "Example Shop",
"logo_url": "branding/logo-abc.png", // storage key — prefix NEXT_PUBLIC_ASSETS_URL to render
"favicon_url": "branding/favicon.png",
"footer_logo": "branding/footer-logo.png"
},
"contact": {
"email": "help@example.com",
"phone": "+91 90000 00000"
},
"seo": {
"site_title": "Example Shop",
"meta_title": "{page} — Example Shop",
"meta_description": "Shop the best of Example.",
"og_image": "seo/og-default.png", // storage key
"twitter_card": "summary_large_image",
"organization": {
"name": "Example Shop",
"url": "https://shop.example.com",
"same_as": ["https://instagram.com/example"]
},
"breadcrumbs": [{ "name": "Home", "url": "/" }]
}
},
"message": "Success",
"statusCode": 200
}Asset values are storage keys, not URLs.
branding.logo_url,branding.favicon_url,branding.footer_logo,seo.og_image, andorganization.logostore an opaque object key (e.g.branding/logo-abc.png). The storefront renders them by prefixingNEXT_PUBLIC_ASSETS_URL.
Public storefront groups
| Group | Keys (selected) |
|---|---|
store_config | currency_name (e.g. INR), currency_symbol (e.g. ₹) — used to render money across the storefront and admin panel |
branding | name, logo_url, favicon_url, footer_logo |
contact | email, phone |
seo | site_title, site_description, meta_title, meta_description, meta_keywords, canonical_base_url, robots, og_title, og_description, og_image, twitter_card, twitter_handle, organization (schema.org Organization), breadcrumbs (schema.org BreadcrumbList) |
storefront_urls | store_url (storefront base, e.g. https://shop.example.com), content_page_path, product_path, category_path, brand_path, product_tag_path, ingredient_path, vendor_path — each path carries a :slug placeholder; defaults mirror the live storefront routes. Used by the dashboards to build "open on store" links |
sold_last_month | enabled only — whether product pages show a "sold last month" count (see Product Sold Metrics). The render_rules key in this group is admin-only and never exposed here. |
product_cart | buy_now_enabled — whether the product page shows Buy Now. show_stock_quantity — whether stock.availableQuantity carries a number on GET /store/products/:slug (the count is withheld server-side when false, so this key is informational for the storefront, not the gate). The low_stock_threshold key in this group is admin-only. |
back_in_stock | enabled, guest_enabled — whether to offer "notify me" on a sold-out variant, and whether a shopper without an account may use it (see Back in Stock). The max_active_per_email and expiry_days keys in this group are admin-only. |
payment | razorpay → { keyId } (derived — see below) |
GET /store/settings/payment — Publishable payment config
The publishable Razorpay key id, so the storefront or a mobile app (Flutter / Android / iOS) can initialise the Razorpay SDK from a single anonymous fetch — no admin token, no checkout round-trip. The same object is included under the payment group of GET /store/settings.
Only the publishable key is exposed; key_secret and webhook_secret are never returned. Which Razorpay flows (standard / Magic) are live is read separately from the per-platform enabled-providers settings, so it is intentionally not duplicated here.
Response 200
{
"data": {
"razorpay": {
"keyId": "rzp_test_xxxxxxxx" // "" when unset
}
},
"message": "Success",
"statusCode": 200
}GET /store/settings/:group — Public settings for one group
Returns the flat { <key>: <value> } map for a single group. The whole group must contain at least one public key — a group whose keys are all admin-only returns 404.
Path params
| Name | Notes |
|---|---|
group | Group identifier (e.g. branding, contact, commerce). Case-sensitive. |
Response 200
{
"data": {
"logo_url": "https://cdn.example/logo.png",
"store_name": "Example Shop"
},
"message": "Success",
"statusCode": 200
}Errors
| Status | Code | When |
|---|---|---|
| 404 | NOT_FOUND | Group has no public keys registered (either the group doesn't exist or every key in it is admin-only) |
GET /store/settings/:group/:key — Single public setting
Returns { value: <unknown> } for a single key.
Path params
| Name | Notes |
|---|---|
group | Group identifier |
key | Setting key within the group |
Response 200
{
"data": { "value": "https://cdn.example/logo.png" },
"message": "Success",
"statusCode": 200
}Errors
| Status | Code | When |
|---|---|---|
| 404 | NOT_FOUND | Key is not registered, or is not flagged public |
Related modules
- Admin / vendor settings surfaces — share the same underlying
SettingsService, but expose admin- and vendor-scoped registry keys. Seedocs/separated/admin/settings.mdanddocs/separated/vendor/settings.md.
Serviceability Module — Storefront
Ask whether the store delivers to a pincode before the shopper commits to it. Returns the operator's own message plus whether it is a soft warning or a hard block, so the PDP and checkout can render either.
Shipping Module — Storefront
HTTP surface for customer-side shipment tracking — the timeline of provider-emitted events for a sub-order the customer placed. Read-only.