Langsung ke konten utama
Penagihan berbasis kursi memungkinkan Anda menagih pelanggan berdasarkan jumlah pengguna, anggota tim, atau lisensi yang mereka perlukan. Ini adalah model harga standar untuk alat kolaborasi tim, perangkat lunak perusahaan, dan produk SaaS B2B.

Apa itu Penagihan Berdasarkan Kursi?

Penagihan berbasis kursi (juga disebut harga per pengguna atau per kursi) mengenakan biaya kepada pelanggan berdasarkan jumlah pengguna yang mengakses produk Anda. Alih-alih biaya tetap, harga akan meningkat seiring dengan ukuran tim.

Kasus Penggunaan Umum

IndustriContohModel Harga
Kolaborasi TimSlack, Notion, AsanaPer pengguna aktif/bulan
Alat PengembangGitHub, GitLab, JiraPer kursi/bulan
Perangkat Lunak CRMSalesforce, HubSpotPer lisensi pengguna
Alat DesainFigma, CanvaPer kursi editor
Perangkat Lunak Keamanan1Password, OktaPer pengguna/bulan
Konferensi VideoZoom, TeamsPer lisensi host

Manfaat Harga Berdasarkan Kursi

Untuk Bisnis Anda:
  • Pendapatan berkembang secara alami seiring pertumbuhan pelanggan
  • Harga yang dapat diprediksi yang dapat dianggarkan oleh pelanggan
  • Jalur peningkatan yang jelas dari individu ke tim hingga perusahaan
  • Nilai seumur hidup yang lebih tinggi seiring tim berkembang
Untuk Pelanggan Anda:
  • Bayar hanya untuk apa yang mereka gunakan
  • Mudah dipahami dan memprediksi biaya
  • Fleksibilitas untuk menambah/menghapus pengguna sesuai kebutuhan
  • Harga yang adil yang sesuai dengan ukuran tim

Bagaimana Penagihan Berdasarkan Kursi Bekerja di Dodo Payments

Dodo Payments menerapkan penagihan berbasis kursi menggunakan sistem Add-ons. Berikut cara kerjanya:

Ikhtisar Arsitektur

Langganan Team Pro seharga 99/bulandanmencakup5kursi.JikaAndamemilikilebihdari5pengguna,Andamembayar99/bulan dan mencakup 5 kursi. Jika Anda memiliki lebih dari 5 pengguna, Anda membayar 15/bulan tambahan untuk setiap kursi ekstra. Misalnya, jika tim Anda membutuhkan 15 kursi:
  • Paket Dasar: $99/bulan (termasuk 5 kursi)
  • Add-on: 10 kursi tambahan × 15/bulan=15/bulan = 150/bulan
  • Total biaya bulanan: 99+99 + 150 = $249 untuk 15 kursi

Komponen Utama

KomponenTujuanContoh
Produk DasarLangganan inti dengan kursi yang termasuk”Rencana Tim - $99/bulan (5 kursi termasuk)“
Add-on KursiBiaya per kursi untuk pengguna tambahan”Kursi Tambahan - $15/bulan masing-masing”
KuantitasJumlah kursi tambahan yang dibeli10 kursi tambahan

Strategi Penetapan Harga

Pilih strategi penetapan harga berbasis kursi yang sesuai untuk bisnis Anda:

Strategi 1: Dasar + Add-on Per-Kursi

Sertakan sejumlah kursi dalam rencana dasar, kenakan biaya untuk kursi tambahan. Contoh:
Starter Plan: $49/month
├── Includes: 3 seats
├── Extra seats: $10/month each
└── 8 total seats = $49 + (5 × $10) = $99/month
Terbaik untuk: Produk di mana tim kecil dapat berfungsi dengan penawaran dasar.

Strategi 2: Harga Per-Kursi Murni

Kenakan tarif tetap per kursi tanpa biaya dasar. Contoh:
Per User: $12/month
├── 5 users = $60/month
├── 20 users = $240/month
└── 100 users = $1,200/month
Implementasi: Atur harga rencana dasar menjadi $0, gunakan hanya add-on kursi. Terbaik untuk: Penetapan harga yang sederhana dan transparan; model berbasis penggunaan.

Strategi 3: Penetapan Harga Kursi Bertingkat

Rencana dasar yang berbeda dengan tarif per-kursi yang berbeda. Contoh:
Starter: $0/month base + $15/seat
├── Lower features, higher per-seat cost

Professional: $99/month base + $10/seat
├── More features, lower per-seat cost

Enterprise: $499/month base + $7/seat
└── All features, volume discount on seats
Implementasi: Buat produk terpisah untuk setiap tingkat dengan harga add-on yang berbeda. Terbaik untuk: Mendorong peningkatan ke tingkat yang lebih tinggi; penjualan perusahaan.

Strategi 4: Paket Kursi

Jual kursi dalam paket daripada secara individu. Contoh:
5-Seat Pack: $50/month ($10/seat)
10-Seat Pack: $80/month ($8/seat)
25-Seat Pack: $175/month ($7/seat)
Implementasi: Buat beberapa add-on untuk ukuran paket yang berbeda. Terbaik untuk: Menyederhanakan keputusan pembelian; mendorong komitmen yang lebih besar.

Menyiapkan Penagihan Berdasarkan Kursi

Langkah 1: Rencanakan Penetapan Harga Anda

Sebelum implementasi, tentukan struktur harga Anda:
1

Define Base Plan

Putuskan apa yang termasuk dalam langganan dasar:
  • Harga dasar (bisa $0 untuk model murni per-kursi)
  • Jumlah kursi yang disertakan
  • Fitur yang tersedia pada tingkat ini
2

Set Seat Pricing

Tentukan biaya add-on per kursi:
  • Harga per kursi tambahan
  • Diskon volume (melalui beberapa add-on)
  • Maksimal kursi yang diperbolehkan (jika berlaku)
3

Consider Billing Frequency

Sesuaikan harga kursi dengan siklus penagihan Anda:
  • Langganan bulanan → biaya kursi bulanan
  • Langganan tahunan → biaya kursi tahunan (seringkali diskon)

Langkah 2: Buat Add-on Kursi

Di dasbor Dodo Payments Anda:
  1. Navigasi ke ProdukAdd-Ons
  2. Klik Buat Add-On
  3. Konfigurasikan add-on:
FieldValueNotes
Nama”Kursi Tambahan” atau “Anggota Tim”Nama yang jelas dan ramah pengguna
Deskripsi”Tambahkan anggota tim lain ke ruang kerja Anda”Jelaskan apa yang didapat pelanggan
HargaHarga per kursi Andamisalnya, $10.00
Mata UangSesuaikan dengan produk dasar AndaHarus sama dengan mata uang yang sama
Kategori PajakSama dengan produk dasarMemastikan penanganan pajak yang konsisten
Buat nama add-on deskriptif yang masuk akal di faktur. “Additional Team Seat” lebih jelas daripada “Seat Add-on” bagi pelanggan yang melihat tagihan mereka.

Langkah 3: Buat Produk Langganan Dasar

Buat produk langganan Anda:
  1. Navigasi ke ProdukBuat Produk
  2. Pilih Langganan
  3. Konfigurasikan harga dan detail
  4. Di bagian Add-Ons, lampirkan add-on kursi Anda

Langkah 4: Lampirkan Add-on ke Produk

Tautkan add-on kursi ke langganan Anda:
  1. Edit produk langganan Anda
  2. Gulir ke bagian Add-Ons
  3. Klik Tambahkan Add-Ons
  4. Pilih add-on kursi Anda
  5. Simpan perubahan
Produk langganan Anda sekarang mendukung harga berbasis kursi. Pelanggan dapat membeli jumlah kursi tambahan berapa pun saat checkout.

Mengelola Kursi

Menambahkan Kursi ke Langganan Baru

Saat membuat sesi checkout, tentukan jumlah kursi:
const session = await client.checkoutSessions.create({
  product_cart: [{
    product_id: 'prod_team_plan',
    quantity: 1,
    addons: [{
      addon_id: 'addon_seat',
      quantity: 10  // 10 additional seats
    }]
  }],
  customer: { email: 'admin@company.com' },
  return_url: 'https://yourapp.com/success'
});

Mengubah Jumlah Kursi pada Langganan yang Ada

Gunakan API Ubah Rencana untuk menyesuaikan kursi:
// Add 5 more seats to existing subscription
await client.subscriptions.changePlan('sub_123', {
  product_id: 'prod_team_plan',
  quantity: 1,
  proration_billing_mode: 'prorated_immediately',
  addons: [{
    addon_id: 'addon_seat',
    quantity: 15  // New total: 15 additional seats
  }]
});

Menghapus Kursi

Untuk mengurangi jumlah kursi, tentukan kuantitas yang lebih rendah:
// Reduce from 15 to 8 additional seats
await client.subscriptions.changePlan('sub_123', {
  product_id: 'prod_team_plan',
  quantity: 1,
  proration_billing_mode: 'difference_immediately',
  addons: [{
    addon_id: 'addon_seat',
    quantity: 8  // Reduced to 8 additional seats
  }]
});

Menghapus Semua Kursi Tambahan

Kirim array addons kosong untuk menghapus semua add-on:
// Remove all additional seats, keep only base plan seats
await client.subscriptions.changePlan('sub_123', {
  product_id: 'prod_team_plan',
  quantity: 1,
  proration_billing_mode: 'difference_immediately',
  addons: []  // Removes all add-ons
});

Prorasi untuk Perubahan Kursi

Ketika pelanggan menambah atau menghapus kursi di tengah siklus, prorasi menentukan bagaimana mereka ditagih.

Mode Prorata

ModeMenambah KursiMengurangi Kursi
prorated_immediatelyCharge for remaining days in cycleCredit for unused days
difference_immediatelyCharge full seat priceCredit applied to future renewals
full_immediatelyCharge full seat price, reset billing cycleNo credit

Contoh Prorata

Skenario: Siklus penagihan 15 hari tersisa, menambahkan 5 kursi seharga $10/kursi
Prorated charge = ($10 × 5 seats) × (15 days / 30 days)
                = $50 × 0.5
                = $25 immediate charge
Pelanggan membayar 25sekarang,lalu25 sekarang, lalu 50/bulan saat pembaruan.
Skenario: Menghapus 3 kursi di tengah siklus dengan prorated_immediately
Current: Team Plan ($99/month) + 10 extra seats × $10/seat = $199/month
Change: Remove 3 seats (10 → 7 extra seats) on day 20 of 30-day cycle
Remaining: 10 days

Credit for removed seats:
  = ($10 × 3 seats) × (10 days / 30 days)
  = $30 × 0.333
  = $10.00 credit

→ $10.00 credit added to subscription
→ Next renewal: $99 + (7 × $10) = $169.00/month
→ Credit auto-applies: $169.00 − $10.00 = $159.00 on next invoice
Memilih mode prorata untuk perubahan kursi: Gunakan prorated_immediately untuk penagihan berbasis hari yang adil ketika tim sering menyesuaikan kursi. Gunakan difference_immediately untuk matematika yang lebih sederhana yang mengenakan biaya atau mengkreditkan harga kursi penuh. Lihat Panduan Prorata untuk perbandingan rinci.

Pratinjau Sebelum Mengubah

Selalu pratinjau prorata sebelum melakukan perubahan:
const preview = await client.subscriptions.previewChangePlan('sub_123', {
  product_id: 'prod_team_plan',
  quantity: 1,
  proration_billing_mode: 'prorated_immediately',
  addons: [{ addon_id: 'addon_seat', quantity: 20 }]
});

console.log('Immediate charge:', preview.immediate_charge.summary);
// Show customer: "Adding 5 seats will cost $25 today"

Melacak Kursi dengan Webhook

Pantau perubahan kursi dengan mendengarkan webhook langganan:

Event yang Relevan

EventKapan DipicuKasus Penggunaan
subscription.activeLangganan baru diaktifkanSediakan kursi awal
subscription.plan_changedKursi ditambahkan/dihapusPerbarui jumlah kursi di aplikasi Anda
subscription.renewedLangganan diperpanjangPastikan jumlah kursi tidak berubah
subscription.cancelledLangganan dibatalkanHapus semua kursi

Contoh Handler Webhook

app.post('/webhooks/dodo', async (req, res) => {
  const event = req.body;

  switch (event.type) {
    case 'subscription.active':
      // New subscription - provision seats
      const seats = calculateTotalSeats(event.data);
      await provisionSeats(event.data.customer_id, seats);
      break;

    case 'subscription.plan_changed':
      // Seats changed - update access
      const newSeats = calculateTotalSeats(event.data);
      await updateSeatCount(event.data.subscription_id, newSeats);
      break;

    case 'subscription.cancelled':
      // Subscription cancelled - deprovision
      await deprovisionAllSeats(event.data.subscription_id);
      break;
  }

  res.json({ received: true });
});

function calculateTotalSeats(subscriptionData) {
  const baseSeats = 5;  // Included in plan
  const addonSeats = subscriptionData.addons?.reduce(
    (total, addon) => total + addon.quantity, 0
  ) || 0;
  return baseSeats + addonSeats;
}

Menegakkan Batas Kursi

Aplikasi Anda harus menegakkan batas kursi. Dodo Payments melacak penagihan, tetapi Anda mengendalikan akses.

Strategi Penegakan

Tegas mencegah penambahan pengguna di luar jumlah kursi.
async function inviteUser(teamId: string, email: string) {
  const team = await getTeam(teamId);
  const subscription = await getSubscription(team.subscriptionId);
  const totalSeats = calculateTotalSeats(subscription);
  const usedSeats = await countTeamMembers(teamId);

  if (usedSeats >= totalSeats) {
    throw new Error('No seats available. Please upgrade your plan.');
  }

  await sendInvitation(teamId, email);
}

Pola Lanjutan

Jenis Kursi yang Berbeda

Tawarkan jenis kursi berbeda dengan harga berbeda:
Full Seats: $20/month - Full access to all features
View-Only Seats: $5/month - Read-only access
Guest Seats: $0/month - Limited external collaborator access
Implementasi: Buat add-on terpisah untuk setiap jenis kursi.
const session = await client.checkoutSessions.create({
  product_cart: [{
    product_id: 'prod_team_plan',
    quantity: 1,
    addons: [
      { addon_id: 'addon_full_seat', quantity: 10 },
      { addon_id: 'addon_viewer_seat', quantity: 25 },
      { addon_id: 'addon_guest_seat', quantity: 50 }
    ]
  }]
});

Diskon Kursi Tahunan

Tawarkan harga kursi tahunan dengan diskon:
Monthly: $15/seat/month
Annual: $12/seat/month (20% savings)
Implementasi: Buat produk terpisah untuk paket bulanan dan tahunan dengan harga add-on yang berbeda.

Persyaratan Kursi Minimum

Tuntut jumlah kursi minimum untuk paket tertentu:
async function validateSeatCount(planId: string, seatCount: number) {
  const minimums = {
    'prod_starter': 1,
    'prod_team': 5,
    'prod_enterprise': 25
  };

  if (seatCount < minimums[planId]) {
    throw new Error(`${planId} requires at least ${minimums[planId]} seats`);
  }
}

Praktik Terbaik

Praktik Terbaik Penetapan Harga

  • Komunikasi Jelas: Tampilkan harga per kursi secara mencolok di halaman harga Anda
  • Kursi yang Disertakan: Pertimbangkan menyertakan beberapa kursi dalam harga dasar untuk mengurangi hambatan
  • Diskon Volume: Tawarkan tarif per kursi lebih rendah untuk tim besar guna memenangkan kesepakatan perusahaan
  • Insentif Tahunan: Diskon paket tahunan untuk meningkatkan arus kas dan retensi

Praktik Terbaik Teknis

  • Cache Jumlah Kursi: Cache jumlah kursi langganan secara lokal untuk menghindari panggilan API setiap permintaan
  • Sinkronisasi Secara Berkala: Sinkronkan jumlah kursi lokal Anda secara berkala dengan Dodo Payments via API
  • Tangani Kegagalan: Jika perubahan kursi gagal, tampilkan pesan kesalahan yang jelas dan opsi coba ulang
  • Jejak Audit: Catat semua perubahan kursi untuk sengketa penagihan dan kepatuhan

Praktik Terbaik Pengalaman Pengguna

  • Umpan Balik Waktu-nyata: Tampilkan dampak biaya segera saat menyesuaikan kursi
  • Langkah Konfirmasi: Minta konfirmasi sebelum perubahan penagihan
  • Transparansi Prorata: Jelaskan dengan jelas biaya prorata sebelum diterapkan
  • Penurunan Tingkat yang Mudah: Jangan membuatnya sulit untuk mengurangi kursi (ini membangun kepercayaan)

Pemecahan Masalah

Gejala: Aplikasi Anda menampilkan jumlah kursi berbeda dari langganan.Penyebab:
  • Webhook tidak diterima atau diproses
  • Kondisi balapan saat perubahan kursi
  • Data cache tidak diperbarui
Solusi:
  1. Terapkan handler webhook untuk subscription.plan_changed
  2. Tambahkan tombol “Sinkronkan dengan penagihan” yang mengambil langganan saat ini
  3. Tetapkan TTL cache untuk memastikan penyegaran reguler
Gejala: Pelanggan bingung dengan jumlah tagihan di tengah siklus.Penyebab:
  • Mode prorata tidak dikomunikasikan dengan jelas
  • Pelanggan tidak melihat pratinjau sebelum mengonfirmasi
Solusi:
  1. Selalu gunakan previewChangePlan sebelum melakukan perubahan
  2. Tampilkan rincian yang jelas: “Menambah X kursi = $Y hari ini (prorata untuk Z hari)”
  3. Dokumentasikan kebijakan prorata Anda di pusat bantuan
Gejala: Add-on kursi tidak tersedia saat checkout.Penyebab:
  • Add-on tidak terpasang ke produk
  • Add-on diarsipkan atau dihapus
  • Ketidaksesuaian mata uang antara produk dan add-on
Solusi:
  1. Verifikasi add-on terpasang di pengaturan produk
  2. Periksa status add-on di dasbor Add-Ons
  3. Pastikan mata uang cocok persis
Gejala: Pelanggan ingin mengurangi kursi tetapi memiliki pengguna yang ditetapkan.Solusi:
  1. Tunjukkan pengguna mana yang harus dihapus sebelum mengurangi kursi
  2. Terapkan alur kerja: Hapus pengguna → Kurangi kursi
  3. Pertimbangkan masa tenggang sebelum memberlakukan pengurangan kursi

Dokumentasi Terkait