> ## 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.

# Checkout dan Payment

> Siapkan shipping, hitung summary checkout, buat guest order, dan tampilkan instruksi payment dari storefront browser.

Checkout Storefront API memakai konsep checkout yang sama dengan storefront bawaan Scalev. Storefront browser dapat mengambil opsi pengiriman, menghitung summary checkout, membuat guest order, membaca public order, dan membuat atau memakai ulang instruksi payment tanpa backend merchant.

Storefront API dirancang agar storefront Anda dapat merender payment page sendiri. Gunakan response public order dan payment untuk menampilkan instruksi pembayaran langsung di UI Anda. `payment_url` tetap dikembalikan sebagai fallback hosted untuk storefront yang belum mengimplementasikan renderer per metode atau untuk flow provider yang memang harus membuka hosted payment page.

Gunakan hanya metode payment yang dikembalikan oleh `GET /v3/stores/{store_id}/public/payment-methods`. Checkout storefront tidak mengembalikan `no_payment`, dan endpoint checkout akan menolaknya jika dikirim langsung.

## Alur guest checkout

1. Baca atau buat guest cart dan simpan `X-Scalev-Guest-Token`.
2. Minta lokasi pengiriman dan postal code jika cart berisi produk fisik.
3. Panggil `POST /public/checkout/shipping-options`.
4. Biarkan buyer memilih opsi pengiriman.
5. Panggil `POST /public/checkout/summary`.
6. Panggil `POST /public/checkout` dengan detail buyer dan field checkout terpilih.
7. Baca order dengan `GET /public/orders/{secret_slug}`.
8. Panggil `POST /public/orders/{secret_slug}/payment` dan render data payment yang dikembalikan di payment page Anda sendiri.

## Shipping options

```http theme={null}
POST /v3/stores/{store_id}/public/checkout/shipping-options
```

Headers:

```text theme={null}
X-Scalev-Storefront-Api-Key: sfpk_...
X-Scalev-Guest-Token: <guest-token>
```

Kirim direct `items` bertipe, atau hilangkan `items` dan biarkan `X-Scalev-Guest-Token` memilih guest cart:

```json theme={null}
{
  "items": [
    {
      "type": "variant",
      "variant_id": 494535,
      "quantity": 1
    }
  ],
  "destination": {
    "location_id": 9089,
    "postal_code": "10510"
  },
  "payment_method": "bank_transfer"
}
```

Direct `items[]` mendukung variant dan bundle price option. Item bundle price option memakai `{ "type": "bundle_price_option", "bundle_price_option_id": 123, "quantity": 1 }`.

Response:

```json theme={null}
{
  "data": [
    {
      "courier_service_id": 123,
      "courier_code": "jne",
      "service_code": "REG",
      "name": "Regular",
      "cost": 12000,
      "etd": "2-3",
      "is_cod": false,
      "warehouse_unique_id": "warehouse_...",
      "courier_aggregator_code": null
    }
  ],
  "is_paginated": false
}
```

Cart digital-only mengembalikan:

```json theme={null}
{
  "data": [],
  "is_paginated": false
}
```

## Checkout summary

```http theme={null}
POST /v3/stores/{store_id}/public/checkout/summary
```

Kirim opsi pengiriman terpilih. Scalev menghitung ulang shipping cost di server dan mengabaikan `shipping_cost` dari client.

```json theme={null}
{
  "destination": {
    "location_id": 9089,
    "postal_code": "10510"
  },
  "courier_service_id": 123,
  "warehouse_unique_id": "warehouse_...",
  "courier_aggregator_code": null,
  "payment_method": "bank_transfer"
}
```

Field response sama dengan summary checkout yang sudah ada:

```json theme={null}
{
  "product_price": "125000.00",
  "shipping_cost": "12000",
  "other_income": "0",
  "other_income_name": "Biaya Lainnya",
  "gross_revenue": "137000.00"
}
```

Cart digital-only mengembalikan `shipping_cost: "0"`.

## Cek kode diskon

```http theme={null}
POST /v3/stores/{store_id}/public/discount-codes/check
```

Gunakan body JSON untuk memvalidasi kode diskon sebelum checkout:

```json theme={null}
{
  "code": "SAVE10",
  "items": [
    {
      "type": "variant",
      "variant_id": 494535,
      "quantity": 1
    }
  ],
  "destination": {
    "location_id": 9089,
    "postal_code": "10510"
  },
  "courier_service_id": 123,
  "warehouse_unique_id": "warehouse_abc",
  "courier_aggregator_code": null,
  "payment_method": "bank_transfer"
}
```

Jika direct `items` dikirim, API memakai item tersebut sebagai sumber item. Jika tidak, kirim `X-Scalev-Guest-Token` untuk guest cart. Kode yang tidak ditemukan atau tidak eligible tetap mengembalikan response validasi normal dengan `is_eligible: false` dan `discount_code: null`.

## Public checkout

Buat order dengan:

```http theme={null}
POST /v3/stores/{store_id}/public/checkout
```

Endpoint ini menerima direct `items` bertipe, guest cart dari `X-Scalev-Guest-Token`, atau keduanya. Jika keduanya dikirim, direct `items` membuat order dan guest cart yang direferensikan dibersihkan setelah sukses.

Gunakan field checkout terpilih yang sama:

```json theme={null}
{
  "items": [
    {
      "type": "variant",
      "variant_id": 494535,
      "quantity": 1
    }
  ],
  "customer_name": "Customer Name",
  "customer_email": "customer@example.com",
  "customer_phone": "08123456789",
  "shipping_address": "Jl. Example 1",
  "shipping_location_id": 9089,
  "shipping_subdistrict": "Cempaka Putih",
  "shipping_postal_code": "10510",
  "courier_service_id": 123,
  "warehouse_unique_id": "warehouse_...",
  "courier_aggregator_code": null,
  "payment_method": "bank_transfer"
}
```

Endpoint checkout memakai courier service, warehouse, destinasi, metode pembayaran, dan item checkout untuk menghitung ulang shipping cost di server. Jangan menjadikan `shipping_cost` dari client sebagai sumber kebenaran.

Jika berhasil, response berisi data public order ringkas yang dibuat, termasuk `secret_slug`, `public_order_url`, `payment_url`, status, total, object map `variants` dan `bundle_price_options` yang sudah ada, line item, detail pengiriman, dan field payment. ID order internal, revenue khusus dashboard, platform fee, payment-status history, dan atribusi affiliate tidak dikembalikan. Gunakan `secret_slug` untuk membaca atau mengubah order. Gunakan `payment_url` hanya sebagai hosted fallback jika storefront Anda tidak merender instruksi payment sendiri.

## Instruksi payment

Setelah checkout, panggil:

```http theme={null}
POST /v3/stores/{store_id}/public/orders/{secret_slug}/payment
```

Endpoint ini idempotent. Jika instruksi payment sudah ada, response mengembalikan order lagi dengan data payment buyer-facing dan URL yang sudah tersedia.

Gunakan urutan preferensi berikut di browser storefront:

1. Render instruksi per metode dari `payment_method`, `sub_payment_method`, `epayment_provider`, dan `pg_payment_info`.
2. Untuk metode hosted oleh provider, buka URL provider dari `pg_payment_info` saat provider memang membutuhkan redirect.
3. Gunakan `payment_url` hanya sebagai fallback ke payment page hosted Scalev jika storefront Anda belum mendukung metode atau response provider tersebut.
4. Poll public order saat metode payment memerlukan data gateway yang mungkin belum langsung tersedia.

## Rendering per metode

Success page bawaan Scalev adalah reference implementation untuk rendering per metode. Storefront API storefront dapat menggantikan page tersebut dengan menerapkan mapping `pg_payment_info` yang sama di UI sendiri.

Success page bawaan terlebih dulu membuat data tampilan sederhana dari `pg_payment_info` Xendit/default yang dipakai saat ini. Data tampilan ini bukan response API baru. Bagian ini hanya referensi jika storefront Anda ingin punya satu renderer payment, bukan branching langsung ke field payload provider:

```json theme={null}
{
  "qrString": "000201010212...",
  "qrImageUrl": "https://api.qrserver.com/v1/create-qr-code/?...",
  "vaNumber": "88081234567890",
  "vaAccountHolder": "Customer Name",
  "invoiceUrl": "https://provider.example/pay/...",
  "renderUrlAs": "button"
}
```

Field sumber aslinya berasal dari order dan response payment. Untuk payload Xendit/default saat ini, petakan dengan aturan berikut:

| Display value     | Field sumber                                                                                                                                                                      |
| ----------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `qrString`        | `pg_payment_info.qr_string` atau `pg_payment_info.payment_method.qr_code.channel_properties.qr_string`                                                                            |
| `vaNumber`        | `pg_payment_info.payment_method.virtual_account.channel_properties.virtual_account_number` atau `pg_payment_info.payment_method.over_the_counter.channel_properties.payment_code` |
| `vaAccountHolder` | `pg_payment_info.payment_method.virtual_account.channel_properties.customer_name` atau `pg_payment_info.payment_method.over_the_counter.channel_properties.customer_name`         |
| `invoiceUrl`      | `pg_payment_info.invoice_url` atau `pg_payment_info.redirect_url`                                                                                                                 |
| `qrImageUrl`      | Buat QR image dari `qrString` di frontend saat Anda membutuhkan gambar QR yang bisa diunduh.                                                                                      |

Untuk `gopay`, `dana`, `linkaja`, `shopeepay`, dan `ovo`, pilih action URL dari `pg_payment_info.actions`: mobile memprioritaskan `url_type` `WEB` atau `DEEPLINK`; desktop memprioritaskan `MOBILE` atau `DEEPLINK`.

Set `renderUrlAs` menjadi `button` untuk `invoice`, `card`, dan semua tampilan mobile. Untuk tampilan desktop lainnya, render URL sebagai QR code.

`bank_transfer`:

Tampilkan total order, rekening manual bank transfer, expiry countdown jika aktif, dan link konfirmasi pembayaran ke `/o/{secret_slug}?showPaymentConfirmation=true`. Hosted page mengambil rekening dari `payment_accounts` store dengan `method` `bank_transfer` dan metode yang masih aktif. `pg_payment_info` bisa berupa `{}`.

`cod`:

Tampilkan body sukses COD dan jangan tampilkan countdown payment. Payment creation dapat mengembalikan `pg_payment_info` kosong.

Virtual account (`va`):

Render bank/channel virtual account dari `sub_payment_method`, `vaNumber`, dan `vaAccountHolder` jika tersedia. Tampilkan tombol copy dan link tutorial pembayaran. Bank code yang dikenal mencakup `BRI`, `MANDIRI`, `PERMATA`, `BNI`, `BCA`, `MAYBANK`, `CIMB`, `BNC`, `DANAMON`, `BSI`, `AG`, `BJB`, `SAHABAT_SAMPOERNA`, `ARTAJASA`, `BMI`, dan `BTN`.

QRIS (`qris`):

Render QR code dari `qrString`. Sediakan juga aksi download QR dari `qrImageUrl` dan instruksi mobile untuk menyimpan atau screenshot QR image sebelum membayar di aplikasi QRIS. Jika QR gagal dibuat atau `qrString` tidak ada, tampilkan retry action yang memanggil public payment endpoint lagi.

E-wallet kecuali OVO (`gopay`, `dana`, `linkaja`, `shopeepay`):

Gunakan `invoiceUrl` dari provider actions. Di mobile, buka sebagai button/deep link. Di desktop, render `invoiceUrl` sebagai QR code saat `renderUrlAs` bernilai `qr_code`; selain itu buka sebagai button. Jika URL tidak bisa dipetakan, arahkan buyer kembali ke public order page.

OVO (`ovo`):

Tampilkan instruksi untuk mengecek aplikasi OVO yang terhubung dengan nomor telepon buyer. Komponen success bawaan tidak merender OVO melalui komponen QR e-wallet yang sama.

Card (`card`) dan invoice/hosted payment (`invoice`):

Buka `invoiceUrl` hasil mapping sebagai button/redirect. Hosted success page otomatis redirect ketika `invoiceUrl` tersedia dan `renderUrlAs` bernilai `button`.

Alfamart dan Indomaret:

Render `vaNumber` sebagai `No Pembayaran`, tampilkan `vaAccountHolder` jika tersedia, dan sediakan aksi copy.

## Polling dan cek status

Untuk metode e-payment (`gopay`, `card`, `invoice`, `va`, `qris`, `ovo`, `dana`, `shopeepay`, `linkaja`, `alfamart`, dan `indomaret`), success page bawaan menunggu `pg_payment_info` muncul dengan refetch public order sampai 15 kali dengan jeda 1,5 detik.

Untuk order pending unpaid dengan `card`, `invoice`, `shopeepay`, `dana`, `qris`, `linkaja`, `gopay`, `bank_transfer`, `indomaret`, dan `alfamart`, success page bawaan kemudian me-refresh public order setiap 5 detik sambil menunggu konfirmasi payment.

Untuk `va`, `bank_transfer`, `qris`, `alfamart`, dan `indomaret`, success page bawaan juga menampilkan aksi manual "cek status pembayaran".

## Authenticated customer checkout

Endpoint customer checkout berada di:

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

Endpoint ini memakai `Authorization: Bearer <customer_access_token>`, bukan Storefront API key. Address, metode payment, shipping option, dan summary memakai field persiapan checkout yang sama dengan public checkout. Buat order dengan `POST /v3/stores/{store_id}/customers/me/checkout`; request menerima direct `items` bertipe, `cart_id`, atau keduanya. Response memakai public order shape yang sama dengan public checkout dan public order read, sehingga semua response checkout completion memakai field order yang sama.

Summary customer checkout memakai courier service, warehouse, destinasi, metode payment, dan direct `items` atau customer cart yang direferensikan untuk menghitung ulang shipping cost di server. `shipping_cost` dari client hanya nilai compatibility dan bukan jumlah authoritative.
