Dokumentasi API — Registrasi Tenant

Panduan integrasi untuk partner (web profile, apps Android, tim lain)
Base URL
Autentikasi — Partner API (HMAC)

Setiap pemanggilan endpoint register WAJIB ditandatangani HMAC-SHA256 memakai API Key & API Secret partner (didapat dari menu Partner API).

Header wajib di tiap request:

X-Api-KeyAPI Key partner (mis. p_xxxx).
X-TimestampWaktu Unix (detik). Harus dalam ±5 menit dari jam server (anti-replay).
X-SignatureTanda tangan HMAC (hex) dari string-to-sign di bawah.

Cara membuat tanda tangan:

stringToSign = X-Timestamp + "\n" + METHOD + "\n" + PATH + "\n" + body
X-Signature  = HEX( HMAC_SHA256( API_Secret, stringToSign ) )

contoh:  METHOD = "POST"   PATH = "/api/public/register"   body = JSON mentah (persis yang dikirim)
API Secret hanya untuk SERVER (backend apps/web profile). Jangan taruh di kode browser/JS klien — bisa dibaca siapa saja. Situs statis lihat bagian bawah.
Alur Pendaftaran

1. Partner panggil register 2. verified 3. Admin Approve 4. active

GET/api/public/check-subdomain?name=menjala — Cek ketersediaan subdomain

Pakai header HMAC yang sama. PATH yang ditandatangani tanpa query string (/api/public/check-subdomain), body kosong.

{ "status": true, "message": "Subdomain tersedia",
  "data": { "subdomain": "menjala", "domain": "menjala.hub.xpanca.com", "available": true } }

{ "status": true, "message": "subdomain sudah dipakai, silakan pilih nama lain",
  "data": { "subdomain": "menjala", "domain": "menjala.hub.xpanca.com", "available": false,
            "reason": "subdomain sudah dipakai, silakan pilih nama lain" } }
Hasil cek bukan reservasi — nama baru benar-benar terkunci saat register berhasil.
POST/api/public/register — Daftar tenant baru

Header: Content-Type: application/json + header HMAC di atas. Body (JSON):

FieldTipeKeterangan
email *stringEmail pemilik (wajib, unik).
business_name *stringNama usaha (wajib).
phonestringNo. HP pemilik.
full_namestringNama lengkap pemilik.
business_fieldstringBidang usaha.
npwpstringNPWP (opsional).
addressstringAlamat usaha.
subdomainstringAlamat aplikasi pilihan pendaftar → {subdomain}.hub.xpanca.com. 3–30 karakter, huruf kecil a-z / angka / minus, tidak diawali/diakhiri minus. Unik: bila sudah dipakai tenant lain → ditolak (400, "subdomain … sudah dipakai"). Kosong = dibuat otomatis dari nama usaha. Cek dulu lewat check-subdomain.

Respons sukses memuat data.slug dan data.domain (mis. menjala.hub.xpanca.com).

Contoh — Bash (openssl)
Contoh — Node.js (server-side)
Respons sukses (200)
{
  "status": true,
  "message": "Registrasi diterima. Akun Anda menunggu persetujuan admin.",
  "data": { "tenant_id": 6, "slug": "toko-budi", "message": "..." }
}
Respons gagal
401 → { "status": false, "message": "autentikasi partner gagal: X-Signature tidak cocok" }
400 → { "status": false, "message": "email ini sudah pernah digunakan untuk mendaftar" }
Untuk situs statis / browser (mis. form di xpanca.id)

Karena Secret tak boleh ada di browser, situs statis tidak menandatangani sendiri. Siapkan endpoint backend kecil milik partner (Node/PHP/serverless) yang menerima form lalu menandatangani & meneruskan ke hub-control:

[Browser form di xpanca.id]  →  POST /daftar  (backend milik partner, pegang Secret)
       → backend tandatangani HMAC → POST {BASE}/api/public/register → balas ke browser
Dengan begitu Secret tetap di server partner, tidak pernah ke browser.
Alternatif Tanpa Coding — Web Registrasi (iframe)

Partner yang tidak punya backend cukup menempel halaman pendaftaran siap pakai. Tidak perlu API Key/Secret; pendaftar tetap tercatat via partner. Atur di menu Partner API → Aksi → Atur & Ambil Kode Iframe.

  1. Otomatis aktif saat partner dibuat, tetapi hanya berjalan di satu domain situs partner (mis. https://tokopartner.com, versi www. ikut diizinkan). 1 partner = 1 domain, dan domain tidak bisa dipakai dua partner. Domain lain diblokir browser; link yang dibuka langsung di tab ditolak. Belum ada domain = "menunggu domain".
  2. Salin kode iframe, tempel di halaman situs partner.
<iframe src="{BASE}/embed/register/{embed_key}?color=16a34a"
  style="width:100%;max-width:600px;height:760px;border:0"
  referrerpolicy="strict-origin-when-cross-origin"></iframe>
QueryFungsi
colorWarna tombol, hex tanpa #.
title / hide_title=1Ganti / sembunyikan judul form.
theme=darkMode gelap.

Halaman mengirim postMessage ke situs induk: {source:"hubctl", type:"ready"|"resize"|"registered"|"completed"} — resize membawa height untuk menyesuaikan tinggi iframe. Selalu cek event.origin.

Keamanan: halaman hanya dilayani sebagai iframe dari domain terdaftar (dicek lewat Sec-Fetch-Dest & Referer — jangan hapus referrerpolicy di kode iframe) atau untuk admin yang login (mode pratinjau). Form membawa token bertanda tangan yang wajib untuk API; ditambah rate-limit, jebakan bot, dan Approve admin. Link bisa diganti kapan saja (Ganti Link, link lama mati).
OTP saat ini dimatikan — pendaftar langsung verified menunggu Approve admin. Endpoint dibatasi rate-limit.