/**
* @param webhook the webhook object
* @param webhook.method destination method. Allowed values: "POST", "PUT"
* @param webhook.url current destination address
* @param webhook.eventType current webhook Event Type
* @param webhook.payload JSON payload
* @param webhook.cancel whether to cancel dispatch of the given webhook
*/
function handler(webhook) {
var AUTUMN_BASE = "https://app.useautumn.com/customers/";
var AUTUMN_USERNAME = "Autumn";
var AUTUMN_ICON_URL = "https://i.ibb.co/BHCF1ZqL/autumnicon.png";
var payload = webhook.payload || {};
var data = payload.data || payload;
// ============ customer.products.updated ============
if (webhook.eventType === "customer.products.updated") {
var scenario = data.scenario || "updated";
var customer = data.customer || {};
var entity = data.entity || null;
var product = data.updated_product || {};
var customerName = customer.name || customer.email || customer.id || "Customer";
var customerEmail = customer.email || null;
var customerId = customer.id || "";
var productName = product.name || "their plan";
if (product.version && product.version !== 1) {
productName = productName + " V" + product.version;
}
var entityLabel = null;
if (entity) {
entityLabel = entity.name || entity.id || null;
}
var meta = {
"new": { emoji: "🎉", header: "New Subscription", verb: "subscribed to" },
"upgrade": { emoji: "🚀", header: "Customer Upgraded", verb: "upgraded to" },
"downgrade": { emoji: "📉", header: "Customer Downgraded", verb: "downgraded to" },
"cancel": { emoji: "⚠️", header: "Subscription Cancelled", verb: "cancelled" },
"renew": { emoji: "🔄", header: "Subscription Uncancelled", verb: "uncancelled" },
"expired": { emoji: "💀", header: "Subscription Expired", verb: "expired on" },
"scheduled": { emoji: "📅", header: "Change Scheduled", verb: "scheduled a change to" }
}[scenario] || { emoji: "🔔", header: "Subscription Updated", verb: "updated" };
var sentence;
if (scenario === "expired") {
sentence = "*" + customerName + "*'s *" + productName + "* expired";
} else {
sentence = "*" + customerName + "* " + meta.verb + " *" + productName + "*";
}
var previewText = meta.emoji + " " + customerName + " " + meta.verb + " " + productName;
var fields = [
{ type: "mrkdwn", text: "*Customer:*\n" + customerName }
];
if (customerEmail) {
fields.push({ type: "mrkdwn", text: "*Email:*\n" + customerEmail });
}
fields.push({ type: "mrkdwn", text: "*Product:*\n" + productName });
fields.push({ type: "mrkdwn", text: "*Scenario:*\n`" + scenario + "`" });
if (entityLabel) {
fields.push({ type: "mrkdwn", text: "*Entity:*\n" + entityLabel });
}
var contextParts = [];
if (customerId) {
contextParts.push("Customer ID: `" + customerId + "`");
}
if (entity && entity.id) {
contextParts.push("Entity: `" + entity.id + "`");
}
var blocks = [
{
type: "header",
text: { type: "plain_text", text: meta.emoji + " " + meta.header, emoji: true }
},
{
type: "section",
text: { type: "mrkdwn", text: sentence }
},
{
type: "section",
fields: fields
}
];
if (customerId) {
blocks.push({
type: "actions",
elements: [
{
type: "button",
text: { type: "plain_text", text: "View in Autumn", emoji: true },
url: AUTUMN_BASE + customerId,
style: "primary"
}
]
});
}
if (contextParts.length > 0) {
blocks.push({
type: "context",
elements: [
{ type: "mrkdwn", text: contextParts.join(" | ") }
]
});
}
webhook.payload = {
username: AUTUMN_USERNAME,
icon_url: AUTUMN_ICON_URL,
text: previewText,
blocks: blocks
};
return webhook;
}
// ============ balances.limit_reached ============
if (webhook.eventType === "balances.limit_reached") {
var lrCustomerId = data.customer_id || "";
var lrFeatureId = data.feature_id || "feature";
var lrLimitType = data.limit_type || "included";
var lrEntityId = data.entity_id || null;
var lrCustomerLink = lrCustomerId
? "<" + AUTUMN_BASE + lrCustomerId + "|`" + lrCustomerId + "`>"
: "`unknown`";
var lrSentence =
lrCustomerLink + " hit their *" + lrFeatureId + "* `" + lrLimitType + "` limit";
var lrPreview = "🚫 " + lrCustomerId + " hit their " + lrFeatureId + " limit";
var lrFields = [
{ type: "mrkdwn", text: "*Customer:*\n" + lrCustomerLink },
{ type: "mrkdwn", text: "*Feature:*\n`" + lrFeatureId + "`" },
{ type: "mrkdwn", text: "*Limit Type:*\n`" + lrLimitType + "`" }
];
if (lrEntityId) {
lrFields.push({ type: "mrkdwn", text: "*Entity:*\n`" + lrEntityId + "`" });
}
var lrContextParts = [];
if (lrCustomerId) lrContextParts.push("Customer ID: `" + lrCustomerId + "`");
if (lrEntityId) lrContextParts.push("Entity: `" + lrEntityId + "`");
var lrBlocks = [
{
type: "header",
text: { type: "plain_text", text: "🚫 Limit Reached", emoji: true }
},
{
type: "section",
text: { type: "mrkdwn", text: lrSentence }
},
{
type: "section",
fields: lrFields
}
];
if (lrCustomerId) {
lrBlocks.push({
type: "actions",
elements: [
{
type: "button",
text: { type: "plain_text", text: "View in Autumn", emoji: true },
url: AUTUMN_BASE + lrCustomerId,
style: "danger"
}
]
});
}
if (lrContextParts.length > 0) {
lrBlocks.push({
type: "context",
elements: [
{ type: "mrkdwn", text: lrContextParts.join(" | ") }
]
});
}
webhook.payload = {
username: AUTUMN_USERNAME,
icon_url: AUTUMN_ICON_URL,
text: lrPreview,
blocks: lrBlocks
};
return webhook;
}
// ============ balances.usage_alert_triggered ============
if (webhook.eventType === "balances.usage_alert_triggered") {
var uaCustomerId = data.customer_id || "";
var uaFeatureId = data.feature_id || "feature";
var uaEntityId = data.entity_id || null;
var uaAlert = data.usage_alert || {};
var uaAlertName = uaAlert.name || "Usage alert";
var uaThreshold = uaAlert.threshold;
var uaThresholdType = uaAlert.threshold_type || "usage";
function formatThreshold(value, type) {
if (value === undefined || value === null) return "—";
if (type === "usage_percentage") return value + "% used";
if (type === "remaining_percentage") return value + "% remaining";
if (type === "remaining") return value + " remaining";
return value + " used";
}
var uaThresholdLabel = formatThreshold(uaThreshold, uaThresholdType);
var uaCustomerLink = uaCustomerId
? "<" + AUTUMN_BASE + uaCustomerId + "|`" + uaCustomerId + "`>"
: "`unknown`";
var uaSentence =
uaCustomerLink + " crossed the *" + uaAlertName + "* threshold on *" + uaFeatureId + "*";
var uaPreview = "📊 Usage Alert: " + uaAlertName + " (" + uaCustomerId + ")";
var uaFields = [
{ type: "mrkdwn", text: "*Customer:*\n" + uaCustomerLink },
{ type: "mrkdwn", text: "*Feature:*\n`" + uaFeatureId + "`" },
{ type: "mrkdwn", text: "*Alert:*\n" + uaAlertName },
{ type: "mrkdwn", text: "*Threshold:*\n" + uaThresholdLabel }
];
if (uaEntityId) {
uaFields.push({ type: "mrkdwn", text: "*Entity:*\n`" + uaEntityId + "`" });
}
var uaContextParts = [];
if (uaCustomerId) uaContextParts.push("Customer ID: `" + uaCustomerId + "`");
if (uaEntityId) uaContextParts.push("Entity: `" + uaEntityId + "`");
var uaBlocks = [
{
type: "header",
text: { type: "plain_text", text: "📊 Usage Alert: " + uaAlertName, emoji: true }
},
{
type: "section",
text: { type: "mrkdwn", text: uaSentence }
},
{
type: "section",
fields: uaFields
}
];
if (uaCustomerId) {
uaBlocks.push({
type: "actions",
elements: [
{
type: "button",
text: { type: "plain_text", text: "View in Autumn", emoji: true },
url: AUTUMN_BASE + uaCustomerId
}
]
});
}
if (uaContextParts.length > 0) {
uaBlocks.push({
type: "context",
elements: [
{ type: "mrkdwn", text: uaContextParts.join(" | ") }
]
});
}
webhook.payload = {
username: AUTUMN_USERNAME,
icon_url: AUTUMN_ICON_URL,
text: uaPreview,
blocks: uaBlocks
};
return webhook;
}
// Cancel any other event types — they don't match Slack's expected schema and would error.
webhook.cancel = true;
return webhook;
}