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

Customize Transformation Code
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 などの主要データを常に含め、素早く識別できるようにします。
- イベントタイプに応じて色を選択: green (
good) は成功、red (danger) は異議や失敗、yellow (warning) はキャンセル、blue (#36a64f) は情報イベントです。 - 各イベントがいつ発生したかを追跡しやすくするため、タイムスタンプを追加します。
Handle Sensitive Data: Slack メッセージに完全なライセンスキーや個人情報などの機密情報を含めないよう注意してください。機密性の高い値は切り詰めたりマスクしたりすることを検討してください。
トラブルシューティング
Notifications not appearing in Slack
Notifications not appearing in Slack
- Slack Webhook URL が正しく有効であることを確認してください
- 変換コードが有効な JavaScript であることを確認してください
- 選択したイベントタイプがトリガーされていることを確認してください
- Slack アプリに必要な権限があることを確認してください
Transformation errors
Transformation errors
- Webhook 管理ポータルで変換エラーのログを確認してください
- Webhook ペイロード構造が変換コードと一致しているか確認してください
- サンプルデータで変換コードをテストしてください
- Webhook ペイロードに必要なすべてのフィールドが含まれていることを確認してください
Missing event types
Missing event types
- 受信したいイベントが Dodo Payments の Webhook 構成で有効になっていることを確認してください
- Slack コネクタ構成でイベントタイプが選択されていることを確認してください
- イベントを受信するためのエンドポイントが適切に構成されていることを確認してください


