はじめに
Dodo PaymentsのSlack統合を使用すると、Slackワークスペース内で直接支払いに関するリアルタイム通知を受け取ることができます。この統合により、支払いの状況を把握し、取引を追跡し、支払いをより効率的に管理できます。この統合は、Dodo PaymentsのWebhook管理ポータルを使用して、Dodo PaymentsのWebhookイベントをSlack互換のメッセージに自動的に変換します。追加のコーディングは不要で、コネクタを設定するだけで通知を受け取ることができます。
始め方
1
Webhookセクションを開く
Dodo PaymentsダッシュボードのWebhookセクションに移動します。+ エンドポイントを追加ボタンをクリックし、Webhookドロップダウンを開いて他の統合を表示します。

2
Slack統合を選択
Slack統合を選択し、Slackワークスペースを接続をクリックします。

3
Slackの権限を付与
Incoming Webhooks Slackアプリに必要な権限を付与し、選択したチャンネルにメッセージを投稿できるようにします。

4
変換コードをカスタマイズ
変換コードを追加または編集して、使用ケースに合わせてSlack通知をカスタマイズします。事前に作成されたテンプレートを使用するか、自分のロジックを書くことができます。

5
テストと作成
カスタムまたは事前に作成されたイベントペイロードで変換コードをテストします。満足したら、作成をクリックして統合を有効にします。

6
統合完了!
🎉 Slack統合を正常に作成しました!あなたのDodo Paymentsイベントは、選択したSlackチャンネルにリアルタイムで配信されます。
変換コードの例
基本的な支払い通知
この変換は、支払いイベントのためのシンプルなテキストメッセージを送信します:payment_notifs.js
コピー
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;
}
リッチなサブスクリプション通知
この変換は、サブスクリプションイベントのために添付ファイル付きのリッチなSlackメッセージを作成します:subscription_notifs.js
コピー
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;
}
紛争管理通知
この変換は、適切な色と緊急度で紛争イベントを処理します:dispute_notifs.js
コピー
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;
}
包括的な全イベントハンドラー
この変換は、一貫したフォーマットで全てのイベントタイプを処理します:all_events_notifs.js
コピー
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)。 - 各イベントが発生した時刻を追跡するために、タイムスタンプを追加してください。
機密データの取り扱い:Slackメッセージに完全なライセンスキーや個人データなどの機密情報を含めないように注意してください。機密値を切り詰めたりマスクしたりすることを検討してください。
トラブルシューティング
Slackに通知が表示されない
Slackに通知が表示されない
- SlackのWebhook URLが正しくアクティブであることを確認してください
- 変換コードが有効なJavaScriptであることを確認してください
- 選択したイベントタイプがトリガーされていることを確認してください
- Slackアプリに必要な権限があることを確認してください
変換エラー
変換エラー
- 変換エラーログのためにWebhook管理ポータルを確認してください
- Webhookペイロードの構造が変換コードと一致していることを確認してください
- サンプルデータで変換コードをテストしてください
- Webhookペイロードにすべての必須フィールドが含まれていることを確認してください
イベントタイプが欠落している
イベントタイプが欠落している
- 受信したいイベントがDodo PaymentsのWebhook設定で有効になっていることを確認してください
- Slackコネクタ設定でイベントタイプが選択されていることを確認してください
- エンドポイントがイベントを受信するように正しく設定されていることを確認してください