Skip to main content
좌석 기반 청구는 계정의 사용자 수를 기준으로 고객에게 요금을 청구합니다. Dodo Payments는 add-on 시스템을 사용해 이를 구현합니다. 기본 구독 상품과 좌석 수를 나타내는 수량을 가진 좌석당 add-on으로 구성됩니다.

Implementation Tutorial

단계별 가이드 및 코드 예제.

Add-ons Documentation

좌석 기반 청구를 지원하는 애드온 시스템에 대해 알아보세요.

Subscription Management

좌석 기반 구독 및 요금제 변경을 관리하세요.

Webhooks

구독 웹후크를 통해 좌석 변경을 추적하세요.

좌석 기반 청구란?

Seat-based billing은 제품에 액세스하는 사용자 수를 기준으로 고객에게 요금을 청구합니다. 고정 요금 대신 팀 규모에 따라 가격이 조정됩니다.

일반적인 사용 사례

좌석 기반 가격 책정의 이점

비즈니스의 경우:
  • 고객이 성장함에 따라 수익도 증가
  • 고객이 비용을 예측하고 예산을 세울 수 있음
  • 개인 사용자에서 팀, 엔터프라이즈로 이어지는 명확한 업그레이드 경로
  • 팀이 확장될수록 고객 생애 가치 증가
고객의 경우:
  • 보유한 사용자 수에 대해서만 비용 지불
  • 비용을 쉽게 이해하고 예측 가능
  • 필요에 따라 사용자 추가 또는 제거
  • 팀 규모에 맞는 공정한 가격 책정

작동 방식

Dodo Payments는 Add-ons 시스템을 사용해 좌석 기반 청구를 구현합니다. 좌석 기반 구독은 다음 두 부분으로 구성됩니다. 고객의 월 총액은 다음과 같습니다.
예시: Team Plan에 seat 8개 추가

가격 책정 전략

비즈니스에 맞는 좌석 기반 가격 책정 전략을 선택하세요:

전략 1: 기본 + 좌석별 부가 기능

기본 요금제에 정해진 수의 좌석을 포함하고 추가 좌석에 대해 요금을 부과합니다.
적합한 경우: 기본 제공 기능만으로 소규모 팀이 업무를 수행할 수 있는 제품.

전략 2: 순수 좌석당 요금제

기본 요금 없이 좌석당 고정 요금을 청구합니다.
구현: 기본 플랜 가격을 $0으로 설정하고 Seat add-on만 사용합니다. 적합한 경우: 간단하고 투명한 가격 책정이 필요한 경우.

전략 3: 단계별 좌석 요금제

기본 요금제와 좌석당 요금이 서로 다른 여러 상품을 제공합니다.
구현: add-on 가격이 서로 다른 각 단계별 상품을 별도로 생성합니다. 적합한 경우: 상위 단계로의 업그레이드 유도, 엔터프라이즈 영업.

전략 4: 좌석 번들

좌석을 개별 단위가 아니라 묶음으로 판매합니다.
구현: 다양한 묶음 크기에 맞는 여러 add-on을 생성합니다. 적합한 경우: 구매 결정을 단순화하고 더 큰 약정을 유도할 때.

좌석 기반 청구 설정

1단계: 가격 정책 계획

구현하기 전에 가격 구조를 정의합니다.
1

Define Base Plan

기본 구독에 포함할 항목을 결정합니다:
  • 기본 가격 (순수한 seat 기반 요금의 경우 $0일 수 있음)
  • 포함된 seat 수
  • 이 등급에서 이용 가능한 기능
2

Set Seat Pricing

좌석당 add-on 비용을 결정합니다.
  • 추가 좌석당 가격
  • 수량 할인(여러 add-on을 통해 제공)
  • 허용되는 최대 좌석 수(해당하는 경우)
3

Consider Billing Frequency

좌석 가격을 청구 주기에 맞춥니다.
  • 월간 구독 → 월간 좌석 요금
  • 연간 구독 → 연간 좌석 요금(대개 할인 적용)

2단계: 좌석 Add-on 생성

Dodo Payments 대시보드에서 다음을 수행합니다.
  1. Products → Add-Ons로 이동합니다.
  2. Create Add-On을 클릭합니다.
  3. add-on을 구성합니다.
인보이스에서 의미가 명확한 설명형 add-on 이름을 사용하세요. 청구서를 검토하는 고객에게는 “Seat Add-on”보다 “Additional Team Seat”가 더 명확합니다.

3단계: 기본 구독 생성

구독 상품을 생성합니다.
  1. Products → Create Product로 이동합니다.
  2. Subscription을 선택합니다.
  3. 가격과 세부 정보를 구성합니다.
  4. Add-Ons 섹션에서 좌석 add-on을 연결합니다.

4단계: 상품에 Add-on 연결

좌석 add-on을 구독에 연결합니다.
  1. 구독 상품을 편집합니다.
  2. Add-Ons 섹션으로 스크롤합니다.
  3. Add Add-Ons를 클릭합니다.
  4. 좌석 add-on을 선택합니다.
  5. 변경 사항을 저장합니다.
이제 구독 상품에서 좌석 기반 가격을 사용할 수 있습니다. 고객은 checkout 중에 원하는 수량의 추가 좌석을 구매할 수 있습니다.

좌석 관리

새 구독에 좌석 추가

checkout session을 생성할 때 좌석 수량을 지정합니다.

기존 구독의 좌석 수 변경

Change Plan API를 사용해 좌석 수를 조정합니다. addons 배열은 변경량이 아니라 새로운 총 좌석 수를 설정합니다.

좌석 제거

좌석 수를 줄이려면 더 낮은 수량을 지정합니다.

모든 추가 좌석 제거

빈 addons 배열을 전달하면 모든 add-on이 제거됩니다.

좌석 변경에 대한 일할 계산

주기 중간에 좌석 변경이 적용되면 Dodo Payments는 다음 세 단계로 즉시 청구 금액을 계산합니다.
크레딧 금액은 선택한 proration mode에 따라 달라집니다. 청구 금액은 항상 전체 주기에 해당합니다.
요금은 항상 전체 주기 기준으로 부과됩니다. 모드에 따라 달라지는 것은 credit뿐입니다. 따라서 청구 금액이 “새 seat 수 × 가격 × 남은 일수”가 되는 경우는 거의 없습니다.prorated_immediately에서는 주기가 진행될수록 credit이 줄어들므로, 동일한 seat 변경이라도 늦게 적용할수록 비용이 더 많이 듭니다. difference_immediately 및 full_immediately에서는 credit이 적용 시점에 따라 달라지지 않으므로, 주기의 어느 날에 변경해도 두 모드의 비용은 동일합니다.

각 모드의 크레딧 방식

difference_immediately에서는 고객이 기존 플랜 가격과 새 플랜 가격의 차액만 지불합니다. 이것이 이름의 유래이며, 주기의 어느 시점에 변경하더라도 금액이 동일한 이유입니다. 크레딧이 새 주기의 청구 금액보다 큰 경우 차액은 구독 범위의 크레딧으로 보관되며 이후 갱신에 자동으로 적용됩니다.
prorated_immediately, difference_immediately, full_immediately는 모두 청구 주기를 변경일로 재설정합니다. 다음 갱신일은 seat 변경이 적용된 날짜를 기준으로 다시 설정됩니다. **do_not_bill**만 기존 갱신일을 유지합니다 (새 seat 수는 다음 갱신 시 전액 청구되며, 변경 시점에는 요금이 부과되지 않음).
do_not_bill는 갱신 시점이 아니라 즉시 좌석 변경을 적용합니다. 호출이 성공하는 즉시 새 좌석 수가 적용되지만 다음 갱신 전까지는 청구되지 않습니다.seat을 추가하면 고객은 현재 주기의 남은 기간 동안 해당 seat을 무료로 사용할 수 있습니다. 30일 주기의 1일 차에 $10인 seat 5개를 추가하면 29일 동안 seat 5개를 무료로 이용하며, 증가한 금액은 기존 갱신일에 처음 청구됩니다.seat을 제거하면 반대가 적용됩니다. 해당 seat은 즉시 회수되며, 이미 결제한 주기의 남은 기간에 대해서는 credit이 제공되지 않습니다.무료 업그레이드나 영업팀과 합의한 추가 좌석 체험처럼 이러한 동작을 의도한 경우 do_not_bill를 사용하세요.

예시: 좌석 5개 추가

네 가지 모드로 하나의 시나리오를 실행하여 수치를 직접 비교합니다.
세 가지 즉시 적용 모드에서는 고객이 오늘 지불하는 금액에 대한 대가로 $130의 새로운 한 달 전체 기간을 받습니다.

prorated_immediately에서 시점이 중요한 이유

주기 후반에 변경할수록 돌려받을 수 있는 현재 주기의 크레딧이 줄어들기 때문에 같은 변경의 비용이 더 커집니다.
모든 행에서 고객은 새 월간 주기 전체를 받습니다. 달라지는 것은 “이미 지불한 금액”과 “지금 지불하는 금액”의 분배뿐입니다. 시점과 관계없이 seat 변경 비용을 동일하게 만들려면 difference_immediately를 사용하세요.

예시: “예상 밖의 청구”

판매자가 가장 자주 놀라는 사례입니다. 주기 후반에 소액의 좌석 add-on을 추가하면 add-on 가격보다 훨씬 큰 금액이 청구될 수 있습니다.
$10/월 seat 1개를 추가하면 prorated_immediately에서 비용은 $55.00입니다. 고객에게는 $60의 새로운 한 달 전체 기간에 대한 요금이 청구되고, 기존 월에 남아 있던 $5가 credit으로 적용되며, 갱신일이 재설정됩니다. 주기 중간에 seat을 소량 추가할 때 seat 가격만 부과하고 추가 비용은 없도록 하려면 difference_immediately를 사용하세요.

예시: 좌석 제거(다운그레이드)

새 요금제가 크레딧보다 저렴한 경우 초과분은 구독 크레딧으로 보관되며 이 구독의 이후 갱신에 자동으로 적용됩니다. 이 크레딧은 Customer Wallet에 추가되지 않으며 credit entitlement도 아닙니다.
credit은 제거되는 seat뿐 아니라 기본 플랜과 모든 add-on을 포함한 구독 전체에 적용됩니다.

Preview 응답 읽기

previewChangePlan는 청구될 정확한 line item을 반환합니다. 각 line item에는 proration_factor가 있습니다.
이를 해석하면 다음과 같습니다. 기본 $50과 3 × $10 add-on에 대해 50%가 credit으로 적용되고, 기본 플랜 전체 $50이 청구되며, add-on 8 × $10이 청구됩니다. Credit = $40, charge = $130, 순액 = $90입니다.
일할 계산은 가장 가까운 일 단위로 반올림하지 않고 변경이 발생한 정확한 시점을 기준으로 초 단위까지 계산됩니다. 위의 예시는 이해를 돕기 위해 일 단위 경계의 수치를 사용했습니다.
좌석 변경에 대한 일할 계산 모드 선택
  • difference_immediately — 변경 시점과 관계없이 고객은 가격 차액을 지불합니다. seat을 자주 조정하는 팀에 가장 예측 가능하며, UI에서 설명하기도 가장 쉽습니다.
  • prorated_immediately — 고객은 현재 주기에 남은 기간에 대해서만 credit을 받습니다. 주기 후반에 변경할수록 비용이 더 많이 듭니다.
  • full_immediately — 고객은 사용하지 않은 기간에 대한 credit 없이 새로운 전체 주기 요금을 지불합니다.
  • do_not_bill — seat 변경은 즉시 적용되지만 지금은 요금이 부과되지 않습니다. 추가된 seat은 다음 갱신일까지 무료이며, 제거된 seat은 credit 없이 회수됩니다. 갱신일은 유지되고, 해당 갱신일부터 새로운 seat 수가 전액 청구됩니다. 청구 주기를 재설정하지 않는 유일한 모드입니다.
do_not_bill를 통해 부여된 좌석은 청구된 적이 없으므로 이후 요금제 변경 시 크레딧으로 처리되지 않습니다. do_not_bill로 좌석 5개를 추가한 뒤 좌석 3개로 변경하면 고객에게는 좌석 3개가 전액 청구되며, 사용 중이던 좌석 5개에 대한 크레딧은 제공되지 않습니다.
항상 previewChangePlan를 호출하고 확인 전에 반환된 금액을 표시하세요. 자세한 비교는 Proration Guide를 참고하세요.

변경 전 Preview

변경하기 전에 항상 일할 계산을 미리 확인합니다.

Webhook으로 좌석 추적

구독 webhook을 수신해 좌석 변경을 모니터링합니다.

관련 이벤트

Webhook handler 예시

webhook payload의 addons 배열에는 현재 add-on 수량이 포함됩니다. 이를 합산하면 총 좌석 수를 얻을 수 있습니다. 기본 요금제에 좌석이 포함된 경우(예: 5개 포함), 애플리케이션 로직에서 이를 add-on 총량에 더하세요.

좌석 한도 적용

애플리케이션에서 좌석 한도를 적용해야 합니다. Dodo Payments는 청구를 추적하지만 액세스 권한은 사용자가 제어합니다.
좌석 수를 초과해 사용자를 추가하지 못하도록 엄격하게 제한합니다.

고급 패턴

다양한 좌석 유형

가격이 서로 다른 여러 좌석 유형을 제공합니다.
구현: 각 좌석 유형에 대해 별도의 add-on을 생성합니다.

연간 좌석 할인

할인된 연간 좌석 가격을 제공합니다.
구현: add-on 가격이 서로 다른 월간 및 연간 요금제 상품을 별도로 생성합니다.

최소 좌석 요구 사항

특정 요금제에 최소 좌석 수를 요구합니다.

모범 사례

가격 정책 모범 사례

  • 명확한 커뮤니케이션: 가격 페이지에 좌석당 가격을 눈에 잘 띄게 표시합니다.
  • 포함 좌석: 진입 장벽을 낮추기 위해 기본 가격에 일부 좌석을 포함하는 방안을 고려합니다.
  • 수량 할인: 엔터프라이즈 계약을 확보하기 위해 대규모 팀에 더 낮은 좌석당 요금을 제공합니다.
  • 연간 인센티브: 현금 흐름과 고객 유지율을 개선하기 위해 연간 요금제를 할인합니다.

기술적 모범 사례

  • 좌석 수 캐시: 모든 요청에서 API를 호출하지 않도록 구독 좌석 수를 로컬에 캐시합니다.
  • 정기 동기화: API를 통해 로컬 좌석 수를 Dodo Payments와 주기적으로 동기화합니다.
  • 실패 처리: 좌석 변경이 실패하면 명확한 오류 메시지와 재시도 옵션을 표시합니다.
  • 감사 추적: 청구 분쟁과 규정 준수를 위해 모든 좌석 변경을 기록합니다.

사용자 경험 모범 사례

  • 실시간 피드백: seat을 조정할 때 비용 영향을 즉시 표시
  • 확인 단계: 청구 변경 전에 확인을 요청
  • Proration 투명성: 적용 전에 일할 계산된 요금을 명확히 설명
  • 간편한 다운그레이드: seat을 줄이는 과정을 어렵게 만들지 않기 (신뢰 구축에 도움이 됨)

문제 해결

증상: 앱에 표시되는 좌석 수가 구독의 좌석 수와 다릅니다.원인:
  • Webhook을 수신하거나 처리하지 못함
  • 좌석 변경 중 race condition 발생
  • 캐시된 데이터가 업데이트되지 않음
해결 방법:
  1. subscription.plan_changed에 대한 webhook handler를 구현합니다.
  2. 현재 구독을 가져오는 “Sync with billing” 버튼을 추가합니다.
  3. 정기적으로 새로 고침되도록 캐시 TTL을 설정합니다.
증상: 고객이 주기 중간의 청구 금액을 이해하지 못합니다.원인: 청구 주기 후반에 prorated_immediately를 사용함(위의 The Surprising Charge 예시 참고).해결 방법:
  1. 변경하기 전에 항상 previewChangePlan를 사용합니다
  2. 명확한 내역을 표시합니다: “seat X개를 추가하면 오늘 $Y가 청구됩니다”
  3. 요금이 항상 가격 차액과 일치하도록 하려면 difference_immediately로 전환합니다
증상: checkout 중에 좌석 add-on을 사용할 수 없습니다.원인:
  • 상품에 add-on이 연결되지 않음
  • add-on이 보관 처리되었거나 삭제됨
  • 상품과 add-on의 통화가 일치하지 않음
해결 방법:
  1. 상품 설정에서 add-on이 연결되어 있는지 확인합니다.
  2. Add-Ons 대시보드에서 add-on 상태를 확인합니다.
  3. 통화가 정확히 일치하는지 확인합니다.
증상: 고객이 사용자를 할당한 상태에서 좌석을 줄이려고 합니다.해결 방법:
  1. 좌석을 줄이기 전에 제거해야 하는 사용자를 표시합니다.
  2. 사용자 제거 → 좌석 축소의 workflow를 구현합니다.
  3. 좌석 축소를 적용하기 전에 유예 기간을 고려합니다.

관련 문서

Seat-Based Pricing Tutorial

코드가 포함된 전체 구현 가이드.

Add-ons

add-on 시스템을 자세히 이해합니다.

Plan Changes & Proration

구독 수정 사항을 처리합니다.

Subscription Webhooks

구독 이벤트를 추적합니다.
마지막 수정일 2026년 9월 26일