Skip to content
Twilight React Playground
ثيم رائدaren

api

objectAdvancedserverbrowserlive demo

The HTTP client behind every engine API module: ky, pointed at the Salla Store API, adding store, language, version, token and branch headers.

import { api } from '@salla.sa/twilight-theme-engine/api/client';

In plain words

api is like fetch, but it already knows where the Salla Store API lives and who is asking. api.get('categories') calls https://api.salla.dev/store/v1/categories and adds which store you mean, the page language, and the customer's login token when there is one. .json() turns the answer into a plain object.

Use it for an endpoint no engine module wraps yet. Every answer comes wrapped: what you want is under data.

Signature

const api: KyInstance
// ky.extend({ prefix: 'https://api.salla.dev/store/v1', timeout: 8000, hooks: { beforeRequest } })

api.get(path, options?).json<T>(): Promise<T>
api.post(path, { json }), api.put(path), api.delete(path)

// Set before every request:
// accept, accept-language (page locale), s-app-os, s-app-version, s-ray, s-source,
// s-theme-type: react, s-store-api-version, x-requested-with, s-cf-proxy-whitelist-id
// store-identifier                 unless the request already has one
// s-version-id                     when a theme version resolves
// Authorization: Bearer <token>    when a customer token exists
// s-scope-id, s-scope-type, s-scope-allocation-type, s-scope-allocation-id   when a branch is selected

Try it live

The raw HTTP client every engine module uses, calling the demo store directly. Headers are added for you.Try this: pick auth/user: a customer-only endpoint answers a guest with HTTP 400 and code token_not_provided, not 401.
Storefront canvas · en · LTR

GET https://api.salla.dev/store/v1/categories

Controls
What a theme writes
import { api } from '@salla.sa/twilight-theme-engine/api/client';

export async function load() {
  // GET https://api.salla.dev/store/v1/categories
  // store-identifier, language, version, token and scope headers are added for you.
  const { data } = await api.get('categories').json<{ data: unknown }>();
  return data;
}

Example

app/components/account/vouchers.ts
import { api } from '@salla.sa/twilight-theme-engine/api/client';

interface Voucher {
  code: string;
  quantity_remaining: number;
}

/** The customer's vouchers: an endpoint no engine module wraps. */
export async function getVouchers(): Promise<Voucher[]> {
  const body = await api
    .get('coupons?is_voucher=1&include_quantity_orders=1')
    .json<{ data?: Voucher[] | null }>();
  return body.data ?? [];
}

How it behaves

  • It is a ky v2 instance. prefix joins with a slash, so 'categories' and '/categories' reach the same URL.

  • A non-2xx answer throws HTTPError: the status is error.response.status, and ky has already parsed the body onto error.data. await error.response.json() does not work, because ky consumed the body.

  • ky retries a GET up to 2 more times on 408, 413, 429, 500, 502, 503 and 504, each attempt with its own 8 s timeout. Inside useQuery, the engine QueryClient adds 1 retry on top.

  • The token comes from the twilight context, then from the token cookie (the request cookie on the server; document.cookie, Salla.storage or the SDK in the browser). See getAuthToken.

  • Customer-only endpoints answer a guest with HTTP 400 and error.code token_not_provided, not 401 (orders, auth/user, notifications and balance/points on the demo store).

Gotchas

  • The base URL is fixed. The docblock describes a VITE_API_URL override, but that line is commented out in client.ts: setting the variable changes nothing.

  • src/api/README.md shows api.get('custom-endpoint', { locale } as any). There is no locale option: the language header always comes from the page being rendered.

  • Nothing unwraps the envelope for you: api.get(path).json() resolves { status, success, data, cursor? }. A request can also fail with HTTP 200: given a bad cursor, the demo store answered 200 with an error and no data. Read data, and check it exists.

Related

Source and docs