Authentication and scope
How each request learns who the customer is and which store, branch and theme version it is for, and what that means for your query keys.
Read this when a call fails for a signed-in customer, or returns data for the wrong branch. An answer from the Store API depends on five things: the store, the customer, the branch, the theme version and the currency. The client attaches all five itself. This page shows where each comes from, so you know when you still have to act.
The customer: the token
The client finds the customer's token and adds Authorization: Bearer <token>. It looks in the twilight context first, then on the server in the request's token cookie, and in the browser in the token cookie, salla.storage and the SDK's own client (where a webview ?token= lands). For a guest it finds none and leaves the header off. You never read or pass the token yourself.
Do not copy the token from the context yourself
getTwilightContext().authToken can be null while the cookie still holds the token, so a header you build from it can wrongly send a signed-in customer as a guest. Let the client add the header, and use useUser().isLoggedIn to decide whether to call.
Skip calls that need a login
useUser() returns isLoggedIn. Use it to skip a call that only works for a signed-in customer:
import { useQuery } from '@tanstack/react-query';
import { api } from '@salla.sa/twilight-theme-engine/api/client';
import { useUser } from '@salla.sa/twilight-theme-engine/hooks/useUser';
export function MyOrders() {
const { isLoggedIn } = useUser();
const orders = useQuery({
queryKey: ['orders'],
queryFn: () => api.get('orders').json(),
enabled: isLoggedIn, // no token, no call, no `token_not_provided` error
});
return orders.isSuccess ? <p>Loaded</p> : null;
}The branch: scope
When the customer has chosen a market and branch, the client sends up to four headers: s-scope-id, s-scope-type, s-scope-allocation-type and s-scope-allocation-id. The API resolves stock and price per branch. You do not set these.
Query keys must include the scope
TanStack Query decides "have I fetched this already?" from the key alone. If the key ignores the branch, a response fetched for branch A is a cache hit for branch B, and the customer switches branch but still sees A's stock.
The engine's modules put the scope in the keys where it matters (product, category list, home, wishlist, store), so use their queries.* for anything that varies by branch. Each module page lists its keys. For your own endpoint, see Write your own endpoint.
The store
The client resolves store-identifier and adds it only if you did not set one. When you already know which store you mean, name it on the request so the one you checked is the one sent:
await api.get('products', {
headers: { 'store-identifier': identifier },
});The theme version
s-version-id says which version of the theme settings the answer is for. A version named by the request (the theme editor preview or your local dev server) wins. Otherwise the client uses the version the loaded settings report, but only while the active scope is the one those settings were requested for. If there is neither, as on the very first settings call or right after the customer switches market, the header is left off and the API picks the version.
The currency
When the customer picked another currency, the SDK stores it in the s-curr cookie and the client sends it as the currency header, so prices come back converted. Read the same value with getActiveCurrency(), for example to label a converted price.
Next
- Errors, timeouts and retries: what failure looks like, including
token_not_provided. - Salla SDK and events: the SDK that holds the session in the browser.
- Languages and RTL: where the locale comes from.
useStore: read the store settings in a component.