> ## Documentation Index
> Fetch the complete documentation index at: https://docs.scalev.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Auth

> Gunakan Storefront API key, guest cart token, dan customer JWT dari storefront browser.

Storefront API memakai tiga lapisan identitas yang aman untuk browser:

* `X-Scalev-Storefront-Api-Key` mengidentifikasi store dan mengizinkan route public storefront anonim.
* `X-Scalev-Guest-Token` mempertahankan guest cart yang sama setelah reload halaman.
* `Authorization: Bearer <customer_access_token>` mengautentikasi customer yang sudah login pada `/customers/me/*`.

Tiga lapisan ini sengaja dipisah. Storefront API key bersifat publishable dan memilih storefront. Header ini bukan otorisasi akun.

## Storefront API key

Storefront API key yang valid hanya membuka akses runtime saat bisnis memiliki paket aktif Basic, Pro, atau Ultimate. Bisnis Free, Lite, tidak aktif, atau belum dibayar tetap bisa mengatur key dan allowed origin, tetapi panggilan Storefront API public akan mengembalikan response `Store not found` yang sama seperti store tidak ditemukan atau key tidak valid.

Route public storefront memerlukan:

```text theme={null}
X-Scalev-Storefront-Api-Key: sfpk_...
```

Gunakan header ini pada route Storefront API anonim di:

```text theme={null}
/v3/stores/{store_id}/public/*
```

Jangan gunakan business API key di JavaScript browser. Business API key adalah credential rahasia untuk integrasi server-side dan flow setup dashboard.

## Guest cart token

Route guest cart mengembalikan dan menerima:

```text theme={null}
X-Scalev-Guest-Token: 7e7f8c12-2e1d-4b31-97ad-5ca4f8d1c2d0
```

Anda mendapatkan token ini dari response guest cart pertama. Panggil `GET /public/cart` atau `POST /public/cart/items` tanpa guest token, lalu baca `X-Scalev-Guest-Token` dari response header.

```js theme={null}
const response = await fetch(
  `https://api.scalev.com/v3/stores/${storeId}/public/cart`,
  {
    credentials: "omit",
    headers: {
      "X-Scalev-Storefront-Api-Key": storefrontApiKey,
    },
  }
);

const guestToken = response.headers.get("X-Scalev-Guest-Token");

if (guestToken) {
  localStorage.setItem("scalev_guest_token", guestToken);
}
```

Simpan guest token di browser storage dan kirim pada request cart dan checkout berikutnya:

```js theme={null}
const guestToken = localStorage.getItem("scalev_guest_token");

await fetch(`https://api.scalev.com/v3/stores/${storeId}/public/cart/items`, {
  method: "POST",
  credentials: "omit",
  headers: {
    "Content-Type": "application/json",
    "X-Scalev-Storefront-Api-Key": storefrontApiKey,
    ...(guestToken ? { "X-Scalev-Guest-Token": guestToken } : {}),
  },
  body: JSON.stringify({
    type: "variant",
    variant_id: 494535,
    quantity: 1,
  }),
});
```

Gunakan hanya `X-Scalev-Guest-Token`; `X-Guest-Token` bukan bagian dari kontrak Storefront API v3.

## Model auth customer

Auth customer anonim dimulai dari:

```text theme={null}
/v3/stores/{store_id}/public/auth/*
```

Route ini memerlukan `X-Scalev-Storefront-Api-Key` karena browser belum login.

Setelah login, route akun memakai customer JWT:

```text theme={null}
Authorization: Bearer <customer_access_token>
```

Gunakan customer JWT pada:

```text theme={null}
/v3/stores/{store_id}/customers/me/*
```

Route ini dibatasi oleh store pada path dan customer JWT. Storefront API key tidak diperlukan di sini karena header tersebut bukan mekanisme otorisasi akun.

Route customer order hanya mengembalikan data order yang layak dilihat customer yang sedang login: identity order, public link, timestamp status, field payment, total termasuk `gross_revenue`, destination address, shipment, data customer, dan order line. Route ini tidak mengembalikan analytics bisnis, net revenue, platform fee, provider internals, riwayat CRM, data affiliate, atau raw metadata. Response juga mempertahankan field yang dipakai Portal customer Scalev, termasuk `store.name`, `store.logo`, `store.unique_id`, flag tampilan store, `payment_accounts` store untuk instruksi manual bank transfer, `final_variants`, `status_history`, dan total tampilan dropshipper.

Access token dan refresh token customer adalah credential yang disimpan di browser. Gunakan Content Security Policy yang ketat, hindari script pihak ketiga yang tidak dipercaya, jaga dependency tetap terbaru, dan sanitasi HTML dari customer atau merchant sebelum dirender di storefront.

## Sign in

Mulai sign-in dengan:

```text theme={null}
POST /v3/stores/{store_id}/public/auth/login
```

Contoh body:

```json theme={null}
{
  "email": "customer@example.com",
  "password": "customer-password"
}
```

Jika store tidak mewajibkan OTP, response adalah `200` dengan token customer:

```json theme={null}
{
  "access": "eyJ...",
  "refresh": "eyJ...",
  "token_type": "Bearer",
  "expires_in": 900,
  "refresh_expires_in": 2592000
}
```

Jika store mewajibkan OTP, response adalah `200` dengan message. Tampilkan input one-time code lalu panggil:

```json theme={null}
{
  "message": "If this email exists in our system, an OTP has been sent to it."
}
```

```text theme={null}
POST /v3/stores/{store_id}/public/auth/otp/verify
```

Contoh body:

```json theme={null}
{
  "email": "customer@example.com",
  "otp": "123456"
}
```

OTP verification yang berhasil mengembalikan token customer:

```json theme={null}
{
  "access": "eyJ...",
  "refresh": "eyJ...",
  "token_type": "Bearer",
  "expires_in": 900,
  "refresh_expires_in": 2592000,
  "store_unique_id": "store_vlzpML8edzxO5roOdV7Oyfn6"
}
```

## Refresh token dan logout

Refresh session customer dengan:

```text theme={null}
POST /v3/stores/{store_id}/public/auth/jwt/refresh
```

```json theme={null}
{
  "refresh": "eyJ..."
}
```

Refresh token akan dirotasi setiap kali refresh dan hanya bisa dipakai sekali. Simpan nilai `refresh` baru dari response dan buang token lama. Jika refresh token yang sudah dirotasi dipakai ulang, seluruh token family dicabut dan customer harus sign in ulang.

Revoke token dengan:

```text theme={null}
POST /v3/stores/{store_id}/public/auth/jwt/blacklist
```

```json theme={null}
{
  "tokens": ["eyJ..."]
}
```

Response blacklist yang berhasil adalah `204` dengan body kosong.

## Reset password

Request email reset password dengan:

```text theme={null}
POST /v3/stores/{store_id}/public/auth/forget-password
```

```json theme={null}
{
  "email": "customer@example.com"
}
```

Untuk request Storefront API, link email reset password memakai kontrak URL ini:

```text theme={null}
http(s)://<allowed-storefront-host>/reset-password?token=<reset-token>
```

Host dan scheme berasal dari browser `Origin` yang sudah tervalidasi jika request berasal dari allowed origin Storefront API. Request tanpa header `Origin` fallback ke custom domain Storefront bawaan dan tetap memakai path `/reset-password?token=...`.

Simpan password baru dengan:

```text theme={null}
POST /v3/stores/{store_id}/public/auth/save-password
```

```json theme={null}
{
  "token": "reset-token-from-email",
  "password": "new-password"
}
```

## Rate limit

Route public Storefront API terkena rate limit sebagai request browser/client langsung, termasuk request yang mengirim `X-Scalev-Storefront-Api-Key` atau `X-Scalev-Guest-Token`. Request ini tidak memakai bucket rate limit machine API key atau OAuth app.
