Developer Portal

Widget API Documentation

Selamat datang di portal Widget API Brana POS. Fitur ini dirancang khusus untuk mempermudah integrasi data toko Anda dari Brana POS ke website promosi pribadi Anda secara instan dan tanpa ribet.

Dengan Widget API, Anda bisa menampilkan profil toko (alamat & cabang), data stok barang secara real-time, harga jual produk, dan biaya jasa servis ke website Anda. API ini bersifat Read-Only (hanya membaca data) dan didukung dengan CORS (Cross-Origin Resource Sharing) aktif, memampukan pemanggilan Ajax via Fetch secara aman langsung dari browser client.

Autentikasi & Kunci Token

Seluruh endpoint publik di bawah wajib melampirkan token identifikasi toko. Anda wajib menambahkan parameter query URL api_key atau apikey di akhir URL endpoint Anda.

Langkah Membuat API Key Toko:

  1. Buka dan login ke Dashboard POS Anda di app.branapos.com.
  2. Masuk ke halaman Pengaturan Toko.
  3. Gulir ke bawah hingga bagian Widget API.
  4. Klik tombol Generate API Key.
  5. Selesai! Token siap disalin dengan mengeklik tombol Copy di sebelahnya.

Keamanan Server & Limitasi

Untuk mengamankan database dari serangan DDoS atau *spam request* yang berisiko membuat website POS Anda down, kami memasang proteksi berikut:

Rate Limiter

Maksimal **60 request per menit** per API Key. Request di atas batas tersebut akan diblokir dengan kode status HTTP 429 Too Many Requests.

Response Caching

Response data di-cache selama **30 detik**. Perubahan data stok barang atau harga di aplikasi kasir akan terupdate di website Anda dalam selang waktu maksimal 30 detik.

GET /api/public/info

Endpoint ini menyajikan profile ringkas dari cabang utama toko Anda (nama toko, slogan, no. WhatsApp, alamat) beserta daftar profile seluruh cabang yang terdaftar di POS.

cURL Call
curl -G "https://app.branapos.com/api/public/info" \
  --data-urlencode "api_key=API_KEY_ANDA"
JSON Output (200 OK)
{
  "store": {
    "name": "Brana Cell Jakarta",
    "slogan": "Pusat Reparasi Gadget & Sparepart",
    "city": "Jakarta Pusat",
    "address": "Jl. K.H. Mas Mansyur No. 120",
    "whatsapp": "6281234567890",
    "email": "hello@branacell.com",
    "logo": "https://app.branapos.com/logos/brana-cell.jpg"
  },
  "branches": [
    {
      "id": 1,
      "name": "Brana Cell Jakarta",
      "city": "Jakarta Pusat",
      "address": "Jl. K.H. Mas Mansyur No. 120",
      "whatsapp": "6281234567890"
    },
    {
      "id": 3,
      "name": "Brana Cell Depok",
      "city": "Depok",
      "address": "Jl. Margonda Raya No. 45",
      "whatsapp": "6281298765432"
    }
  ]
}
GET /api/public/produk

Mengembalikan seluruh katalog produk aktif, harga jual, nama kategori, dan jumlah stok barang di cabang tersebut.

Query String Parameters (Opsional)

Parameter Tipe Keterangan
branch_id number Filter data stok produk dari ID cabang tertentu (lihat daftar cabang pada endpoint `info`).
q string Pencarian produk berdasarkan nama produk atau barcode kode SKU barang.
cURL Call
curl -G "https://app.branapos.com/api/public/produk" \
  --data-urlencode "api_key=API_KEY_ANDA" \
  --data-urlencode "branch_id=1" \
  --data-urlencode "q=baterai"
JSON Output (200 OK)
{
  "store": {
    "name": "Brana Cell Jakarta",
    "city": "Jakarta Pusat"
  },
  "data": [
    {
      "id": 12,
      "code": "PRD-0129",
      "name": "Baterai iPhone X Original",
      "category": "Sparepart Apple",
      "sellPrice": 250000,
      "stock": 14,
      "description": "Baterai replacement kualitas OEM. Garansi toko 3 bulan."
    },
    {
      "id": 15,
      "code": "PRD-0130",
      "name": "Baterai Samsung S20 Ultra OEM",
      "category": "Sparepart Samsung",
      "sellPrice": 280000,
      "stock": 5,
      "description": "Baterai pengganti untuk Samsung S20 Ultra."
    }
  ],
  "meta": {
    "total": 2,
    "updatedAt": "2026-06-07T08:00:00.000Z"
  }
}
GET /api/public/servis

Mengembalikan seluruh biaya jasa servis/perbaikan yang ditawarkan toko beserta estimasi harga jasa pengerjaannya.

Query String Parameters (Opsional)

Parameter Tipe Keterangan
q string Mencari layanan jasa servis berdasarkan nama atau kode tindakan.
cURL Call
curl -G "https://app.branapos.com/api/public/servis" \
  --data-urlencode "api_key=API_KEY_ANDA" \
  --data-urlencode "q=ganti lcd"
JSON Output (200 OK)
{
  "store": {
    "name": "Brana Cell Jakarta",
    "city": "Jakarta Pusat"
  },
  "data": [
    {
      "id": 4,
      "code": "SV-0004",
      "name": "Ganti LCD Smartphone Standard",
      "description": "Biaya jasa pasang LCD non-curve / standard.",
      "price": 50000
    },
    {
      "id": 8,
      "code": "SV-0008",
      "name": "Ganti LCD iPad / Tablet",
      "description": "Jasa pembongkaran OCA & penggantian modul layar sentuh tablet.",
      "price": 150000
    }
  ],
  "meta": {
    "total": 2,
    "updatedAt": "2026-06-07T08:00:00.000Z"
  }
}

Integrasi JavaScript Vanilla

Anda bisa langsung menempelkan kode pemanggilan *Asynchronous Fetch* di bawah ini pada website pribadi toko Anda untuk memanggil data produk Brana POS.

async function fetchBranaProducts(apiKey) {
  const url = `https://app.branapos.com/api/public/produk?api_key=${encodeURIComponent(apiKey)}`;
  
  try {
    const response = await fetch(url);
    
    // Penanganan Rate-Limiting (429)
    if (response.status === 429) {
      const retryAfter = response.headers.get('Retry-After') || '60';
      console.warn(`Terlalu banyak request. Coba kembali dalam ${retryAfter} detik.`);
      alert(`Limit tercapai. Silakan tunggu ${retryAfter} detik.`);
      return;
    }

    if (!response.ok) {
      const err = await response.json();
      throw new Error(err.error || 'Gagal memuat data');
    }

    const result = await response.json();
    console.log('Toko:', result.store.name);
    console.log('Daftar Produk:', result.data);
    
    // Tampilkan data produk ke DOM website Anda...
    displayProducts(result.data);

  } catch (error) {
    console.error('Terjadi kesalahan:', error.message);
  }
}

Klip Kode: Widget Grid Stok & Harga Produk

Gunakan cuplikan struktur HTML dan script render di bawah untuk menampilkan katalog produk premium dengan status stok otomatis di website Anda:

<!-- HTML Container -->
<div id="brana-product-grid" class="grid grid-cols-1 md:grid-cols-3 gap-6">
  <!-- Card-card produk akan muncul disini melalui JavaScript -->
</div>

<script>
function renderProducts(products) {
  const container = document.getElementById('brana-product-grid');
  container.innerHTML = products.map(p => `
    <div class="border rounded-2xl p-5 shadow-sm bg-white dark:bg-zinc-900 dark:border-zinc-800">
      <span class="text-[9px] font-bold text-blue-500 uppercase tracking-widest">\${p.category || 'PRODUK'}</span>
      <h3 class="text-base font-bold text-slate-800 dark:text-white mt-1 leading-tight">\${p.name}</h3>
      <p class="text-[10px] text-slate-400 mt-0.5">Kode: \${p.code}</p>
      <p class="text-xs text-slate-500 dark:text-zinc-400 mt-2 font-medium line-clamp-2">\${p.description || '-'}</p>
      
      <div class="flex justify-between items-center mt-5 pt-3 border-t dark:border-zinc-800">
        <div>
          <p class="text-[9px] text-slate-400 font-bold uppercase">Harga</p>
          <p class="text-sm font-black text-slate-900 dark:text-white mt-0.5">
            \${new Intl.NumberFormat('id-ID', { style: 'currency', currency: 'IDR', minimumFractionDigits: 0 }).format(p.sellPrice)}
          </p>
        </div>
        <div class="text-right">
          <p class="text-[9px] text-slate-400 font-bold uppercase">Stok Tersedia</p>
          <span class="inline-block px-2 py-0.5 bg-emerald-500/10 text-emerald-600 rounded text-xs font-bold mt-1">
            \${p.stock} Pcs
          </span>
        </div>
      </div>
    </div>
  \`).join('');
}
</script>

Klip Kode: Widget Katalog Harga Tindakan Servis

Gunakan cuplikan kode di bawah untuk membuat daftar list biaya jasa servis reparasi transparan untuk memikat calon customer:

<!-- HTML Container -->
<div class="max-w-xl mx-auto border rounded-3xl overflow-hidden shadow-sm bg-white dark:bg-zinc-900 dark:border-zinc-800">
  <div class="p-6 border-b dark:border-zinc-800">
    <h3 class="text-lg font-bold text-slate-900 dark:text-white">Katalog Jasa Servis</h3>
    <p class="text-xs text-slate-400 mt-1">*Biaya diluar penggantian suku cadang/sparepart</p>
  </div>
  <div id="brana-service-list" class="divide-y dark:divide-zinc-800">
    <!-- Daftar jasa servis muncul di sini -->
  </div>
</div>

<script>
function renderServices(services) {
  const container = document.getElementById('brana-service-list');
  container.innerHTML = services.map(s => `
    <div class="p-5 flex justify-between items-start gap-4 hover:bg-slate-50 dark:hover:bg-zinc-800/40 transition-colors">
      <div class="min-w-0">
        <span class="text-[8px] font-mono text-blue-500 font-bold">\${s.code}</span>
        <h4 class="text-sm font-bold text-slate-800 dark:text-white leading-snug mt-0.5">\${s.name}</h4>
        <p class="text-xs text-slate-400 mt-1 leading-normal">\${s.description || '-'}</p>
      </div>
      <span class="text-sm font-black text-slate-900 dark:text-white font-mono shrink-0">
        \${new Intl.NumberFormat('id-ID', { style: 'currency', currency: 'IDR', minimumFractionDigits: 0 }).format(s.price)}
      </span>
    </div>
  \`).join('');
}
</script>