메인 콘텐츠로 건너뛰기

개요

온디맨드 구독을 사용하면 고객의 결제 수단을 한 번 승인한 후 필요할 때마다 고정된 일정이 아닌 변동 금액을 청구할 수 있습니다. 이 기능은 모든 계정에서 사용할 수 있으며, 승인이 필요하지 않습니다. 이 가이드를 사용하여:
  • 온디맨드 구독 생성하기 (선택적 초기 가격으로 위임 승인하기)
  • 사용자 정의 금액으로 후속 청구 트리거하기
  • 웹훅을 사용하여 결과 추적하기
일반 구독 설정에 대한 내용은 구독 통합 가이드를 참조하세요.

전제 조건

  • Dodo Payments 상인 계정 및 API 키
  • 이벤트를 수신할 웹훅 비밀 및 엔드포인트 구성
  • 카탈로그에 구독 제품이 있어야 합니다.
고객이 호스팅된 체크아웃을 통해 위임을 승인하도록 하려면 payment_link: true를 설정하고 return_url를 제공하세요.

온디맨드 작동 방식

  1. 결제 수단을 승인하고 선택적으로 초기 요금을 수집하기 위해 on_demand 객체로 구독을 생성합니다.
  2. 나중에 전용 청구 엔드포인트를 사용하여 해당 구독에 대해 사용자 정의 금액으로 청구를 생성합니다.
  3. 웹훅(예: payment.succeeded, payment.failed)를 수신하여 시스템을 업데이트합니다.

온디맨드 구독 생성하기

엔드포인트: POST /checkouts 주요 요청 필드 (본문):
체크아웃 세션 생성하기에서 확인하세요.

온디맨드 구독 생성하기

import DodoPayments from 'dodopayments';

const client = new DodoPayments({
  bearerToken: process.env.DODO_PAYMENTS_API_KEY,
  environment: 'test_mode', // defaults to 'live_mode'
});

async function main() {
  const subscription = await client.checkoutSessions.create({
    product_cart: [{ product_id: 'pdt_123', quantity: 1 }],
    billing_address:  { city: 'SF', country: 'US', state: 'CA', street: '1 Market St', zipcode: '94105' },
    customer: { customer_id: 'cus_123' },
    return_url: 'https://example.com/billing/success',
    subscription_data: {
        on_demand: {
            mandate_only: true // set false to collect an initial charge
            // product_price: 1000, // optional: charge $10.00 now if mandate_only is false
            // product_currency: 'USD',
            // product_description: 'Custom initial charge',
            // adaptive_currency_fees_inclusive: false,
        }
    }
  });

  console.log(subscription.checkout_url);
}

main().catch(console.error);
Success
{
  "session_id": "cks_123",
  "checkout_url": "https://test.checkout.dodopayments.com/session/cks123"
}

온디맨드 구독 청구하기

위임이 승인된 후 필요에 따라 청구를 생성합니다. 엔드포인트: POST /subscriptions/{subscription_id}/charge 주요 요청 필드 (본문):
product_price
integer
필수
청구할 금액 (가장 작은 통화 단위). 예: $25.00를 청구하려면 2500을 전달하세요.
product_currency
string
청구에 대한 선택적 통화 재정의.
product_description
string
이 청구에 대한 선택적 설명 재정의.
adaptive_currency_fees_inclusive
boolean
true인 경우 product_price에 적응형 통화 수수료를 포함합니다. false인 경우 수수료가 추가됩니다.
metadata
object
결제에 대한 추가 메타데이터. 생략할 경우 구독 메타데이터가 사용됩니다.
import DodoPayments from 'dodopayments';

const client = new DodoPayments({ bearerToken: process.env.DODO_PAYMENTS_API_KEY });

async function chargeNow(subscriptionId) {
  const res = await client.subscriptions.charge(subscriptionId, { product_price: 2500 });
  console.log(res.payment_id);
}

chargeNow('sub_123').catch(console.error);
Success
{ "payment_id": "pay_abc123" }
온디맨드가 아닌 구독에 대해 청구하면 실패할 수 있습니다. 청구하기 전에 구독에 on_demand: true가 포함되어 있는지 확인하세요.

결제 재시도

우리의 사기 탐지 시스템은 공격적인 재시도 패턴을 차단할 수 있으며 (잠재적인 카드 테스트로 표시될 수 있음) 안전한 재시도 정책을 따르세요.
버스트 재시도 패턴은 우리의 위험 시스템 및 프로세서에 의해 사기 또는 의심스러운 카드 테스트로 표시될 수 있습니다. 클러스터 재시도를 피하고 아래의 백오프 일정 및 시간 정렬 지침을 따르세요.

안전한 재시도 정책을 위한 원칙

  • 백오프 메커니즘: 재시도 간에 지수 백오프를 사용하세요.
  • 재시도 한도: 총 재시도를 제한하세요 (최대 3-4회 시도).
  • 지능형 필터링: 재시도 가능한 실패(예: 네트워크/발급자 오류, 자금 부족)에서만 재시도하세요; 하드 거부는 재시도하지 마세요.
  • 카드 테스트 방지: DO_NOT_HONOR, STOLEN_CARD, LOST_CARD, PICKUP_CARD, FRAUDULENT, AUTHENTICATION_FAILURE와 같은 실패는 재시도하지 마세요.
  • 메타데이터 다양화 (선택적): 자체 재시도 시스템을 유지하는 경우 메타데이터를 통해 재시도를 구분하세요 (예: retry_attempt).

권장 재시도 일정 (구독)

  • 1차 시도: 청구를 생성할 때 즉시
  • 2차 시도: 3일 후
  • 3차 시도: 7일 후 (총 10일)
  • 4차 시도 (최종): 7일 후 (총 17일)
최종 단계: 여전히 미납인 경우, 정책에 따라 구독을 미납으로 표시하거나 취소하세요. 고객에게 결제 수단을 업데이트할 수 있는 기간 동안 알림을 보내세요.

버스트 재시도를 피하고 승인 시간에 맞추기

  • 재시도를 원래 승인 타임스탬프에 고정하여 포트폴리오 전반에 걸쳐 “버스트” 동작을 피하세요.
  • 예: 고객이 오늘 오후 1:10에 체험판 또는 위임을 시작하면, 후속 재시도를 백오프에 따라 다음 날 오후 1:10에 예약하세요 (예: +3일 → 오후 1:10, +7일 → 오후 1:10).
  • 또는 마지막 성공적인 결제 시간을 저장하는 경우 T, 다음 시도를 T + X days에 예약하여 시간대 정렬을 유지하세요.
시간대 및 DST: 일정을 위해 일관된 시간 표준을 사용하고 표시를 위해서만 변환하여 간격을 유지하세요.

재시도하지 말아야 할 거부 코드

  • STOLEN_CARD
  • DO_NOT_HONOR
  • FRAUDULENT
  • PICKUP_CARD
  • AUTHENTICATION_FAILURE
  • LOST_CARD
거부 사유의 포괄적인 목록과 사용자가 수정할 수 있는지 여부는 거래 실패 문서를 참조하세요.
소프트/임시 문제에서만 재시도하세요 (예: insufficient_funds, issuer_unavailable, processing_error, 네트워크 타임아웃). 동일한 거부가 반복되면 추가 재시도를 중단하세요.

구현 지침 (코드 없음)

  • 정확한 타임스탬프를 지속하는 스케줄러/큐를 사용하세요; 다음 시도를 정확한 시간대 오프셋에서 계산하세요 (예: T + 3 days에서 같은 HH:MM).
  • 마지막 성공적인 결제 타임스탬프 T를 유지하고 참조하여 다음 시도를 계산하세요; 여러 구독을 동시에 묶지 마세요.
  • 마지막 거부 사유를 항상 평가하세요; 위의 스킵 목록에서 하드 거부에 대한 재시도를 중단하세요.
  • 고객 및 계정당 동시 재시도를 제한하여 우발적인 급증을 방지하세요.
  • 사전적으로 소통하세요: 다음 예정된 시도 전에 고객에게 결제 수단을 업데이트하라는 이메일/SMS를 보내세요.
  • 메타데이터는 관찰 가능성을 위해서만 사용하세요 (예: retry_attempt); 중요하지 않은 필드를 회전하여 사기/위험 시스템을 “회피”하려고 하지 마세요.

웹훅으로 결과 추적하기

웹훅 처리를 구현하여 고객 여정을 추적하세요. 웹훅 구현하기를 참조하세요.
  • subscription.active: 위임이 승인되고 구독이 활성화됨
  • subscription.failed: 생성 실패 (예: 위임 실패)
  • subscription.on_hold: 구독이 보류됨 (예: 미납 상태)
  • payment.succeeded: 청구 성공
  • payment.failed: 청구 실패
온디맨드 흐름의 경우, 사용 기반 청구를 조정하기 위해 payment.succeededpayment.failed에 집중하세요.

테스트 및 다음 단계

1

테스트 모드에서 생성하기

테스트 API 키를 사용하여 payment_link: true로 구독을 생성한 후, 링크를 열고 위임을 완료하세요.
2

청구 트리거하기

작은 product_price (예: 100)로 청구 엔드포인트를 호출하고 payment.succeeded를 수신하는지 확인하세요.
3

라이브로 전환하기

이벤트 및 내부 상태 업데이트를 검증한 후 라이브 API 키로 전환하세요.

문제 해결

  • 422 잘못된 요청: 생성 시 on_demand.mandate_only가 제공되었는지 확인하고, 청구를 위해 product_price가 제공되었는지 확인하세요.
  • 통화 오류: product_currency를 재정의하는 경우, 해당 통화가 귀하의 계정 및 고객에게 지원되는지 확인하세요.
  • 웹훅을 수신하지 못함: 웹훅 URL 및 서명 비밀 구성 확인.