Saltar al contenido principal

Introducción

La integración de Dodo Payments con Slack te permite recibir notificaciones en tiempo real sobre tus pagos directamente en tu espacio de trabajo de Slack. Esta integración te permite mantenerte actualizado sobre el estado de tus pagos, rastrear transacciones y gestionar tus pagos de manera más eficiente.
Esta integración utiliza nuestro portal de gestión de webhooks para transformar automáticamente los eventos de webhook de Dodo Payments en mensajes compatibles con Slack. No se requiere código adicional: solo configura el conector y comienza a recibir notificaciones.

Comenzando

1

Open the Webhook Section

Ve a la sección Webhook en tu panel de Dodo Payments. Haz clic en el botón + Add Endpoint y luego abre el menú desplegable de webhooks para mostrar otras integraciones.
Dodo Payments dashboard showing Add Endpoint button and integrations dropdown
2

Select Slack Integration

Selecciona la integración Slack y haz clic en Connect your Slack workspace.
Slack integration card and connect button
3

Grant Slack Permissions

Otorga los permisos necesarios a la aplicación Incoming Webhooks de Slack para que pueda publicar mensajes en tu canal elegido.
Slack OAuth permissions screen for Incoming Webhooks app
4

Customize Transformation Code

Agrega o edita el código de transformación para personalizar tus notificaciones de Slack según tu caso de uso. Puedes utilizar las plantillas predefinidas o escribir tu propia lógica.
Transformation code editor for Slack integration
5

Test and Create

Prueba tu código de transformación con cargas de eventos personalizadas o predefinidas. Una vez que estés satisfecho, haz clic en Create para activar la integración.
Test transformation and create button
6

Integration Complete!

🎉 ¡Has creado correctamente la integración con Slack! Los eventos de Dodo Payments ahora se entregarán en tiempo real a tu canal de Slack seleccionado.

Ejemplos de código de transformación

Notificaciones básicas de pagos

Esta transformación envía mensajes de texto simples para eventos de pago:
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;
}

Notificaciones ricas de suscripción

Esta transformación crea mensajes ricos de Slack con adjuntos para eventos de suscripción:
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;
}

Notificaciones de gestión de disputas

Esta transformación maneja eventos de disputa con colores y urgencia apropiados:
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;
}

Manejador integral de todos los eventos

Esta transformación maneja todos los tipos de eventos con un formato consistente:
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;
}

Mejores prácticas

Para que tus notificaciones de Slack sean efectivas:
  • Utiliza adjuntos enriquecidos con colores, campos y formato para mayor claridad y capacidad de acción.
  • Incluye siempre datos clave como montos, correos electrónicos de clientes e identificadores para una identificación rápida.
  • Elige colores que coincidan con el tipo de evento: verde (good) para éxito, rojo (danger) para disputas o fallos, amarillo (warning) para cancelaciones y azul (#36a64f) para eventos informativos.
  • Agrega marcas de tiempo para ayudar a seguir cuándo ocurrió cada evento.
Maneja datos sensibles: Ten cuidado de no incluir información sensible como claves completas de licencia o datos personales en los mensajes de Slack. Considera truncar o enmascarar los valores sensibles.

Solución de problemas

  • Verifica que la URL del webhook de Slack sea correcta y esté activa
  • Comprueba que el código de transformación sea JavaScript válido
  • Asegúrate de que los tipos de eventos seleccionados se estén activando
  • Verifica que tu aplicación de Slack tenga los permisos necesarios
  • Consulta el portal de gestión de webhooks para ver los registros de errores de transformación
  • Verifica que la estructura de la carga útil del webhook coincida con tu código de transformación
  • Prueba tu código de transformación con datos de muestra
  • Asegúrate de que todos los campos requeridos estén presentes en la carga útil del webhook
  • Confirma que los eventos que deseas recibir estén habilitados en tu configuración de webhook de Dodo Payments
  • Comprueba que los tipos de eventos estén seleccionados en la configuración de tu conector de Slack
  • Verifica que tu endpoint esté configurado correctamente para recibir los eventos