Documentation Index
Fetch the complete documentation index at: https://docs.dodopayments.com/llms.txt
Use this file to discover all available pages before exploring further.
Change Plan API
Plan Change Preview
Integration Guide
What is a subscription upgrade or downgrade?
Changing plans lets you move a customer between subscription tiers or quantities. Use it to:- Align pricing with usage or features
- Move from monthly to annual (or vice versa)
- Adjust quantity for seat-based products
When to use plan changes
- Upgrade when a customer needs more features, usage, or seats
- Downgrade when usage decreases
- Migrate users to a new product or price without cancelling their subscription
Plan Change Flow
Prerequisites
Before implementing subscription plan changes, ensure you have:- A Dodo Payments merchant account with active subscription products
- API credentials (API key and webhook secret key) from the dashboard
- An existing active subscription to modify
- Webhook endpoint configured to handle subscription events
Step-by-Step Implementation Guide
Follow this comprehensive guide to implement subscription plan changes in your application:Understand Plan Change Requirements
- Which subscription products can be changed to which others
- What proration mode fits your business model
- How to handle failed plan changes gracefully
- Which webhook events to track for state management
Choose Your Proration Strategy
- prorated_immediately
- difference_immediately
- full_immediately
- do_not_bill
- Calculates exact prorated amount based on remaining cycle time
- Charges a prorated amount based on unused time remaining in the cycle
- Provides transparent billing to customers
Implement the Change Plan API
prorated_immediately, full_immediately, difference_immediately, or do_not_bill.prevent_change: Keep subscription on current plan until payment succeedsapply_change(default): Apply plan change immediately regardless of payment outcome
- 미제공 /
null— 새로운 제품에 적용 가능한 경우 기존 할인은preserve_on_plan_change=true와 함께 유지됩니다. [](빈 배열) — 구독에서 모든 기존 할인을 제거합니다.["CODE_A", "CODE_B", ...]— 기존 할인을 이 중첩 세트로 교체합니다.
discount_codes 사용 권장. 이 필드는 하위 호환성을 위해 여전히 작동하지만, 같은 요청에서 discount_codes와 결합할 수 없습니다.immediately(기본값): 즉시 플랜 변경 적용next_billing_date: 다음 청구 날짜에 변경 예약. 고객은 청구 기간이 끝날 때까지 현재 플랜을 유지합니다.
next_billing_date를 사용하여 고객이 청구 기간이 끝날 때까지 현재 플랜 혜택을 유지하도록 합니다.Handle Webhook Events
subscription.active: 플랜 변경 성공, 구독 업데이트됨subscription.plan_changed: 구독 플랜 변경 (업그레이드/다운그레이드/애드온 업데이트)subscription.on_hold: 플랜 변경 요금 실패, 구독이 일시 중지됨payment.succeeded: 플랜 변경의 즉시 요금 성공payment.failed: 즉시 요금 실패
Update Your Application State
- 새 플랜에 따라 기능 부여/취소
- 새 플랜 세부 정보로 고객 대시보드 업데이트
- 플랜 변경 확인 이메일 발송
- 감사 목적을 위한 청구 변경 로그
플랜 변경 미리보기
플랜 변경을 확정하기 전에 Preview API를 사용하여 고객에게 정확히 청구될 금액을 보여주십시오:- Node.js SDK
- Python SDK
플랜 변경 API
Change Plan API를 사용하여 활성 구독의 제품, 수량 및 비례 동작을 수정하십시오.빠른 시작 예제
- Node.js SDK
- Python SDK
- Go SDK
- HTTP
invoice_id 및 payment_id와 같은 필드는 플랜 변경 중 즉시 요금 및/또는 인보이스가 생성될 때만 반환됩니다. 항상 결과를 확인하기 위해 웹훅 이벤트(예: payment.succeeded, subscription.plan_changed)를 신뢰하십시오.Addons 관리
구독 플랜을 변경할 때 Addons도 수정할 수 있습니다:할인 코드 적용
구독 플랜 변경 시 하나 이상의 중첩 할인 코드를 적용할 수 있습니다 (최대 20개, 배열 순서대로 적용). 이는 업그레이드나 마이그레이션 시 프로모션 가격을 제공하는 데 유용합니다.- Node.js SDK
- Python SDK
- HTTP
플랜 변경 시 할인 적용 동작
discount_codes 값 | 동작 |
|---|---|
미제공 / null | 새로운 제품에 적용 가능한 경우 preserve_on_plan_change=true와 함께 기존 할인이 자동으로 유지됩니다. |
[] (빈 배열) | 모든 기존 할인이 구독에서 제거됩니다. |
["CODE_A", "CODE_B", ...] | 이 중첩 세트로 기존 할인을 교체하고, 배열 순서대로 검증 및 적용됩니다. |
discount_code 필드는 사용 중단됨이지만 여전히 하위 호환성을 위해 작동합니다 — 기존 통합은 즉시 변경할 필요가 없습니다. 같은 요청에서 discount_codes와 결합할 수 없습니다. 편리할 때 배열 형식으로 마이그레이션하십시오.비례 모드
플랜 변경 시 고객 청구 방식을 선택하십시오:prorated_immediately
- 현재 사이클의 부분 차액에 대해 청구
- 트라이얼 중인 경우 즉시 청구하고 새 플랜으로 전환
- 다운그레이드: 미래 갱신에 적용될 비례 크레딧 생성 가능
full_immediately
- 새 플랜의 전체 금액을 즉시 청구
- 이전 플랜의 남은 시간을 무시
difference_immediately를 사용한 다운그레이드에서 생성된 크레딧은 구독 범위 내에서 정확히 사용되며 Credit-Based Billing 권한과는 별개입니다. 동일한 구독의 미래 갱신에 자동으로 적용되고 다른 구독 간에 양도될 수 없습니다.difference_immediately
- 업그레이드: 이전 플랜과 새 플랜 간의 가격 차이를 즉시 청구
- 다운그레이드: 남은 가치를 구독의 내부 크레딧으로 추가하고 갱신 시 자동 적용
do_not_bill
- 청구나 크레딧이 계산되지 않음
- 고객은 청구 조정 없이 즉시 새 플랜으로 전환
- 청구 주기는 변경되지 않음
- 무료 마이그레이션, 플랜 변경 시 또는 비용 차이를 흡수하는 데 적합
| 기능 | prorated_immediately | difference_immediately | full_immediately | do_not_bill |
|---|---|---|---|---|
| 업그레이드 요금 | 남은 날에 대한 비례 차액 | 플랜 간의 전체 금액 차이 | 새 플랜의 전체 금액 | 요금 없음 |
| 다운그레이드 크레딧 | 남은 날에 대한 비례 크레딧 | 전체 금액 차이로 크레딧 | 크레딧 없음 | 크레딧 없음 |
| 청구 주기 | 변경 없음 | 변경 없음 | 오늘로 재설정 | 변경 없음 |
| 트라이얼 동작 | 트라이얼 종료, 즉시 청구 | 트라이얼 종료, 즉시 청구 | 트라이얼 종료, 전체 금액 청구 | 트라이얼 종료, 요금 없음 |
| 최적 사용 사례 | 공정한 시간 기반 청구 | 간단한 업그레이드/다운그레이드 계산 | 청구 주기 재설정 | 무료 마이그레이션 또는 예우 제공 |
| 복잡성 | 중간 (일 계산) | 낮음 (간단한 뺄셈) | 낮음 (전체 청구) | 없음 |
예제 시나리오
이 표준 숫자를 일관되게 사용하십시오:- 현재 플랜: Basic 월 $30
- 업그레이드 대상: Pro 월 $80
- 다운그레이드 대상 (Pro에서): Starter 월 $20
- 청구 주기: 30일, 1월 1일 시작
- 플랜 변경은 1월 16일에 발생 (15일 남음, 15일 사용)
Upgrade: Basic ($30) → Pro ($80) with prorated_immediately
Upgrade: Basic ($30) → Pro ($80) with prorated_immediately
Downgrade: Pro ($80) → Starter ($20) with prorated_immediately
Downgrade: Pro ($80) → Starter ($20) with prorated_immediately
Upgrade: Basic ($30) → Pro ($80) with difference_immediately
Upgrade: Basic ($30) → Pro ($80) with difference_immediately
Downgrade: Pro ($80) → Starter ($20) with difference_immediately
Downgrade: Pro ($80) → Starter ($20) with difference_immediately
Upgrade: Basic ($30) → Pro ($80) with full_immediately
Upgrade: Basic ($30) → Pro ($80) with full_immediately
Mid-cycle upgrade with add-ons using prorated_immediately
Mid-cycle upgrade with add-ons using prorated_immediately
각 모드가 청구를 처리하는 방법
결제 실패 처리
플랜 변경 결제 실패 시on_payment_failure 매개변수를 사용하여 결과를 제어합니다.
결제 실패 모드
- prevent_change (Recommended for critical upgrades)
- apply_change (Default)
- 플랜 변경은 “보류 중”으로 표시됩니다
- 고객은 현재 플랜에 대한 접근을 유지합니다
- 결제가 성공한 후에만 구독이
active상태로 이동 - 업그레이드된 기능을 제공하기 전에 결제를 보장하고자 할 때 유용
on_payment_failure 매개변수는 대시보드에서 구성된 비즈니스 수준 기본 설정을 사용합니다.각 모드를 사용할 시기
| 시나리오 | 권장 모드 | 이유 |
|---|---|---|
| 프리미엄 기능으로 업그레이드 | prevent_change | 기능을 제공하기 전에 결제 보장 |
| 수량 증가 (더 많은 좌석) | prevent_change | 결제 없이 사용 방지 |
| 플랜 다운그레이드 | apply_change | 고객이 지출을 줄임 |
| 신뢰할 수 있는 엔터프라이즈 고객 | apply_change | 미결제 위험 낮음 |
| 시도에서 유료 전환 | prevent_change | 중요한 결제 순간 |
웹훅 처리
웹훅을 통해 구독 상태를 추적하여 플랜 변경 및 결제를 확인합니다.처리할 이벤트 유형
subscription.active: 구독 활성화됨subscription.plan_changed: 구독 플랜 변경 (업그레이드/다운그레이드/애드온 변경)subscription.on_hold: 요금 실패, 구독 일시 중단subscription.renewed: 갱신 성공payment.succeeded: 플랜 변경 또는 갱신에 대한 결제 성공payment.failed: 결제 실패
서명 확인 및 의도 처리
- Next.js Route Handler
- Express.js
모범 사례
신뢰할 수 있는 구독 플랜 변경을 위한 이 권장사항을 따르십시오:플랜 변경 전략
- 철저히 테스트: 항상 테스트 모드에서 플랜 변경을 테스트한 후 프로덕션으로 전환
- 비례 검토를 신중히 선택: 비즈니스 모델에 맞는 비례 모드를 선택
- 실패를 우아하게 처리: 적절한 오류 처리 및 재시도 로직 구현
- 성공률 모니터링: 플랜 변경 성공/실패율을 추적하고 문제 조사
웹훅 구현
- 서명 확인: 항상 웹훅 서명을 확인하여 진위를 보장
- 불변성 구현: 중복된 웹훅 이벤트를 우아하게 처리
- 비동기식 처리: 웹훅 응답을 무거운 작업으로 차단하지 않기
- 모든 것을 로그: 디버깅 및 감사 목적을 위한 세부 로그 유지
사용자 경험
- 명확하게 커뮤니케이션: 고객에게 청구 변경 및 시기를 알림
- 확인 제공: 성공적인 플랜 변경에 대해 이메일 확인 발송
- 경계 사례 처리: 트라이얼 기간, 비례, 실패한 결제를 고려
- 즉시 UI 업데이트: 플랜 변경을 애플리케이션 인터페이스에 반영
일반 문제 및 솔루션
구독 플랜 변경 중 발생하는 일반적인 문제 해결:Charge created but subscription not updated
Charge created but subscription not updated
- 웹훅 처리가 실패했거나 지연됨
- 웹훅 수신 후 애플리케이션 상태가 업데이트되지 않음
- 상태 업데이트 중 데이터베이스 트랜잭션 문제
- 강력한 웹훅 처리를 구현하여 재시도 로직 추가
- 상태 업데이트를 위한 불변 작업 사용
- 누락된 웹훅 이벤트를 감지하고 경고하는 모니터링 추가
- 웹훅 엔드포인트가 접근 가능하고 올바르게 응답하는지 확인
Credits not applied after downgrade
Credits not applied after downgrade
- 비례 모드 기대치: 다운그레이드는
difference_immediately로 전체 플랜 가격 차액을 크레딧으로 적립하고,prorated_immediately는 남은 시간 기반으로 비례 크레딧 생성 - 크레딧은 구독 전용이며 다른 구독 간에 양도되지 않음
- 고객 대시보드에서 크레딧 잔액이 보이지 않음
- 다운그레이드 시 자동 크레딧을 원하면
difference_immediately사용 - 크레딧은 동일한 구독의 미래 갱신에 적용됨을 고객에게 설명
- 크레딧 잔액을 보여주는 고객 포털 구현
- 다음 인보이스 미리보기를 확인하여 적용된 크레딧 확인
Webhook signature verification fails
Webhook signature verification fails
- 잘못된 웹훅 비밀 키
- 서명 확인 전 원시 요청 본문 수정됨
- 잘못된 서명 확인 알고리즘
- 대시보드에서 올바른
DODO_WEBHOOK_SECRET사용을 확인 - JSON 구문 분석 미들웨어 전 원시 요청 본문 읽기
- 플랫폼에 맞는 표준 웹훅 확인 라이브러리 사용
- 개발 환경에서 웹훅 서명 확인 테스트
Plan change fails with 422 error
Plan change fails with 422 error
- 잘못된 구독 ID나 제품 ID
- 구독이 활성 상태가 아님
- 필수 매개변수 누락
- 플랜 변경에 사용 불가능한 제품
- 구독이 존재하고 활성 상태인지 확인
- 제품 ID가 유효하고 사용 가능한지 확인
- 모든 필수 매개변수가 제공되었는지 확인
- 매개변수 요건에 대한 API 문서를 검토
Immediate charge fails during plan change
Immediate charge fails during plan change
- 고객 결제 수단의 자금 부족
- 결제 수단 만료 또는 무효
- 은행이 거래를 거부함
- 사기 감지로 요금이 차단됨
payment.failed웹훅 이벤트를 적절히 처리- 고객에게 결제 수단 업데이트 알림
- 임시 실패에 대한 재시도 로직 구현
- 실패한 즉시 요금으로 플랜 변경 허용 고려
Subscription on hold after plan change
Subscription on hold after plan change
on_hold 상태로 이동발생 현상:
플랜 변경 요금이 실패하면 구독이 자동으로 on_hold 상태로 배치됩니다. 결제 수단이 업데이트될 때까지 구독은 자동 갱신되지 않습니다.해결책: 결제 수단을 업데이트하여 구독을 재활성화실패한 플랜 변경 후 on_hold 상태에서 구독을 재활성화하려면:- 결제 수단 업데이트를 Update Payment Method API를 사용하여 수행
- 자동 요금 생성: API는 남은 금액에 대한 요금을 자동으로 생성
- 인보이스 생성: 요금에 대한 인보이스 생성
- 결제 처리: 새 결제 수단을 사용하여 결제 처리
- 재활성화: 결제가 성공하면 구독이
active상태로 재활성화
subscription.on_hold: 플랜 변경 요금 실패 시 구독이 홀드됨payment.succeeded: 결제 수단 업데이트 후 남은 금액 결제 성공subscription.active: 결제 성공 후 구독이 재활성화됨
- 플랜 변경 요금 실패 시 고객에게 즉시 알림
- 결제 수단 업데이트 방법에 대한 명확한 지침 제공
- 재활성화 상태 추적을 위한 웹훅 이벤트 모니터링
- 임시 결제 실패에 대한 자동 재시도 로직 구현 고려
Update Payment Method API Reference
구현 테스트
구독 플랜 변경 구현을 철저히 테스트하려면 다음 단계를 따르십시오:Test different proration modes
- 다양한 청구 주기 상태로
prorated_immediately테스트 - 업그레이드 및 다운그레이드를 위한
difference_immediately테스트 - 청구 주기 재설정을 위한
full_immediately테스트 - 청구/크레딧 없는 플랜 변경을 위한
do_not_bill테스트 - 크레딧 계산이 올바른지 확인
오류 처리
구현에서 일반적인 API 오류를 우아하게 처리하십시오:HTTP 상태 코드
200 OK
200 OK
400 Bad Request
400 Bad Request
401 Unauthorized
401 Unauthorized
404 Not Found
404 Not Found
422 Unprocessable Entity
422 Unprocessable Entity
500 Internal Server Error
500 Internal Server Error