# Bikin Frontend Sendiri

Dashboard bawaan SumoRouter hanyalah klien dari **Customer API** (`/api/*`). Semua yang bisa dilakukan
di dashboard (daftar, login, API key, usage, top-up, kupon, afiliasi, playground) bisa kamu bangun
ulang dengan UI sendiri, misalnya aplikasi mobile, white-label, atau integrasi ke produk kamu.

Referensi lengkap setiap endpoint: **[Customer API](/api/customer)**.

## Dua jenis autentikasi

| API | Path | Auth |
|---|---|---|
| AI gateway | `/v1/*` | API key `sk-…` |
| Dashboard / akun | `/api/*` | Token sesi (JWT) dari login, `Authorization: Bearer <token>` |

Token sesi berlaku **7 hari** dan langsung tidak berlaku saat user ganti password, ditangguhkan,
atau logout dari semua perangkat. Simpan token di memori atau storage yang aman; tangani `401` dengan
mengarahkan user ke halaman login.

Ganti password (`POST /api/me/password`) dan aktif/nonaktif 2FA mengakhiri sesi lain dan
mengembalikan `token` baru: **ganti token yang kamu simpan** dengan yang baru.

:::caution
`PUT /api/keys/{id}` mengganti **semua** pengaturan key. Field opsional yang tidak dikirim akan
dikosongkan, jadi kirim ulang seluruh pengaturan (ambil dulu dari `GET /api/keys`).
:::

## Peta endpoint

| Fitur | Endpoint |
|---|---|
| Info instance | `GET /api/branding`, `GET /api/auth/methods`, `GET /api/setup/status` |
| Daftar & login | `POST /api/auth/register`, `POST /api/auth/login`, `POST /api/auth/verify-email`, `POST /api/auth/mfa/verify` ([alur lengkap](/developers/auth-flow)) |
| Lupa password | `POST /api/auth/forgot-password`, `POST /api/auth/reset-password` |
| Profil | `GET /api/me`, `PUT /api/me/profile`, `POST /api/me/password`, `/api/me/mfa/*`, `/api/me/notifications` |
| Katalog model | `GET /api/models` (publik, dengan harga) |
| API key | `GET/POST /api/keys`, `PUT/DELETE /api/keys/{id}`, `POST /api/keys/{id}/regenerate` |
| Pemakaian | `GET /api/usage/summary`, `/api/usage/daily`, `/api/usage/logs`, `/api/usage/logs/{id}`, `/api/usage/filters` |
| Top-up | `GET /api/billing/config`, `POST /api/billing/topups`, `GET /api/billing/topups/{order_id}` |
| Kupon | `POST /api/billing/redeem`, `GET /api/billing/redemptions` |
| Afiliasi | `GET /api/me/affiliate` |
| Playground | `POST /api/playground/chat/completions` (ditagih ke saldo user, tanpa API key) |

## Contoh: halaman saldo dan top-up

```ts
const API = "https://ai.brandkamu.id/api";
const auth = { Authorization: `Bearer ${sessionToken}` };

const me = await fetch(`${API}/me`, { headers: auth }).then((r) => r.json());
console.log("Saldo USD:", me.balance_nano / 1e9);

const cfg = await fetch(`${API}/billing/config`).then((r) => r.json());
// cfg.enabled, cfg.idr_per_usd, cfg.min_topup_idr, cfg.max_topup_idr

const topup = await fetch(`${API}/billing/topups`, {
  method: "POST",
  headers: { ...auth, "Content-Type": "application/json" },
  body: JSON.stringify({ amount_idr: 50000 }),
}).then((r) => r.json());
// Tampilkan QRIS (payment_code) atau buka payment_link_url,
// lalu polling GET /api/billing/topups/{order_id} sampai status "completed".
```

## CORS dan domain

Customer API hanya mengizinkan request browser dari **satu origin** (`CORS_ORIGIN`, default domain
dashboard). Pilihan untuk frontend kamu:

1. **Proxy lewat server kamu** (disarankan): frontend memanggil backend kamu, backend kamu memanggil SumoRouter. Tidak ada masalah CORS dan token tidak terekspos ke pihak lain.
2. **Self-host**: jalankan instance sendiri dan isi `CORS_ORIGIN` dengan origin frontend kamu.
3. **Aplikasi non-browser** (mobile, desktop, server) tidak terkena CORS sama sekali.

:::caution
Jangan pernah menaruh API key `sk-…` di kode frontend. Untuk fitur chat di browser, pakai
`/api/playground/chat/completions` dengan token sesi user, atau proxy lewat backend kamu.
:::

## Format umum

- Semua uang dalam **nano-USD** (`1 USD = 1_000_000_000`), kecuali field yang berakhiran `_idr`.
- Waktu dalam ISO 8601 (UTC).
- List memakai `?limit=&offset=`.
- Error: `{"error": {"message", "type", "code"}}` (lihat [Error](/guides/errors)).
