> ## 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 슬랙 통합을 통해 슬랙 작업 공간에서 직접 결제에 대한 실시간 알림을 받을 수 있습니다. 이 통합을 통해 결제 상태를 업데이트하고, 거래를 추적하며, 결제를 보다 효율적으로 관리할 수 있습니다.

<Info>
  이 통합은 웹훅 관리 포털을 사용하여 Dodo Payments 웹훅 이벤트를 자동으로 Slack 호환 메시지로 변환합니다. 추가 코딩은 필요하지 않습니다. 커넥터를 구성하고 알림을 받기만 하면 됩니다.
</Info>

## 시작하기

<Steps>
  <Step title="Open the Webhook Section">
    Dodo Payments 대시보드에서 <b>Webhook</b> 섹션으로 이동합니다. <b>+ Add Endpoint</b> 버튼을 클릭한 후, 웹훅 드롭다운을 열어 다른 통합을 확인하세요.

    <Frame>
      <img src="https://mintcdn.com/dodopayments/slbAEdrLLwKHfaRf/images/integrations/slack/1.png?fit=max&auto=format&n=slbAEdrLLwKHfaRf&q=85&s=46218103ebf0646011873758c76b9bb6" alt="Dodo Payments 대시보드에 표시된 Endpoint 추가 버튼과 통합 드롭다운" style={{ maxHeight: '500px', width: 'auto' }} width="1782" height="1016" data-path="images/integrations/slack/1.png" />
    </Frame>
  </Step>

  <Step title="Select Slack Integration">
    <b>Slack</b> 통합을 선택하고 <b>Connect your Slack workspace</b>를 클릭합니다.

    <Frame>
      <img src="https://mintcdn.com/dodopayments/slbAEdrLLwKHfaRf/images/integrations/slack/2.png?fit=max&auto=format&n=slbAEdrLLwKHfaRf&q=85&s=4bd696f82dbbab1bc099c6ccae5b9212" alt="Slack 통합 카드와 연결 버튼" style={{ maxHeight: '500px', width: 'auto' }} width="1670" height="226" data-path="images/integrations/slack/2.png" />
    </Frame>
  </Step>

  <Step title="Grant Slack Permissions">
    선택한 채널에 메시지를 게시할 수 있도록 Incoming Webhooks Slack App에 필요한 권한을 부여하세요.

    <Frame>
      <img src="https://mintcdn.com/dodopayments/slbAEdrLLwKHfaRf/images/integrations/slack/3.png?fit=max&auto=format&n=slbAEdrLLwKHfaRf&q=85&s=00f04516a2720e377a29551ae42ad812" alt="Incoming Webhooks 앱을 위한 Slack OAuth 권한 화면" style={{ maxHeight: '500px', width: 'auto' }} width="1198" height="1536" data-path="images/integrations/slack/3.png" />
    </Frame>
  </Step>

  <Step title="Customize Transformation Code">
    Slack 알림을 사용 사례에 맞게 맞춤화하려면 변환 코드를 추가하거나 편집하세요. 미리 만들어진 템플릿을 사용하거나 직접 로직을 작성할 수 있습니다.

    <Frame>
      <img src="https://mintcdn.com/dodopayments/slbAEdrLLwKHfaRf/images/integrations/slack/4.png?fit=max&auto=format&n=slbAEdrLLwKHfaRf&q=85&s=f3c7f2b7a9bb6d6ba1d1d6922ad42bc4" alt="Slack 통합을 위한 변환 코드 편집기" style={{ maxHeight: '500px', width: 'auto' }} width="1686" height="1118" data-path="images/integrations/slack/4.png" />
    </Frame>
  </Step>

  <Step title="Test and Create">
    사용자 지정 또는 미리 만들어진 이벤트 페이로드로 변환 코드를 테스트하세요. 만족하면 <b>Create</b>를 클릭하여 통합을 활성화합니다.

    <Frame>
      <img src="https://mintcdn.com/dodopayments/slbAEdrLLwKHfaRf/images/integrations/slack/5.png?fit=max&auto=format&n=slbAEdrLLwKHfaRf&q=85&s=7d22a91488a2038a177324fa627b7497" alt="변환 테스트 및 생성 버튼" style={{ maxHeight: '500px', width: 'auto' }} width="1852" height="490" data-path="images/integrations/slack/5.png" />
    </Frame>
  </Step>

  <Step title="Integration Complete!">
    🎉 Slack 통합을 성공적으로 생성했습니다! 이제 Dodo Payments 이벤트가 선택한 Slack 채널로 실시간 전송됩니다.
  </Step>
</Steps>

## 변환 코드 예제

### 기본 결제 알림

이 변환은 결제 이벤트에 대한 간단한 텍스트 메시지를 보냅니다:

```javascript payment_notifs.js icon="js" expandable theme={null}
function handler(webhook) {
  switch (webhook.eventType) {
    case "payment.succeeded":
      webhook.payload = {
        text: `✅ Payment Successful\nAmount: $${(webhook.payload.data.total_amount / 100).toFixed(2)}\nCustomer: ${webhook.payload.data.customer.email}\nPayment ID: ${webhook.payload.data.payment_id}`
      };
      break;
      
    case "payment.failed":
      webhook.payload = {
        text: `❌ Payment Failed\nAmount: $${(webhook.payload.data.total_amount / 100).toFixed(2)}\nCustomer: ${webhook.payload.data.customer.email}\nReason: ${webhook.payload.data.error_message || 'Unknown'}`
      };
      break;
      
    case "payment.processing":
      webhook.payload = {
        text: `⏳ Payment Processing\nAmount: $${(webhook.payload.data.total_amount / 100).toFixed(2)}\nCustomer: ${webhook.payload.data.customer.email}`
      };
      break;
  }

  return webhook;
}
```

### 풍부한 구독 알림

이 변환은 구독 이벤트에 대한 첨부 파일이 있는 풍부한 슬랙 메시지를 생성합니다:

```javascript subscription_notifs.js icon="js" expandable theme={null}
function handler(webhook) {
  switch (webhook.eventType) {
    case "subscription.active":
      webhook.payload = {
        attachments: [{
          color: "good",
          title: "🎉 Subscription Activated",
          fields: [
            {
              title: "Customer",
              value: webhook.payload.data.customer.email,
              short: true
            },
            {
              title: "Product ID",
              value: webhook.payload.data.product_id,
              short: true
            },
            {
              title: "Amount",
              value: `$${(webhook.payload.data.recurring_pre_tax_amount / 100).toFixed(2)}/${webhook.payload.data.payment_frequency_interval}`,
              short: true
            },
            {
              title: "Next Billing",
              value: new Date(webhook.payload.data.next_billing_date).toLocaleDateString(),
              short: true
            }
          ],
          footer: "Dodo Payments",
          ts: Math.floor(new Date(webhook.payload.timestamp).getTime() / 1000)
        }]
      };
      break;
      
    case "subscription.cancelled":
      webhook.payload = {
        attachments: [{
          color: "warning",
          title: "⚠️ Subscription Cancelled",
          fields: [
            {
              title: "Customer",
              value: webhook.payload.data.customer.email,
              short: true
            },
            {
              title: "Product ID",
              value: webhook.payload.data.product_id,
              short: true
            },
            {
              title: "Cancellation Date",
              value: new Date(webhook.payload.data.cancelled_at).toLocaleDateString(),
              short: true
            },
            {
              title: "Cancel at Next Billing",
              value: webhook.payload.data.cancel_at_next_billing_date ? "Yes" : "No",
              short: true
            }
          ],
          footer: "Dodo Payments",
          ts: Math.floor(new Date(webhook.payload.timestamp).getTime() / 1000)
        }]
      };
      break;
      
    case "subscription.renewed":
      webhook.payload = {
        attachments: [{
          color: "good",
          title: "🔄 Subscription Renewed",
          fields: [
            {
              title: "Customer",
              value: webhook.payload.data.customer.email,
              short: true
            },
            {
              title: "Product ID",
              value: webhook.payload.data.product_id,
              short: true
            },
            {
              title: "Amount",
              value: `$${(webhook.payload.data.recurring_pre_tax_amount / 100).toFixed(2)}`,
              short: true
            },
            {
              title: "Next Billing",
              value: new Date(webhook.payload.data.next_billing_date).toLocaleDateString(),
              short: true
            }
          ],
          footer: "Dodo Payments",
          ts: Math.floor(new Date(webhook.payload.timestamp).getTime() / 1000)
        }]
      };
      break;
  }

  return webhook;
}
```

### 분쟁 관리 알림

이 변환은 적절한 색상과 긴급성을 가진 분쟁 이벤트를 처리합니다:

```javascript dispute_notifs.js icon="js" expandable theme={null}
function handler(webhook) {
  switch (webhook.eventType) {
    case "dispute.opened":
      webhook.payload = {
        attachments: [{
          color: "danger",
          title: "🚨 New Dispute Opened",
          fields: [
            {
              title: "Payment ID",
              value: webhook.payload.data.payment_id,
              short: true
            },
            {
              title: "Amount",
              value: `$${(webhook.payload.data.amount / 100).toFixed(2)}`,
              short: true
            },
            {
              title: "Status",
              value: webhook.payload.data.dispute_status,
              short: true
            },
            {
              title: "Stage",
              value: webhook.payload.data.dispute_stage,
              short: true
            },
            {
              title: "Remarks",
              value: webhook.payload.data.remarks || "No remarks",
              short: false
            }
          ],
          footer: "Dodo Payments - Action Required",
          ts: Math.floor(new Date(webhook.payload.timestamp).getTime() / 1000)
        }]
      };
      break;
      
    case "dispute.won":
      webhook.payload = {
        attachments: [{
          color: "good",
          title: "✅ Dispute Won",
          fields: [
            {
              title: "Payment ID",
              value: webhook.payload.data.payment_id,
              short: true
            },
            {
              title: "Amount",
              value: `$${(webhook.payload.data.amount / 100).toFixed(2)}`,
              short: true
            },
            {
              title: "Status",
              value: webhook.payload.data.dispute_status,
              short: true
            },
            {
              title: "Resolution",
              value: "Dispute resolved in your favor",
              short: false
            }
          ],
          footer: "Dodo Payments",
          ts: Math.floor(new Date(webhook.payload.timestamp).getTime() / 1000)
        }]
      };
      break;
      
    case "dispute.lost":
      webhook.payload = {
        attachments: [{
          color: "danger",
          title: "❌ Dispute Lost",
          fields: [
            {
              title: "Payment ID",
              value: webhook.payload.data.payment_id,
              short: true
            },
            {
              title: "Amount",
              value: `$${(webhook.payload.data.amount / 100).toFixed(2)}`,
              short: true
            },
            {
              title: "Status",
              value: webhook.payload.data.dispute_status,
              short: true
            },
            {
              title: "Impact",
              value: "Funds will be debited from your account",
              short: false
            }
          ],
          footer: "Dodo Payments - Review Required",
          ts: Math.floor(new Date(webhook.payload.timestamp).getTime() / 1000)
        }]
      };
      break;
  }

  return webhook;
}
```

### 포괄적인 모든 이벤트 핸들러

이 변환은 일관된 형식으로 모든 이벤트 유형을 처리합니다:

```javascript all_events_notifs.js icon="js" expandable  theme={null}
function handler(webhook) {
  const event = webhook.payload.data;
  const timestamp = new Date(webhook.payload.timestamp).toLocaleString();
  
  let color, emoji, title, fields = [];
  
  switch (webhook.eventType) {
    case "payment.succeeded":
      color = "good";
      emoji = "✅";
      title = "Payment Successful";
      fields = [
        { title: "Amount", value: `$${(event.total_amount / 100).toFixed(2)}`, short: true },
        { title: "Customer", value: event.customer.email, short: true },
        { title: "Payment ID", value: event.payment_id, short: true },
        { title: "Method", value: event.payment_method || "Unknown", short: true }
      ];
      break;
      
    case "payment.failed":
      color = "danger";
      emoji = "❌";
      title = "Payment Failed";
      fields = [
        { title: "Amount", value: `$${(event.total_amount / 100).toFixed(2)}`, short: true },
        { title: "Customer", value: event.customer.email, short: true },
        { title: "Reason", value: event.error_message || "Unknown", short: false }
      ];
      break;
      
    case "subscription.active":
      color = "good";
      emoji = "🎉";
      title = "Subscription Activated";
      fields = [
        { title: "Customer", value: event.customer.email, short: true },
        { title: "Product ID", value: event.product_id, short: true },
        { title: "Amount", value: `$${(event.recurring_pre_tax_amount / 100).toFixed(2)}/${event.payment_frequency_interval}`, short: true },
        { title: "Next Billing", value: new Date(event.next_billing_date).toLocaleDateString(), short: true }
      ];
      break;
      
    case "subscription.cancelled":
      color = "warning";
      emoji = "⚠️";
      title = "Subscription Cancelled";
      fields = [
        { title: "Customer", value: event.customer.email, short: true },
        { title: "Product ID", value: event.product_id, short: true },
        { title: "Cancellation Date", value: new Date(event.cancelled_at).toLocaleDateString(), short: true },
        { title: "Cancel at Next Billing", value: event.cancel_at_next_billing_date ? "Yes" : "No", short: true }
      ];
      break;
      
    case "refund.succeeded":
      color = "good";
      emoji = "💰";
      title = "Refund Processed";
      fields = [
        { title: "Amount", value: `$${(event.amount / 100).toFixed(2)}`, short: true },
        { title: "Refund ID", value: event.refund_id, short: true },
        { title: "Payment ID", value: event.payment_id, short: true },
        { title: "Reason", value: event.reason || "Not specified", short: true }
      ];
      break;
      
    case "dispute.opened":
      color = "danger";
      emoji = "🚨";
      title = "New Dispute Opened";
      fields = [
        { title: "Payment ID", value: event.payment_id, short: true },
        { title: "Amount", value: `$${(event.amount / 100).toFixed(2)}`, short: true },
        { title: "Status", value: event.dispute_status, short: true },
        { title: "Stage", value: event.dispute_stage, short: true },
        { title: "Remarks", value: event.remarks || "No remarks", short: false }
      ];
      break;
      
    case "license_key.created":
      color = "good";
      emoji = "🔑";
      title = "License Key Created";
      fields = [
        { title: "License ID", value: event.id, short: true },
        { title: "Product ID", value: event.product_id, short: true },
        { title: "License Key", value: event.key.substring(0, 8) + "...", short: true },
        { title: "Expires", value: event.expires_at ? new Date(event.expires_at).toLocaleDateString() : "Never", short: true }
      ];
      break;
      
    default:
      // Handle any other events with a generic format
      color = "warning";
      emoji = "ℹ️";
      title = webhook.eventType.replace(/_/g, ' ').replace(/\b\w/g, l => l.toUpperCase());
      fields = [
        { title: "Event Type", value: webhook.eventType, short: true },
        { title: "Timestamp", value: timestamp, short: true }
      ];
  }
  
  webhook.payload = {
    attachments: [{
      color: color,
      title: `${emoji} ${title}`,
      fields: fields,
      footer: "Dodo Payments",
      ts: Math.floor(new Date(webhook.payload.timestamp).getTime() / 1000)
    }]
  };

  return webhook;
}
```

## 모범 사례

Slack 알림을 효과적으로 만들기 위해:

* 명확성과 실행력을 위해 색상, 필드 및 서식이 포함된 풍부한 메시지 첨부를 사용하세요.
* 금액, 고객 이메일, ID 등 핵심 데이터를 항상 포함하여 빠르게 식별할 수 있도록 하세요.
* 이벤트 유형에 따라 색상을 선택하세요: 성공에는 초록색 (`good`), 분쟁 또는 실패에는 빨간색 (`danger`), 취소에는 노란색 (`warning`), 정보성 이벤트에는 파란색 (`#36a64f`).
* 각 이벤트가 언제 발생했는지 추적할 수 있도록 타임스탬프를 추가하세요.

<Warning>
  **민감한 데이터 처리**: 전체 라이선스 키나 개인 데이터와 같은 민감한 정보를 Slack 메시지에 포함하지 않도록 주의하세요. 민감한 값은 잘라내거나 마스킹하는 것을 고려하세요.
</Warning>

## 문제 해결

<AccordionGroup>
  <Accordion title="Notifications not appearing in Slack">
    * Slack 웹훅 URL이 정확하고 활성 상태인지 확인하세요.
    * 변환 코드가 유효한 JavaScript인지 확인하세요.
    * 선택된 이벤트 유형이 트리거되고 있는지 확인하세요.
    * Slack 앱에 필요한 권한이 있는지 확인하세요.
  </Accordion>

  <Accordion title="Transformation errors">
    * 변환 오류 로그가 있는지 웹훅 관리 포털을 확인하세요.
    * 웹훅 페이로드 구조가 변환 코드와 일치하는지 확인하세요.
    * 샘플 데이터를 사용하여 변환 코드를 테스트하세요.
    * 웹훅 페이로드에 모든 필수 필드가 있는지 확인하세요.
  </Accordion>

  <Accordion title="Missing event types">
    * 수신하려는 이벤트가 Dodo Payments 웹훅 구성에서 활성화되어 있는지 확인하세요.
    * Slack 커넥터 구성에서 이벤트 유형이 선택되어 있는지 확인하세요.
    * 엔드포인트가 이벤트 수신을 위해 올바르게 구성되어 있는지 확인하세요.
  </Accordion>
</AccordionGroup>
