메인 콘텐츠로 건너뛰기

개요

온디맨드 구독을 사용하면 고객의 결제 수단을 한 번 승인한 후, 고정된 일정 대신 필요할 때마다 가변 금액을 청구할 수 있습니다.
이 기능은 귀하의 계정에서 활성화해야 할 수 있습니다. 대시보드에서 보이지 않는 경우 지원팀에 문의하십시오.
이 가이드를 사용하여:
  • 온디맨드 구독 생성(선택적 초기 가격으로 위임 승인)
  • 사용자 정의 금액으로 후속 요금 트리거
  • 웹훅을 사용하여 결과 추적
일반 구독 설정에 대한 내용은 구독 통합 가이드를 참조하십시오.

전제 조건

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

온디맨드 작동 방식

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

온디맨드 구독 생성

엔드포인트: POST /subscriptions 주요 요청 필드(본문):
product_id
string
required
구독의 제품 ID입니다.
quantity
integer
required
단위 수. 최소 1입니다.
billing
object
required
고객의 청구 주소입니다.
customer
object
required
기존 고객을 연결하거나 고객 세부정보를 제공합니다.
true인 경우, 위임 승인을 위한 호스팅된 체크아웃 링크를 생성하고 선택적 초기 결제를 제공합니다.
return_url
string
호스팅된 체크아웃을 완료한 후 고객을 리디렉션할 위치입니다.
on_demand.mandate_only
boolean
required
true인 경우, 생성 중에 고객에게 요금을 청구하지 않고 결제 수단을 승인합니다.
on_demand.product_price
integer
초기 청구 금액(가장 작은 통화 단위). 지정된 경우, 이 값은 제품 생성 시 설정된 원래 가격을 덮어씁니다. 생략하면 제품의 저장된 가격이 사용됩니다. 예: $1.00를 청구하려면 100을 전달하십시오.
on_demand.product_currency
string
초기 청구에 대한 선택적 통화 재정의입니다. 기본값은 제품 통화입니다.
on_demand.product_description
string
청구 및 항목에 대한 선택적 설명 재정의입니다.
on_demand.adaptive_currency_fees_inclusive
boolean
true인 경우, product_price에 적응형 통화 수수료를 포함합니다. false인 경우, 수수료가 추가됩니다. 적응형 가격 책정이 비활성화된 경우 무시됩니다.

온디맨드 구독 생성

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.subscriptions.create({
    billing: { city: 'SF', country: 'US', state: 'CA', street: '1 Market St', zipcode: '94105' },
    customer: { customer_id: 'customer_123' },
    product_id: 'prod_sub_123',
    quantity: 1,
    payment_link: true,
    return_url: 'https://example.com/billing/success',
    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,
    },
  });

  // If payment_link was true, redirect the customer to authorize the mandate
  console.log(subscription.payment_link);
}

main().catch(console.error);
payment_link: true를 설정하고, 고객을 payment_link로 리디렉션하여 위임 승인을 완료하십시오.
Success
{
  "subscription_id": "sub_123",
  "payment_link": "https://pay.dodopayments.com/checkout/...",
  "customer": { "customer_id": "customer_123", "email": "[email protected]", "name": "Alex Doe" },
  "metadata": {},
  "recurring_pre_tax_amount": 0,
  "addons": []
}

온디맨드 구독 요금 청구

위임이 승인된 후 필요에 따라 요금을 생성합니다. 엔드포인트: POST /subscriptions/{subscription_id}/charge 주요 요청 필드(본문):
product_price
integer
required
청구할 금액(가장 작은 통화 단위). 예: $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,
  environment: 'test_mode', // defaults to 'live_mode'
});

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 및 서명 비밀 구성 확인.