Storefront API v3 membantu Anda membangun UI storefront sendiri, sementara Scalev menangani katalog, cart, checkout, akun customer, lokasi pengiriman, order, dan instruksi payment. Gunakan halaman ini sebagai panduan implementasi lengkap A-Z setelah Anda memahami overview Storefront API, model auth, alur checkout, dan event konversi iklan opsional.
Storefront API v3 bisa di-host sebagai frontend statis, misalnya di Cloudflare Pages, Vercel, Netlify, atau CDN lain, tanpa membuat backend custom atau proxy same-origin. Frontend memanggil https://api.scalev.com secara langsung.
Panggil Storefront API v3 langsung dari browserStorefront API v3 dirancang untuk dipanggil langsung dari browser atau client end-user. Jangan menaruh Storefront API v3 di balik backend proxy, reverse proxy, middleware, edge function, serverless function, atau pass-through API layer milik Anda sendiri.Rate limiter untuk Storefront API v3 sengaja dibuat ketat karena API ini dirancang untuk penggunaan client-side langsung. Jika request ini diproxy, banyak user dapat terlihat datang dari IP server yang sama, sehingga rate limiting, deteksi spam, proteksi order duplikat, dan logika validasi lain dapat terdampak negatif.Untuk deployment headless storefront, anggap browser sebagai caller yang dimaksud untuk Storefront API v3. Gunakan backend Anda sendiri hanya untuk hal non-Scalev seperti admin settings, custom business logic, atau private integrations.
Arsitektur
Gunakan aturan ini untuk frontend storefront:
- Gunakan
unique_id store di URL runtime storefront publik.
- Gunakan storefront public API key yang publishable di kode frontend.
- Kirim key sebagai
X-Scalev-Storefront-Api-Key untuk endpoint /public/*.
- Kirim customer JWT sebagai
Authorization: Bearer <access> untuk endpoint /customers/me/*.
- Simpan dan kirim ulang
X-Scalev-Guest-Token untuk alur guest cart.
- Jangan expose business API key di kode frontend.
- Jangan membuat backend endpoint custom untuk katalog, cart, checkout, instruksi payment, pelacakan order, atau alur akun customer.
Semua path endpoint di bawah ini relatif terhadap:
https://api.scalev.com/v3/stores/{store_id}
Checklist setup
- Buat atau ambil storefront public API key.
- Daftarkan origin storefront, misalnya
https://demo.example.com, sebagai allowed origin.
- Konfigurasikan frontend dengan:
SCALEV_API_BASE=https://api.scalev.com
SCALEV_STORE_UNIQUE_ID=<store_unique_id>
SCALEV_STOREFRONT_API_KEY=<publishable_storefront_key>
- Serve frontend dari origin yang sudah didaftarkan.
- Buat panggilan API langsung dari browser.
- Jika storefront menjalankan iklan, pasang browser pixel dan event konversi server Scalev dengan event ID yang sama. Lihat Event konversi iklan.
Runtime Storefront memakai unique_id store. Endpoint setup Storefront API adalah endpoint bisnis terautentikasi. Endpoint setup bisa menerima numeric store ID lama untuk kompatibilitas, tetapi frontend storefront sebaiknya dikonfigurasi dengan unique_id store.
Helper fetch minimal
Gunakan satu helper untuk route storefront publik anonim:
const API_BASE = "https://api.scalev.com";
const STORE_ID = "store_xxx";
const STOREFRONT_KEY = "sfpk_xxx";
async function storefrontFetch(path: string, init: RequestInit = {}) {
const headers = new Headers(init.headers);
headers.set("Accept", "application/json");
headers.set("X-Scalev-Storefront-Api-Key", STOREFRONT_KEY);
return fetch(`${API_BASE}/v3/stores/${STORE_ID}${path}`, {
...init,
credentials: "omit",
headers,
});
}
Gunakan helper lain untuk route customer yang sudah login:
async function customerFetch(
path: string,
accessToken: string,
init: RequestInit = {}
) {
const headers = new Headers(init.headers);
headers.set("Accept", "application/json");
headers.set("Authorization", `Bearer ${accessToken}`);
return fetch(`${API_BASE}/v3/stores/${STORE_ID}${path}`, {
...init,
credentials: "omit",
headers,
});
}
Simpan guest cart token dari response guest cart pertama:
const response = await storefrontFetch("/public/cart");
const guestToken = response.headers.get("x-scalev-guest-token");
if (guestToken) {
localStorage.setItem("scalev_guest_token", guestToken);
}
Kirim ulang guest token pada panggilan guest cart dan guest checkout berikutnya:
const headers = new Headers({
"Content-Type": "application/json",
});
const guestToken = localStorage.getItem("scalev_guest_token");
if (guestToken) {
headers.set("X-Scalev-Guest-Token", guestToken);
}
await storefrontFetch("/public/cart/items", {
method: "POST",
headers,
body: JSON.stringify({
type: "variant",
variant_id: 494535,
quantity: 1,
}),
});
Alur katalog
Gunakan urutan katalog ini:
GET /public/items/count
GET /public/items
- Gunakan
entity_type untuk membedakan:
product
bundle_price_option
- Untuk detail product, panggil
GET /public/products/{slug}.
- Untuk detail bundle price option, panggil
GET /public/bundle-price-options/{slug}.
- Untuk harga variant, panggil
GET /public/variants/pricing?ids=....
- Untuk availability, panggil
GET /public/variants/{variant_id}/availability.
Gunakan variant_id untuk product variant. Gunakan bundle_price_option_id untuk bundle price option. Keduanya bisa dimasukkan ke payload cart dan checkout dengan typed item union.
Shape item checkout
Gunakan shape ini untuk product variant:
{
"type": "variant",
"variant_id": 494535,
"quantity": 1
}
Gunakan shape ini untuk bundle price option:
{
"type": "bundle_price_option",
"bundle_price_option_id": 31925,
"quantity": 1
}
Alur guest cart dan guest checkout
Gunakan alur ini untuk buyer anonim:
GET /public/cart
- simpan
x-scalev-guest-token
POST /public/cart/items
PATCH /public/cart/items/{item_id}
DELETE /public/cart/items/{item_id}
POST /public/checkout/shipping-options
POST /public/checkout/summary
POST /public/checkout
GET /public/orders/{secret_slug}
POST /public/orders/{secret_slug}/payment
Perilaku sumber checkout:
- Jika
items dikirim, order dibuat dari direct items.
- Jika
items tidak dikirim, order dibuat dari guest cart yang direferensikan oleh X-Scalev-Guest-Token.
- Jika direct
items dan X-Scalev-Guest-Token sama-sama dikirim, direct items menjadi sumber dan guest cart dikosongkan setelah order berhasil dibuat.
Alur auth customer
Panggil:
Jika response berisi access dan refresh, login selesai.
Jika response adalah OTP challenge, tampilkan input OTP dan panggil:
POST /public/auth/otp/verify
Penanganan token:
- Simpan
access untuk panggilan customer terautentikasi.
- Simpan
refresh jika Anda membuat sesi persisten.
- Refresh token hanya bisa dipakai satu kali.
- Setelah memanggil refresh, buang refresh token lama dan simpan refresh token baru.
- Logout memakai
POST /public/auth/jwt/blacklist.
Blacklist token customer dengan:
{
"tokens": ["<access>", "<refresh>"]
}
Alur akun customer
Gunakan endpoint customer ini sesuai urutan UI akun:
GET /customers/me
PATCH /customers/me
POST /customers/me/set-new-password
GET /customers/me/addresses
POST /customers/me/addresses
GET /customers/me/addresses/{address_id}
PATCH /customers/me/addresses/{address_id}
DELETE /customers/me/addresses/{address_id}
Alur customer cart dan checkout
Gunakan alur ini untuk customer yang login:
GET /customers/me/cart
POST /customers/me/cart/items
PATCH /customers/me/cart/items/{item_id}
DELETE /customers/me/cart/items/{item_id}
GET /customers/me/checkout/addresses
GET /customers/me/checkout/payment-methods
POST /customers/me/checkout/shipping-options
POST /customers/me/checkout/summary
POST /customers/me/checkout
GET /customers/me/orders
GET /customers/me/orders/{id}
Perilaku sumber customer checkout:
- Jika
items dikirim, order dibuat dari direct items.
- Jika
items tidak dikirim, cart_id memilih sumber customer cart.
- Jika
items dan cart_id sama-sama dikirim, direct items menjadi sumber dan cart yang direferensikan dikosongkan setelah order berhasil dibuat.
Alur lokasi
Gunakan salah satu pola pemilihan lokasi yang didukung.
Pola A:
- Pilih provinsi:
GET /public/locations/provinces
- Pilih kota:
GET /public/locations/cities?province_id=...
- Pilih subdistrict:
GET /public/locations/subdistricts?city_id=...
- Kode pos:
GET /public/locations/{location_id}/postal-codes
Pola B:
- Search langsung:
GET /public/locations?search=...
- Gunakan location atau subdistrict yang dikembalikan.
- Kode pos:
GET /public/locations/{location_id}/postal-codes
Response lokasi hanya menyertakan field yang dibutuhkan untuk tampilan dan request berikutnya:
{
"province_id": 31,
"province_name": "DKI Jakarta"
}
{
"city_id": 3171,
"city_name": "Kota Jakarta Pusat"
}
{
"id": 9090,
"subdistrict_name": "Gambir",
"city_name": "Kota Jakarta Pusat",
"province_name": "DKI Jakarta",
"display": "Gambir, Kota Jakarta Pusat, DKI Jakarta"
}
{
"postal_code": "10110"
}
Alur reset password
Implementasikan reset password sebagai alur link di browser:
- User memasukkan email.
- Frontend memanggil
POST /public/auth/forget-password.
- Scalev mengirim link email ke
/reset-password?token=<reset-token>.
- Frontend membaca
token dari URL.
- User memasukkan password baru dan konfirmasi.
- Frontend memanggil
POST /public/auth/save-password.
Jangan tampilkan input token reset manual. Frontend tidak boleh meminta user copy dan paste reset token. Hostname reset dipilih dari registered allowed origin saat request menyertakan Origin.
Rendering payment
Gunakan field order ini untuk merender halaman payment:
product_price
product_discount
shipping_cost
shipping_discount
other_income
gross_revenue
payment_method
sub_payment_method
payment_account_holder
payment_account_number
payment_url
pg_payment_info
store.payment_accounts
handler_phone
chat_message
Manual bank transfer bisa memakai store.payment_accounts saat tidak ada akun spesifik pada order. Metode hosted atau provider-backed bisa memakai payment_url atau pg_payment_info. gross_revenue adalah jumlah yang dibayar buyer.
Lihat Checkout dan Payment untuk aturan rendering per metode.
Subscription customer dan course
Untuk halaman akun customer, gunakan:
GET /customers/me/subscriptions
GET /customers/me/subscriptions/{id}
POST /customers/me/subscriptions/{id}/cancel
POST /customers/me/subscriptions/{id}/resume
GET /customers/me/subscription-items/{id}/upgrade
POST /customers/me/subscription-items/{id}/upgrade
GET /customers/me/subscription-items/{id}/downgrade
POST /customers/me/subscription-items/{id}/downgrade
GET /customers/me/variants/{uuid}/course
GET /customers/me/course-sections/{uuid}
GET /customers/me/course-contents/{uuid}
PATCH /customers/me/course-contents/{uuid}
Endpoint course bergantung pada entitlement. Response 403 atau 404 bisa berarti customer tidak memiliki variant course tersebut, bukan berarti integrasi storefront rusak.
Payload checkout lengkap minimal
Gunakan payload checkout variant lengkap seperti:
{
"items": [
{
"type": "variant",
"variant_id": 494535,
"quantity": 1
}
],
"customer_name": "Demo Customer",
"customer_email": "demo.customer@example.com",
"customer_phone": "6281234567890",
"shipping_address": "Jl. Demo Storefront API No. 3",
"shipping_province": "DKI Jakarta",
"shipping_city": "Kota Jakarta Pusat",
"shipping_subdistrict": "Cempaka Putih",
"shipping_postal_code": "10510",
"shipping_location_id": 9089,
"payment_method": "bank_transfer"
}
Gunakan payload checkout bundle price option seperti:
{
"items": [
{
"type": "bundle_price_option",
"bundle_price_option_id": 31925,
"quantity": 1
}
],
"customer_name": "Demo Customer",
"customer_email": "demo.customer@example.com",
"payment_method": "bank_transfer"
}
Checklist agent
Implementasi lengkap saat bisa:
- menampilkan daftar item katalog
- menampilkan detail product
- menampilkan detail bundle price option
- mengecek pricing dan availability
- menyimpan guest cart dengan
X-Scalev-Guest-Token
- menambah, mengubah, dan menghapus item cart
- memilih lokasi pengiriman
- menghitung shipping options dan checkout summary
- membuat public checkout order
- menampilkan status public order dan instruksi payment
- membuat atau mengambil instruksi payment
- login customer dengan branch direct-token atau OTP
- refresh dan blacklist JWT
- mengelola profil dan alamat customer
- memakai customer cart
- membuat authenticated checkout order
- menampilkan daftar dan detail authenticated order
- menampilkan subscription dan course entitlement-gated saat ada
- melakukan semua hal di atas dari frontend tanpa backend custom