> ## 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.

# 구독 통합 가이드

> 이 가이드는 Dodo Payments 구독 제품을 웹사이트에 통합하는 데 도움을 줍니다.

## 전제 조건

Dodo Payments API를 통합하려면 다음이 필요합니다:

* Dodo Payments 상인 계정
* 대시보드에서 API 자격 증명 (API 키 및 웹훅 비밀 키)

전제 조건에 대한 자세한 가이드는 [이 섹션](/developer-resources/integration-guide#dashboard-setup)을 확인하세요.

## API 통합

### 체크아웃 세션

Checkout Sessions를 사용하여 보안 호스팅된 체크아웃으로 구독 상품을 판매하세요. 구독 상품을 `product_cart`에 전달하고 반환된 `checkout_url`로 고객을 리디렉션하세요.

<Tip>
  **혼합 체크아웃**: 하나의 체크아웃 세션에서 구독 상품과 일회성 상품을 결합할 수 있습니다. 이렇게 하면 구독과 함께 초기 설정 비용, SaaS 하드웨어 번들 등의 사용 사례를 지원할 수 있습니다. 예시를 보려면 [Checkout Sessions guide](/developer-resources/checkout-session)를 참조하세요.
</Tip>

<Tabs>
  <Tab title="Node.js SDK">
    ```javascript theme={null}
    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();
    ```
  </Tab>

  <Tab title="Python SDK">
    ```python theme={null}
    import os
    from dodopayments import DodoPayments

    client = DodoPayments(
        bearer_token=os.environ.get("DODO_PAYMENTS_API_KEY"),
        environment="test_mode",  # defaults to "live_mode"
    )

    session = client.checkout_sessions.create(
        product_cart=[
            {"product_id": "prod_subscription_monthly", "quantity": 1}
        ],
        subscription_data={"trial_period_days": 14},  # optional
        customer={
            "email": "subscriber@example.com",
            "name": "Jane Doe",
        },
        return_url="https://example.com/success",
    )

    print(session.checkout_url)
    ```
  </Tab>

  <Tab title="REST API">
    ```javascript theme={null}
    const response = await fetch('https://test.dodopayments.com/checkouts', {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
        'Authorization': `Bearer ${process.env.DODO_PAYMENTS_API_KEY}`
      },
      body: JSON.stringify({
        product_cart: [
          { product_id: 'prod_subscription_monthly', quantity: 1 }
        ],
        subscription_data: { trial_period_days: 14 }, // optional
        customer: {
          email: 'subscriber@example.com',
          name: 'Jane Doe'
        },
        return_url: 'https://example.com/success'
      })
    });

    if (!response.ok) {
      throw new Error(`HTTP error! status: ${response.status}`);
    }

    const session = await response.json();
    console.log(session.checkout_url);
    ```
  </Tab>
</Tabs>

### API 응답

다음은 응답의 예입니다:

```json theme={null}
{
  "session_id": "cks_Gi6KGJ2zFJo9rq9Ukifwa",
  "checkout_url": "https://test.checkout.dodopayments.com/session/cks_Gi6KGJ2zFJo9rq9Ukifwa"
}
```

고객을 `checkout_url`로 리디렉션하세요.

### 웹훅

구독을 통합할 때 구독 생애 주기를 추적하기 위해 웹훅을 받게 됩니다. 이러한 웹훅은 구독 상태 및 결제 시나리오를 효과적으로 관리하는 데 도움을 줍니다.

웹훅 엔드포인트를 설정하려면 [자세한 통합 가이드](/developer-resources/integration-guide#implementing-webhooks)를 따르세요.

#### 구독 이벤트 유형

다음 웹훅 이벤트는 구독 상태 변경을 추적합니다:

1. **`subscription.active`** - 구독이 성공적으로 활성화되었습니다.
2. **`subscription.updated`** - 구독 개체가 업데이트되었습니다 (필드가 변경될 때마다 발생합니다).
3. **`subscription.on_hold`** - 갱신 실패로 인해 구독이 보류 상태로 전환됩니다.
4. **`subscription.failed`** - mandate 생성 실패로 인해 구독 생성에 실패했습니다.
5. **`subscription.renewed`** - 다음 청구 기간을 위해 구독이 갱신되었습니다.

신뢰할 수 있는 구독 생애 주기 관리를 위해 이러한 구독 이벤트를 추적하는 것을 권장합니다.

<Tip>
  구독 변경 사항에 대한 실시간 알림을 받으려면 `subscription.updated`를 사용하여 API를 폴링하지 않고 애플리케이션 상태를 동기화하세요.
</Tip>

#### 결제 시나리오

**성공적인 결제 흐름**

결제가 성공하면 다음 웹훅을 받게 됩니다:

1. `subscription.active` - 구독 활성화를 나타냅니다
2. `payment.succeeded` - 최초 결제를 확인합니다:
   * 즉시 청구(무료 체험 0일)의 경우: 2\~10분 이내에 예상됩니다
   * 무료 체험 기간이 있는 경우: 해당 기간이 끝날 때
3. `subscription.renewed` - 다음 주기의 결제 차감 및 갱신을 나타냅니다. (기본적으로 구독 상품에 대한 결제가 이루어질 때마다 `subscription.renewed` 웹훅과 함께 `payment.succeeded` 웹훅이 전송됩니다)

**결제 실패 시나리오**

1. 구독 실패

* `subscription.failed` - mandate 생성 실패로 인해 구독 생성이 실패했습니다.
* `payment.failed` - 결제 실패를 나타냅니다.

2. 구독 보류

* `subscription.on_hold` - 갱신 결제 또는 요금제 변경 요금 실패로 인해 구독이 보류 상태가 됩니다.
* 구독이 보류 상태가 되면 결제 수단이 업데이트될 때까지 자동 갱신되지 않습니다.

<Info>**모범 사례**: 구현을 단순화하려면 구독 수명 주기를 관리할 때 주로 구독 이벤트를 추적하는 것이 좋습니다.</Info>

### 구독 보류 처리

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

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

구독이 보류 상태가 되는 경우는 다음과 같습니다:

* **갱신 결제 실패**: 자동 갱신 요금이 자금 부족, 카드 만료 또는 은행 거부로 인해 실패합니다.
* **요금 변경 실패**: 요금 업그레이드/다운그레이드 중 즉시 요금이 실패합니다.
* **결제 방법 승인 실패**: 결제 방법이 반복 청구를 위해 승인될 수 없습니다.

<Warning>
  `on_hold` 상태의 구독은 자동으로 갱신되지 않습니다. 구독을 다시 활성화하려면 결제 수단을 업데이트해야 합니다.
</Warning>

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

`on_hold` 상태의 구독을 다시 활성화하려면 Update Payment Method API를 사용하세요. 이 API는 자동으로 다음을 수행합니다:

1. 남은 금액에 대한 청구를 생성합니다
2. 해당 청구에 대한 인보이스를 생성합니다
3. 새 결제 수단으로 결제를 처리합니다
4. 결제가 성공하면 구독을 `active` 상태로 다시 활성화합니다

<Steps>
  <Step title="Handle subscription.on_hold webhook">
    `subscription.on_hold` 웹훅을 수신하면 애플리케이션 상태를 업데이트하고 고객에게 알려주세요:

    ```javascript theme={null}
    // 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 });
    });
    ```
  </Step>

  <Step title="Update payment method">
    고객이 결제 수단을 업데이트할 준비가 되면 Update Payment Method API를 호출하세요:

    <CodeGroup>
      ```javascript Node.js theme={null}
      // 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
      }
      ```

      ```python Python theme={null}
      # Update with new payment method
      response = client.subscriptions.update_payment_method(
          subscription_id=subscription_id,
          type="new",
          return_url="https://example.com/return"
      )

      # For on_hold subscriptions, a charge is automatically created
      if response.payment_id:
          print("Charge created for remaining dues:", response.payment_id)
          # Redirect customer to response.payment_link to complete payment
      ```
    </CodeGroup>

    <Info>
      고객이 저장된 결제 수단을 보유하고 있다면 기존 결제 수단 ID를 사용할 수도 있습니다:

      ```javascript theme={null}
      await client.subscriptions.updatePaymentMethod(subscriptionId, {
        type: 'existing',
        payment_method_id: 'pm_abc123'
      });
      ```
    </Info>
  </Step>

  <Step title="Monitor webhook events">
    결제 수단을 업데이트한 후에는 다음 웹훅 이벤트를 모니터링하세요:

    1. **`payment.succeeded`** - 남은 금액에 대한 청구가 성공했습니다
    2. **`subscription.active`** - 구독이 다시 활성화되었습니다

    ```javascript theme={null}
    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.'
      });
    }
    ```
  </Step>
</Steps>

### 샘플 구독 이벤트 페이로드

***

| 속성            | 유형     | 필수 여부 | 설명                                                         |
| ------------- | ------ | ----- | ---------------------------------------------------------- |
| `business_id` | string | Yes   | 비즈니스를 위한 고유 식별자                                            |
| `timestamp`   | string | Yes   | 이벤트가 발생한 시점의 타임스탬프(전달 시점과 반드시 일치하지 않을 수 있습니다)              |
| `type`        | string | Yes   | 이벤트 유형입니다. 자세한 내용은 [Event Types](#event-types)를 참조하세요      |
| `data`        | object | Yes   | 주요 데이터 페이로드입니다. 자세한 내용은 [Data Object](#data-object)를 참조하세요 |

## 구독 요금 변경

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

<Card title="Change Plan API Reference" icon="arrows-rotate" href="/api-reference/subscriptions/change-plan">
  구독 요금제를 변경하는 방법에 대한 자세한 내용은 Change Plan API 문서를 참조하세요.
</Card>

### 비례 배분 옵션

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

#### 1. `prorated_immediately`

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

#### 2. `full_immediately`

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

#### 3. `difference_immediately`

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

### 동작

* 이 API를 호출하면 Dodo Payments가 선택한 일할 계산 옵션에 따라 즉시 청구를 시작합니다
* 요금제 변경이 다운그레이드이고 `prorated_immediately`를 사용하는 경우 크레딧이 자동으로 계산되어 구독의 크레딧 잔액에 추가됩니다. 이 크레딧은 해당 구독에만 적용되며 동일한 구독의 향후 반복 결제를 상쇄하는 용도로만 사용됩니다
* `full_immediately` 옵션은 크레딧 계산을 건너뛰고 새로운 요금제 금액 전체를 청구합니다

<Tip>
  **일할 계산 옵션을 신중하게 선택하세요**: 사용하지 않은 시간을 고려한 공정한 청구를 위해 `prorated_immediately`를 사용하거나 현재 청구 주기에 관계없이 전체 새 요금제를 청구하려면 `full_immediately`를 사용하세요.
</Tip>

### 청구 처리

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

## 주문형 구독

<Info>
  주문형 구독을 사용하면 고정 일정에 얽매이지 않고 고객에게 유연하게 요금을 청구할 수 있습니다. 이 기능은 모든 계정에서 사용할 수 있습니다.
</Info>

**주문형 구독을 생성하려면:**

주문형 구독을 생성하려면 [POST /subscriptions](/api-reference/subscriptions/post-subscriptions) API 엔드포인트를 사용하고 요청 본문에 `on_demand` 필드를 포함하세요. 이렇게 하면 즉시 청구 없이 결제 수단을 승인하거나 사용자 정의 초기 가격을 설정할 수 있습니다.

**주문형 구독에 요금을 청구하려면:**

후속 청구의 경우 [POST /subscriptions/{subscription_id}/charge](/api-reference/subscriptions/create-charge) 엔드포인트를 사용하고 해당 거래에 대해 고객에게 청구할 금액을 지정하십시오.

<Note>
  요청/응답 예시, 안전한 재시도 정책, 웹훅 처리를 포함한 단계별 전체 가이드는 <a href="/developer-resources/ondemand-subscriptions">On-Demand Subscriptions Guide</a>를 참조하세요.
</Note>

## 관련 API 참고 문서

API reference for creating subscription products and managing subscription lifecycle

**온디맨드 구독 요금 청구 방법:**

후속 요금을 청구하려면, [POST /subscriptions/{subscription_id}/charge](/api-reference/subscriptions/create-charge) 엔드포인트를 사용하고 해당 거래에 대해 고객에게 청구할 금액을 지정하세요.

<Note>
  요청/응답 예제, 안전한 재시도 정책 및 웹훅 처리 등을 포함한 완전한 단계별 가이드는 <a href="/developer-resources/ondemand-subscriptions">온디맨드 구독 가이드</a>를 참조하세요.
</Note>

## 관련 API 참조

<CardGroup cols={2}>
  <Card title="Create Subscription" icon="code" href="/api-reference/subscriptions/post-subscriptions">
    구독 상품 생성 및 구독 라이프사이클 관리에 대한 API 참조
  </Card>

  <Card title="Change Subscription Plan" icon="arrows-rotate" href="/api-reference/subscriptions/change-plan">
    비율 옵션을 사용하여 구독 플랜 업그레이드, 다운그레이드 또는 변경에 대한 API 참조
  </Card>

  <Card title="Update Payment Method" icon="credit-card" href="/api-reference/subscriptions/update-payment-method">
    결제 방법 업데이트 및 보류 중인 구독 재활성화에 대한 API 참조
  </Card>

  <Card title="Patch Subscription" icon="pen" href="/api-reference/subscriptions/patch-subscriptions">
    구독 세부정보 및 구성 업데이트에 대한 API 참조
  </Card>
</CardGroup>
