HTML Mode runtime
Use the window.Scalev runtime methods available inside Scalev HTML Mode pages.
Scalev HTML Mode pages can use window.Scalev from browser JavaScript. The runtime gives your page safe page context, selected store context, checkout helpers, analytics forwarding, form prefill helpers, and diagnostics while keeping private API tokens server-side.
This page is written for developers and AI agents that generate HTML Mode files. Use these methods instead of calling private Scalev URLs directly.
Availability
The runtime is available on rendered HTML Mode pages. In local editor previews, some methods can return stubbed preview data.
const scalev = window.Scalev;
if (!scalev) {
// Keep the page usable while runtime data loads.
}Most methods are asynchronous and return a Promise. Scalev.data.get() and Scalev.diagnostics.get() are synchronous.
Runtime method payloads and responses use camelCase object keys. The runtime handles the backend casing internally, so page JavaScript should not send snake_case keys. Runtime methods also return the JavaScript-visible result directly. They remove backend collection containers such as data and is_paginated before returning arrays.
String enum values and provider-owned blobs keep their original values. For example, success_page, direct_to_whatsapp, analytics parameters, metadata, and customData are not renamed.
Store context
When Store Context is selected, Scalev.data.get().store includes only the selected store summary, products, and bundle price options. Treat it as the page-specific checkout catalog.
When HTML Checkout Page is selected, Scalev.data.get().afterCheckout includes the selected after-checkout success type and its public destination config.
When Store Context is unselected, treat store as unavailable. Build a regular landing page and rely only on page-safe methods such as Scalev.data.get(), Scalev.analytics.track(), and Scalev.prefill.get().
Security rules
- Keep API keys, business-user JWTs, storefront API keys, customer tokens, cookies, and credentials out of page JavaScript.
- Use documented
window.Scalevmethods instead of private Scalev URLs or private APIs. - Create orders only after a visitor intentionally submits a form.
- Prefer
Scalev.checkout.createOrder()on submit; it validates the payload before the order is persisted. - Use only selected products, bundles, prices, inventory, payment methods, shipping options, and customer identity values present in the runtime data.
Scalev.data.get()
Scalev.data.get()Returns public page data injected into the rendered page.
const data = Scalev.data.get();Response example:
{
"page": {
"id": 1,
"uniqueId": "pageUid",
"username": "brand"
},
"store": {
"id": 1,
"uniqueId": "storeUid",
"name": "Main Store",
"paymentMethodOptions": [
{
"value": "bt:BCA:paymentAccountUid",
"display": "Bank Central Asia",
"logoUrl": "https://cdn.scalev.com/icons/BT_BCA.png"
},
{
"value": "cod",
"display": "COD",
"logoUrl": "https://cdn.scalev.com/icons/cod.png"
}
],
"products": [
{
"id": 1,
"name": "Product",
"variants": [
{
"id": 10,
"uniqueId": "variantUid",
"name": "Default",
"price": 99000,
"availableQty": 12
}
]
}
],
"bundlePriceOptions": [
{
"id": 20,
"uniqueId": "bundleOptionUid",
"name": "Bundle",
"price": 179000
}
]
},
"afterCheckout": {
"type": "other_page",
"otherPagePath": "/thank-you"
}
}Use store.paymentMethodOptions to render payment choices. Render display, show logoUrl, and submit the selected value as paymentMethod. Scalev omits e-payment methods that cannot be executed with a verified fee schedule when the store passes provider transaction fees to the customer; do not recreate hidden options from saved store configuration.
Payment option values are already flattened:
va:BRImeans virtual account for BRI.bt:BCA:paymentAccountUidmeans manual bank transfer for the represented BCA account.- Regular values such as
cod,qris,invoice,alfamart, orgopaykeep their original values.
Location methods
Use these methods for address and shipping forms.
const provinces = await Scalev.location.provinces();
const cities = await Scalev.location.cities(provinces[0].id);
const subdistricts = await Scalev.location.subdistricts(cities[0].id);
const postalCodes = await Scalev.location.postalCodes(subdistricts[0].id);provinces, cities, and subdistricts accept optional query objects:
const provinces = await Scalev.location.provinces({ search: "Jawa" });Province and city responses use { id, name }. Subdistrict responses use id and name for the subdistrict, plus cityName, provinceName, and display for address labels.
Response examples:
[
{
"id": 31,
"name": "DKI Jakarta"
}
][
{
"id": 3171,
"name": "Kota Jakarta Pusat"
}
][
{
"id": 9090,
"name": "Gambir",
"cityName": "Kota Jakarta Pusat",
"provinceName": "DKI Jakarta",
"display": "Gambir, Kota Jakarta Pusat, DKI Jakarta"
}
][
{
"postalCode": "10110"
}
]Scalev.checkout.validateDiscount(payload)
Scalev.checkout.validateDiscount(payload)Validates a discount code for a checkout payload.
const result = await Scalev.checkout.validateDiscount({
discountCode: "PROMO10",
grossRevenue: 179000,
netProductPrice: 179000,
shippingCost: 0,
paymentMethod: store.paymentMethodOptions?.[0]?.value || "cod"
});Response example:
{
"discountCode": {
"code": "PROMO10",
"appliedTo": "product_price",
"amountType": "fixed",
"amount": 10000,
"isEnabled": true
},
"eligibilityDetails": {
"isEnabled": true,
"isExpiryCheck": true,
"isUsageLimitCheck": true,
"isMinimumRevenueCheck": true,
"isLimitedToPagesCheck": true,
"isLimitedToPaymentMethodsCheck": true,
"isPageDiscountActive": true,
"isAmountNotZero": true
},
"isEligible": true,
"discountCodeDiscount": 10000
}Scalev.checkout.shippingOptions(payload)
Scalev.checkout.shippingOptions(payload)Returns shipping options for the selected items, destination, and payment method. Use this as the only shipping lookup method.
const shippingOptions = await Scalev.checkout.shippingOptions({
paymentMethod: selectedPaymentOption.value,
destination: {
subdistrictId: selectedSubdistrictId,
postalCode: selectedPostalCode
},
items: [
{
type: "product",
variantUniqueId: firstVariant.uniqueId,
quantity: 1
}
]
});Pass the chosen option back as one shipping field in estimateSummary and createOrder. The runtime prepares the checkout request from that option. Options include logoUrl when a courier code is available.
Response example:
[
{
"courierServiceId": 48,
"courierCode": "anteraja",
"serviceCode": "ND",
"name": "Next Day",
"cost": 15300,
"etd": "1",
"isCod": false,
"warehouseUniqueId": "warehouseUid",
"courierAggregatorCode": null,
"logoUrl": "https://cdn.scalev.com/assets/images/kurir/anteraja.png"
}
]Recommended method payload:
{
"items": [
{ "type": "product", "variantUniqueId": "variantUid", "quantity": 1 },
{
"type": "bundle",
"bundlePriceOptionUniqueId": "bundleOptionUid",
"quantity": 1
}
],
"destination": { "subdistrictId": 12345, "postalCode": "10110" },
"paymentMethod": "cod"
}Scalev.checkout.estimateSummary(payload)
Scalev.checkout.estimateSummary(payload)Returns a checkout summary for pages that show a buyer-facing breakdown before submit.
This method is optional. Pass the same item, destination, payment, and shipping that you will send to Scalev.checkout.createOrder(payload).
The result does not replace order creation validation. Scalev still validates and applies final shipping, discount, extra-fee, and total amounts during order creation before the order is persisted.
const shipping = shippingOptions[0];
const payload = {
destination: { subdistrictId: 12345, postalCode: "10110" },
items: [
{ type: "product", variantUniqueId: firstVariant.uniqueId, quantity: 1 },
{
type: "bundle",
bundlePriceOptionUniqueId: firstBundlePriceOption.uniqueId,
quantity: 1
}
],
paymentMethod: selectedPaymentOption.value,
shipping
};
const summary = await Scalev.checkout.estimateSummary(payload);Recommended method payload:
{
"items": [
{ "type": "product", "variantUniqueId": "variantUid", "quantity": 1 },
{
"type": "bundle",
"bundlePriceOptionUniqueId": "bundleOptionUid",
"quantity": 1
}
],
"destination": { "subdistrictId": 12345, "postalCode": "10110" },
"paymentMethod": "cod",
"shipping": {
"courierServiceId": 48,
"courierCode": "anteraja",
"serviceCode": "ND",
"name": "Next Day",
"cost": 15300,
"etd": "1",
"isCod": false,
"warehouseUniqueId": "warehouseUid",
"courierAggregatorCode": null,
"logoUrl": "https://cdn.scalev.com/assets/images/kurir/anteraja.png"
}
}Response example:
{
"productPrice": 268000,
"shippingCost": 15300,
"otherIncome": 6500,
"otherIncomeName": "Biaya Penanganan",
"serviceFee": 2500,
"grossRevenue": 292300
}Use estimateSummary when the checkout UI displays totals before submit. Refresh it whenever the selected items, quantities, destination, shipping option, discount, or payment method changes. Render otherIncome with otherIncomeName when it is non-zero, and render one Biaya layanan or Service fee row from serviceFee when it is non-zero.
otherIncome remains the store's existing Other Charges concept. serviceFee is one combined customer-facing fee for direct e-payment. Both can be non-zero in the same checkout. Scalev calculates Other Charges first, then uses the checkout amount plus otherIncome as the base for the Service Fee, and grossRevenue is the displayed and charged total.
Both fees are calculated by Scalev from the store's saved Service Fee and Other Charges settings. The page does not send a fee policy, a fee amount, or a fee quote, and there is no fee field to echo back into createOrder. Order creation recalculates both fees from the same store settings, so treat every summary value as a preview for the buyer. serviceFee is zero when the store charges no customer fee for the selected method, and it is always zero for cod, other non-e-payment methods, and payment_link, while saved Other Charges rules still apply.
A payment_link order is always created with otherIncome of zero, whatever the request contains. The Payment Link snapshots the store's Other Charges configuration and quotes both fees on the Scalev-hosted payment page once the buyer picks a concrete method.
Scalev.checkout.createOrder(payload)
Scalev.checkout.createOrder(payload)Creates a real public order and validates the payload. Call this only after a visitor intentionally submits the form.
async function submitOrder(event) {
event.preventDefault();
const data = Scalev.data.get();
const store = data.store;
const firstVariant = store.products[0].variants[0];
const selectedPaymentOption = store.paymentMethodOptions[0];
const selectedSubdistrictId = 12345;
const selectedPostalCode = "10110";
const items = [
{ type: "product", variantUniqueId: firstVariant.uniqueId, quantity: 1 }
];
const destination = {
subdistrictId: selectedSubdistrictId,
postalCode: selectedPostalCode
};
const shippingOptions = await Scalev.checkout.shippingOptions({
paymentMethod: selectedPaymentOption.value,
destination,
items
});
const shipping = shippingOptions[0];
const payload = {
customer: {
name: event.currentTarget.elements.customerName.value,
phone: event.currentTarget.elements.customerPhone.value,
email: event.currentTarget.elements.customerEmail.value
},
destination: {
address: event.currentTarget.elements.address.value,
...destination
},
items,
paymentMethod: selectedPaymentOption.value,
shipping
};
const order = await Scalev.checkout.createOrder(payload);
return order;
}Supported payload fields:
- Customer object:
customer.name,customer.phone,customer.email - Destination object:
destination.address,destination.subdistrictId,destination.postalCode - Payment field:
paymentMethod - Items list:
items[]with{ type: "product", variantUniqueId, quantity }or{ type: "bundle", bundlePriceOptionUniqueId, quantity } - Discount field:
discountCode - Optional post-payment override:
isPostPaymentRedirectEnabledandpostPaymentRedirectUrl
The post-payment fields are creation-only API inputs; Scalev does not add them as controls to your public form. Omit both fields to inherit the Checkout Page setting. Send isPostPaymentRedirectEnabled: false to force Scalev's hosted success flow for that order. Send isPostPaymentRedirectEnabled: true with an absolute HTTPS postPaymentRedirectUrl to replace the page setting for that order. Scalev snapshots the result, so an order update cannot change it later.
Do not submit top-level product or shipping discount fields. Product price and item-level adjustments belong on items[] when needed. Use validateDiscount to preview eligible discount code amounts, then pass the selected code as discountCode to createOrder.
For shipping selection, call Scalev.checkout.shippingOptions(payload), let the visitor choose one option, then pass that whole option as shipping into summary and order calls.
Recommended method payload:
{
"customer": {
"name": "Customer Name",
"phone": "08123456789",
"email": "[email protected]"
},
"destination": {
"address": "Customer address",
"subdistrictId": 12345,
"postalCode": "10110"
},
"items": [
{ "type": "product", "variantUniqueId": "variantUid", "quantity": 1 }
],
"paymentMethod": "cod",
"shipping": {
"courierServiceId": 48,
"courierCode": "anteraja",
"serviceCode": "ND",
"name": "Next Day",
"cost": 15300,
"etd": "1",
"isCod": false,
"warehouseUniqueId": "warehouseUid",
"courierAggregatorCode": null,
"logoUrl": "https://cdn.scalev.com/assets/images/kurir/anteraja.png"
},
"discountCode": "PROMO10",
"eventSourceUrl": "https://brand.myscalev.com/page",
"utmSource": "ads"
}For payment selection, render store.paymentMethodOptions[].display, render payment images from store.paymentMethodOptions[].logoUrl, and submit only the selected option value as paymentMethod.
Response example:
{
"orderId": "260601HPQSPBX",
"status": "pending",
"paymentStatus": "unpaid",
"secretSlug": "orderSecretSlug",
"publicOrderUrl": "https://brand.myscalev.com/order/orderSecretSlug",
"paymentUrl": null,
"productPrice": "90000.00",
"productDiscount": "0.00",
"shippingCost": "15300.00",
"shippingDiscount": "0.00",
"discountCodeDiscount": "10000.00",
"otherIncome": "0.00",
"otherIncomeName": "Biaya Lainnya",
"serviceFee": "0.00",
"grossRevenue": "95300.00",
"paymentMethod": "bank_transfer",
"paymentAccount": {
"uniqueId": "paymentAccountUid",
"financialEntityName": "Bank Central Asia",
"accountNumber": "1234567890"
},
"courierService": {
"id": 48,
"name": "Next Day",
"courier": {
"name": "AnterAja",
"code": "anteraja"
}
},
"variants": {},
"bundlePriceOptions": {
"Bundle": {
"bundlePriceOptionUniqueId": "bundleOptionUid",
"quantity": 1
}
},
"handlerPhone": null,
"chatMessage": null
}Error handling
Runtime methods reject the Promise with a JavaScript Error. Use error.message for UI copy. Use error.status, error.data, and Scalev.diagnostics.get() only for debugging.
try {
const order = await Scalev.checkout.createOrder(payload);
return order;
} catch (error) {
showFormError(error.message || "Order creation failed.");
}Scalev.analytics.track(provider, payload)
Scalev.analytics.track(provider, payload)Forwards configured analytics events through Scalev.
await Scalev.analytics.track("facebook", {
firstName: "Customer",
phone: "08123456789",
variants: [{ uniqueId: "variantUid", quantity: 1, price: 179000 }],
events: [
{
eventName: "Lead",
parameters: { value: 179000, currency: "IDR" }
}
]
});Supported provider names:
facebooktiktokkwai
Response example:
nullIf no provider is passed, the runtime skips the call without contacting Scalev:
{
"skipped": true,
"reason": "missing_analytics_provider"
}If the analytics request fails, the checkout flow should continue and the runtime returns:
{
"skipped": true,
"reason": "analytics_request_failed"
}Scalev.prefill.get()
Scalev.prefill.get()Reads safe browser-scoped form prefill data.
const prefill = await Scalev.prefill.get();
const customerName = prefill.customer?.name || "";
const customerPhone = prefill.customer?.phone || "";
const destinationAddress = prefill.destination?.address || "";Response example:
{
"customer": {
"name": "Customer Name",
"phone": "08123456789",
"email": "[email protected]"
},
"destination": {
"address": "Jl. Contoh No. 1",
"subdistrictId": 9104,
"postalCode": "12250"
}
}Scalev.prefill.save(form, metadata)
Scalev.prefill.save(form, metadata)Persists safe browser-scoped form prefill data in the encrypted scv_fd cookie. This is handled locally by fe-public and does not call a Storefront or page runtime API endpoint.
await Scalev.prefill.save(
{
customer: {
name: "Customer Name",
phone: "08123456789",
email: "[email protected]"
},
destination: {
address: "Jl. Contoh No. 1",
subdistrictId: 9104,
postalCode: "12250"
}
},
{
source: "checkout_form"
}
);Response example:
{
"saved": true
}Scalev.diagnostics.get()
Scalev.diagnostics.get()Returns recent runtime diagnostics for debugging.
const diagnostics = Scalev.diagnostics.get();Response example:
[
{
"level": "error",
"code": "runtime_request_failed",
"message": "Scalev runtime request failed.",
"details": {
"path": "/pages/pageUid/orders",
"status": 422,
"response": {
"message": "customer.phone: can't be blank"
}
},
"timestamp": "2026-06-01T08:00:00.000Z"
}
]Updated 26 days ago
