Mulai Cepat

Dari daftar sampai punya link booking yang hidup dalam beberapa langkah: masuk dengan Google, buat satu layanan, atur jam operasional, lalu bagikan atau pasang link booking-nya. Tiap langkah cocok dengan tampilan dashboard dan punya endpoint API yang sesuai.

Lihat .md
Sebelum mulai
Anda butuh akun Google untuk masuk dan satu bisnis (tenant) aktif. Path dashboard di bawah memakai /api/*; partner API memakai /v1/* secara terpisah. Semua timestamp memakai epoch milidetik UTC (akhiran _at_ms).

Ringkasan langkah#

Lima langkah membawa Anda dari nol ke booking pertama. Anda bisa mengerjakannya lewat dashboard, lewat API, atau campuran keduanya.

  1. Masuk dengan Google
    Login OIDC Google membuat sesi dashboard.
  2. Buat layanan pertama
    Tetapkan nama, durasi, dan harga lewat Katalog → Layanan.
  3. Atur jam operasional
    Tentukan jam buka mingguan, blokir waktu, dan hari libur.
  4. Bagikan atau embed link
    Sebar link booking publik atau pasang widget di website mana pun.
  5. Terima booking pertama
    Pelanggan memilih slot dan submit tanpa perlu akun.

1. Masuk dengan Google#

Termilo memakai login Google (OIDC) untuk dashboard. Setelah masuk, sesi disimpan sebagai cookie HttpOnly __Host-termilo_session selama 30 hari. Semua permintaan yang mengubah data di /api/* memerlukan header CSRF X-Termilo-CSRF yang Anda ambil dari GET /api/session (csrfToken).

Shard tenant ditentukan dari workspace aktif sesi Anda — bukan dari id tenant yang dikirim pemanggil. Peran tenant_owner dan tenant_admin boleh menulis; tenant_staff dan tenant_viewer hanya membaca.

API key tersedia untuk integrasi
Alur dashboard ini tetap memakai sesi dan CSRF. Untuk partner API atau MCP branding, buat Bearer key di dashboard lalu ikuti referensi autentikasi atau panduan MCP.

2. Buat layanan pertama#

Di dashboard: buka Katalog → LayananTambah layanan. Isi Nama, Kategori, dan Deskripsi; nyalakan “Aktif untuk dibooking”. Atur Durasi (menit) dan Buffer setelah (menit), lalu set Harga (Rp). Simpan.

Setiap aksi simpan dipetakan ke POST /api/services. Hanya tiga field yang wajib:

PARAMETERTIPEWAJIBKETERANGAN
slugstringwajibPengenal unik layanan di URL booking. Mis. konsultasi-30.
namestringwajibNama layanan yang tampil ke pelanggan.
durationMinnumberwajibLama sesi dalam menit.
bufferBeforeMinnumberopsionalJeda sebelum sesi, dalam menit. Bawaan 0.
bufferAfterMinnumberopsionalJeda sesudah sesi, dalam menit. Bawaan 0.
priceAmountnumber | nullopsionalHarga dalam satuan terkecil (sen/rupiah penuh). Boleh kosong.
priceCurrencystringopsionalKode mata uang, mis. IDR.

Membuat layanan lewat API langsung:

curl https://app.termilo.id/api/services \ -H "Content-Type: application/json" \ -H "X-Termilo-CSRF: $CSRF_TOKEN" \ --cookie "__Host-termilo_session=$SESSION" \ -d '{ "slug": "konsultasi-30", "name": "Konsultasi 30 menit", "durationMin": 30, "bufferAfterMin": 10, "priceAmount": 150000, "priceCurrency": "IDR" }'
201 Createdapplication/json
{
"ok": true,
"data": {
"serviceId": "svc_8f2a",
"slug": "konsultasi-30",
"name": "Konsultasi 30 menit",
"durationMin": 30,
"status": "active"
},
"meta": { "requestId": "req_…" }
}
Deposit dibayar lewat gateway milik bisnis
Opsi “Minta deposit” (20% / 30% / 50%) di editor layanan menentukan persentasenya. Pembayaran deposit diproses lewat gateway pembayaran yang dihubungkan bisnis sendiri. Detailnya ada di panduan Deposit & Pembayaran.

3. Atur jam operasional#

Buka Operasional → Jam operasional. Atur jam buka–tutup per hari (Sen–Min, langkah 30 menit) dan pakai “Salin ke semua hari” agar cepat. Nyalakan “Tutup otomatis saat libur nasional”, lalu tambahkan “Pengecualian & hari libur” bila perlu.

Pemetaan endpoint: jendela mingguan ke POST /api/availability-rules (sebagai weekday, startMinute, endMinute, timezone), blokir waktu satu kali ke POST /api/blocked-times, dan penutupan tenant ke POST /api/holidays. Validasi mensyaratkan startMinute < endMinute.

Slot dihitung, bukan disimpan
Slot booking dihitung dari aturan jam dikurangi hari libur, blokir waktu, dan booking yang sudah ada. Slot di respons availability hanyalah kandidat tampilan — otoritas final ada saat pembuatan booking di bawah kunci, ditandai finalAuthority: booking_create_recheck_under_lock.

4. Bagikan atau embed link#

Begitu ada layanan aktif dan jam operasional, halaman booking publik Anda hidup di /book/akun-anda (ganti akun-anda dengan slug tenant Anda). Bagikan langsung, atau pasang sebagai widget di website mana pun lewat custom element <termilo-booking>.

Widget mengambil konfigurasinya dari atribut data-termilo-* atau lewat window.Termilo.init(...). Mode inline menanam form di halaman; mode modal membukanya dari tombol pemicu:

<!-- Pasang di tempat widget akan muncul. --> <termilo-booking data-termilo-tenant="akun-anda" data-termilo-mode="inline" data-termilo-accent="#087C70" ></termilo-booking> <script async src="https://embed.termilo.id/embed.js"></script>
Sumber booking ikut tercatat
Booking dari widget memakai source: "embed" dan memicu event serta audit yang sama seperti booking dari halaman publik (source: "public_page"). Panduan Embed di Website membahas semua atribut dan opsi tampilan.

5. Terima booking pertama#

Pelanggan tidak perlu akun. Aplikasi membaca slot publik (tanpa auth), lalu mengirim booking. Endpoint availability mengembalikan kandidat slot beserta capacityRemaining; jendela maksimal 31 hari:

# Pelanggan/aplikasi membaca slot publik — tanpa auth. curl "https://app.termilo.id/book/akun-anda/availability\ ?serviceSlug=konsultasi-30&fromMs=1750723200000&toMs=1750809600000"
200 OKapplication/json
{ "ok": true, "data": {
"finalAuthority": "booking_create_recheck_under_lock",
"slots": [
{ "startsAtMs": 1750762800000, "endsAtMs": 1750764600000,
"staffId": "stf_1", "capacityRemaining": 1 }
] } }

Untuk membuat booking, kirim serviceSlug, startsAtMs, source, dan objek customer dengan email atau telepon. Header Idempotency-Key wajib:

# Membuat booking publik. Header Idempotency-Key wajib. curl https://app.termilo.id/book/akun-anda/bookings \ -H "Content-Type: application/json" \ -H "Idempotency-Key: 9f1c-…" \ -d '{ "serviceSlug": "konsultasi-30", "startsAtMs": 1750762800000, "source": "public_page", "customer": { "name": "Sari", "primaryEmail": "sari@contoh.id" } }'

Respons mengembalikan objek booking ditambah manageToken dan manageUrl agar pelanggan bisa mengelola booking-nya sendiri. Status awal selalu held dengan hold_expires_at_ms = sekarang + 10 menit.

Slot dikunci ulang saat dibuat
Saat booking dibuat, slot dicek ulang di bawah kunci Durable Object sehingga dua orang tidak bisa mengambil waktu yang sama. Bila slot sudah terisi, responsnya BOOKING_SLOT_UNAVAILABLE (409). Status 201 untuk booking baru, 200 untuk replay idempoten.

Selesai. Dari dashboard, Anda lalu menjalankan siklus booking lewat /api/bookings/:bookingId/confirm, …/cancel, …/complete, …/no-show, dan …/reschedule.

Lanjut ke panduan lengkap#

Sudah punya link booking yang hidup? Dalami tiap langkah: