메인 콘텐츠로 건너뛰기

전제 조건

Dodo Payments API를 통합하려면 다음이 필요합니다:
  • Dodo Payments 상인 계정
  • 대시보드에서 API 자격 증명 (API 키 및 웹훅 비밀 키)
전제 조건에 대한 자세한 가이드는 이 섹션을 확인하세요.

API 통합

체크아웃 세션

Checkout Sessions를 사용하여 보안 호스팅된 체크아웃으로 구독 상품을 판매하세요. 구독 상품을 product_cart에 전달하고 반환된 checkout_url로 고객을 리디렉션하세요.
혼합 체크아웃: 하나의 체크아웃 세션에서 구독 상품과 일회성 상품을 결합할 수 있습니다. 이렇게 하면 구독과 함께 초기 설정 비용, SaaS 하드웨어 번들 등의 사용 사례를 지원할 수 있습니다. 예시를 보려면 Checkout Sessions guide를 참조하세요.
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 session = await client.checkoutSessions.create({
    product_cart: [
      { product_id: 'prod_subscription_monthly', quantity: 1 }
    ],
    // Optional: configure trials for subscription products
    subscription_data: { trial_period_days: 14 },
    customer: {
      email: 'subscriber@example.com',
      name: 'Jane Doe',
    },
    return_url: 'https://example.com/success',
  });

  console.log(session.checkout_url);
}

main();

API 응답

다음은 응답의 예입니다:
{
  "session_id": "cks_Gi6KGJ2zFJo9rq9Ukifwa",
  "checkout_url": "https://test.checkout.dodopayments.com/session/cks_Gi6KGJ2zFJo9rq9Ukifwa"
}
고객을 checkout_url로 리디렉션하세요.

웹훅

구독을 통합할 때 구독 생애 주기를 추적하기 위해 웹훅을 받게 됩니다. 이러한 웹훅은 구독 상태 및 결제 시나리오를 효과적으로 관리하는 데 도움을 줍니다. 웹훅 엔드포인트를 설정하려면 자세한 통합 가이드를 따르세요.

구독 이벤트 유형

다음 웹훅 이벤트는 구독 상태 변경을 추적합니다:
  1. subscription.active - 구독이 성공적으로 활성화되었습니다.
  2. subscription.updated - 구독 개체가 업데이트되었습니다 (필드가 변경될 때마다 발생합니다).
  3. subscription.on_hold - 갱신 실패로 인해 구독이 보류 상태로 전환됩니다.
  4. subscription.failed - mandate 생성 실패로 인해 구독 생성에 실패했습니다.
  5. subscription.renewed - 다음 청구 기간을 위해 구독이 갱신되었습니다.
신뢰할 수 있는 구독 생애 주기 관리를 위해 이러한 구독 이벤트를 추적하는 것을 권장합니다.
구독 변경 사항에 대한 실시간 알림을 받으려면 subscription.updated를 사용하여 API를 폴링하지 않고 애플리케이션 상태를 동기화하세요.

결제 시나리오

성공적인 결제 흐름 결제가 성공하면 다음 웹훅을 받게 됩니다:
  1. subscription.active - 구독 활성화를 나타냅니다
  2. payment.succeeded - 최초 결제를 확인합니다:
    • 즉시 청구(무료 체험 0일)의 경우: 2~10분 이내에 예상됩니다
    • 무료 체험 기간이 있는 경우: 해당 기간이 끝날 때
  3. subscription.renewed - 다음 주기의 결제 차감 및 갱신을 나타냅니다. (기본적으로 구독 상품에 대한 결제가 이루어질 때마다 subscription.renewed 웹훅과 함께 payment.succeeded 웹훅이 전송됩니다)
결제 실패 시나리오
  1. 구독 실패
  • subscription.failed - mandate 생성 실패로 인해 구독 생성이 실패했습니다.
  • payment.failed - 결제 실패를 나타냅니다.
  1. 구독 보류
  • subscription.on_hold - 갱신 결제 또는 요금제 변경 요금 실패로 인해 구독이 보류 상태가 됩니다.
  • 구독이 보류 상태가 되면 결제 수단이 업데이트될 때까지 자동 갱신되지 않습니다.
모범 사례: 구현을 단순화하려면 구독 수명 주기를 관리할 때 주로 구독 이벤트를 추적하는 것이 좋습니다.

구독 보류 처리

구독이 on_hold 상태가 되면 다시 활성화하려면 결제 수단을 업데이트해야 합니다. 이 섹션에서는 구독이 보류 상태로 전환되는 시기와 처리 방법을 설명합니다.

구독이 보류 상태가 되는 경우

구독이 보류 상태가 되는 경우는 다음과 같습니다:
  • 갱신 결제 실패: 자동 갱신 요금이 자금 부족, 카드 만료 또는 은행 거부로 인해 실패합니다.
  • 요금 변경 실패: 요금 업그레이드/다운그레이드 중 즉시 요금이 실패합니다.
  • 결제 방법 승인 실패: 결제 방법이 반복 청구를 위해 승인될 수 없습니다.
on_hold 상태의 구독은 자동으로 갱신되지 않습니다. 구독을 다시 활성화하려면 결제 수단을 업데이트해야 합니다.

보류 상태에서 구독 재활성화

on_hold 상태의 구독을 다시 활성화하려면 Update Payment Method API를 사용하세요. 이 API는 자동으로 다음을 수행합니다:
  1. 남은 금액에 대한 청구를 생성합니다
  2. 해당 청구에 대한 인보이스를 생성합니다
  3. 새 결제 수단으로 결제를 처리합니다
  4. 결제가 성공하면 구독을 active 상태로 다시 활성화합니다
1

Handle subscription.on_hold webhook

subscription.on_hold 웹훅을 수신하면 애플리케이션 상태를 업데이트하고 고객에게 알려주세요:
// Webhook handler
app.post('/webhooks/dodo', async (req, res) => {
  const event = req.body;
  
  if (event.type === 'subscription.on_hold') {
    const subscription = event.data;
    
    // Update subscription status in your database
    await updateSubscriptionStatus(subscription.subscription_id, 'on_hold');
    
    // Notify customer to update payment method
    await sendEmailToCustomer(subscription.customer_id, {
      subject: 'Payment Required - Subscription On Hold',
      message: 'Your subscription is on hold. Please update your payment method to continue service.'
    });
  }
  
  res.json({ received: true });
});
2

Update payment method

고객이 결제 수단을 업데이트할 준비가 되면 Update Payment Method API를 호출하세요:
// Update with new payment method
const response = await client.subscriptions.updatePaymentMethod(subscriptionId, {
  type: 'new',
  return_url: 'https://example.com/return'
});

// For on_hold subscriptions, a charge is automatically created
if (response.payment_id) {
  console.log('Charge created for remaining dues:', response.payment_id);
  // Redirect customer to response.payment_link to complete payment
}
고객이 저장된 결제 수단을 보유하고 있다면 기존 결제 수단 ID를 사용할 수도 있습니다:
await client.subscriptions.updatePaymentMethod(subscriptionId, {
  type: 'existing',
  payment_method_id: 'pm_abc123'
});
3

Monitor webhook events

결제 수단을 업데이트한 후에는 다음 웹훅 이벤트를 모니터링하세요:
  1. payment.succeeded - 남은 금액에 대한 청구가 성공했습니다
  2. subscription.active - 구독이 다시 활성화되었습니다
if (event.type === 'payment.succeeded') {
  const payment = event.data;
  
  // Check if this payment is for an on_hold subscription
  if (payment.subscription_id) {
    // Wait for subscription.active webhook to confirm reactivation
  }
}

if (event.type === 'subscription.active') {
  const subscription = event.data;
  
  // Update subscription status in your database
  await updateSubscriptionStatus(subscription.subscription_id, 'active');
  
  // Restore customer access
  await restoreCustomerAccess(subscription.customer_id);
  
  // Notify customer of successful reactivation
  await sendEmailToCustomer(subscription.customer_id, {
    subject: 'Subscription Reactivated',
    message: 'Your subscription has been reactivated successfully.'
  });
}

샘플 구독 이벤트 페이로드


속성유형필수 여부설명
business_idstringYes비즈니스를 위한 고유 식별자
timestampstringYes이벤트가 발생한 시점의 타임스탬프(전달 시점과 반드시 일치하지 않을 수 있습니다)
typestringYes이벤트 유형입니다. 자세한 내용은 Event Types를 참조하세요
dataobjectYes주요 데이터 페이로드입니다. 자세한 내용은 Data Object를 참조하세요

구독 요금 변경

구독 요금을 변경 API 엔드포인트를 사용하여 구독 요금을 업그레이드하거나 다운그레이드할 수 있습니다. 이를 통해 구독의 제품, 수량을 수정하고 비례 배분을 처리할 수 있습니다.

Change Plan API Reference

구독 요금제를 변경하는 방법에 대한 자세한 내용은 Change Plan API 문서를 참조하세요.

비례 배분 옵션

구독 요금을 변경할 때 즉시 요금을 처리하는 두 가지 옵션이 있습니다:

1. prorated_immediately

  • 현재 청구 주기에 남은 시간을 기준으로 일할 계산액을 산정합니다
  • 이전 요금제와 새 요금제의 차액만 고객에게 청구합니다
  • 체험 기간에는 사용자를 즉시 새 요금제로 전환하고 고객에게 바로 요금을 청구합니다

2. full_immediately

  • 새 요금제에 대해 전체 구독 요금을 청구합니다
  • 이전 요금제의 남은 시간이나 크레딧을 무시합니다
  • 청구 주기를 재설정하거나 일할 계산과 관계없이 전체 금액을 청구하려는 경우 유용합니다

3. difference_immediately

  • 업그레이드할 때 고객은 두 요금제 금액의 차액을 즉시 청구받습니다.
  • 예를 들어 현재 요금제가 30달러이고 고객이 80달러로 업그레이드하면 즉시 $50이 청구됩니다.
  • 다운그레이드할 때 현재 요금제에서 사용되지 않은 금액은 내부 크레딧으로 추가되어 향후 구독 갱신에 자동 적용됩니다.
  • 예를 들어 현재 요금제가 50달러이고 고객이 20달러 요금제로 전환하면 남은 $30이 크레딧으로 적립되어 다음 청구 주기에 사용됩니다.

동작

  • 이 API를 호출하면 Dodo Payments가 선택한 일할 계산 옵션에 따라 즉시 청구를 시작합니다
  • 요금제 변경이 다운그레이드이고 prorated_immediately를 사용하는 경우 크레딧이 자동으로 계산되어 구독의 크레딧 잔액에 추가됩니다. 이 크레딧은 해당 구독에만 적용되며 동일한 구독의 향후 반복 결제를 상쇄하는 용도로만 사용됩니다
  • full_immediately 옵션은 크레딧 계산을 건너뛰고 새로운 요금제 금액 전체를 청구합니다
일할 계산 옵션을 신중하게 선택하세요: 사용하지 않은 시간을 고려한 공정한 청구를 위해 prorated_immediately를 사용하거나 현재 청구 주기에 관계없이 전체 새 요금제를 청구하려면 full_immediately를 사용하세요.

청구 처리

  • 요금 변경 시 즉시 시작된 청구는 보통 2분 이내에 처리됩니다.
  • 이 즉시 청구가 어떤 이유로든 실패하면 구독은 문제가 해결될 때까지 자동으로 보류 상태로 전환됩니다.

주문형 구독

주문형 구독을 사용하면 고정 일정에 얽매이지 않고 고객에게 유연하게 요금을 청구할 수 있습니다. 이 기능은 모든 계정에서 사용할 수 있습니다.
주문형 구독을 생성하려면: 주문형 구독을 생성하려면 POST /subscriptions API 엔드포인트를 사용하고 요청 본문에 on_demand 필드를 포함하세요. 이렇게 하면 즉시 청구 없이 결제 수단을 승인하거나 사용자 정의 초기 가격을 설정할 수 있습니다. 주문형 구독에 요금을 청구하려면: 후속 요금 청구를 위해 POST /subscriptions/charge 엔드포인트를 사용하고 해당 거래에 대해 고객에게 청구할 금액을 지정하세요.
요청/응답 예시, 안전한 재시도 정책, 웹훅 처리를 포함한 단계별 전체 가이드는 On-Demand Subscriptions Guide를 참조하세요.