Supported events
| Event | Slack | Discord |
|---|---|---|
customer.products.updated | ✓ | ✓ |
balances.limit_reached | ✓ | ✓ |
balances.usage_alert_triggered | ✓ | ✓ |
Setup
1
Get an incoming webhook URL
Follow the official guide for the platform you want to use:Both flows give you a webhook URL that looks like
https://hooks.slack.com/services/... or
https://discord.com/api/webhooks/.... Keep it handy for the next step.2
Add the webhook endpoint in Autumn
In your Autumn dashboard, go to Developer → Webhooks and click
Add Endpoint. Paste in the URL from the previous step and select the
events you want to subscribe to.

3
Enable transformations
Open the endpoint you just created, switch to the Advanced tab, and
click Edit transformation.
Paste in the transform code below for the platform you’re targeting,
then click Save and Enable.


4
Enable throttling
Back on the Advanced tab, click Edit next to Endpoint Throttling
and set a sensible RPS (requests-per-second) limit. This prevents your
Slack or Discord channel from being flooded during high-volume events such
as bulk customer migrations or backfills.

Transform code
Copy the transform for your platform into the Code editor on the transformation page, then click Save and Enable./**
* @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;
}
/**
* @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_AVATAR_URL = "https://i.ibb.co/BHCF1ZqL/autumnicon.png";
// Discord embed colors (decimal RGB).
var COLOR_SUCCESS = 0x22c55e;
var COLOR_INFO = 0x3b82f6;
var COLOR_WARNING = 0xf59e0b;
var COLOR_DANGER = 0xef4444;
var COLOR_NEUTRAL = 0x6b7280;
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 emoji = "🔔";
var header = "Subscription Updated";
var verb = "updated";
var color = COLOR_NEUTRAL;
if (scenario === "new") {
emoji = "🎉"; header = "New Subscription"; verb = "subscribed to"; color = COLOR_SUCCESS;
} else if (scenario === "upgrade") {
emoji = "🚀"; header = "Customer Upgraded"; verb = "upgraded to"; color = COLOR_SUCCESS;
} else if (scenario === "downgrade") {
emoji = "📉"; header = "Customer Downgraded"; verb = "downgraded to"; color = COLOR_WARNING;
} else if (scenario === "cancel") {
emoji = "⚠️"; header = "Subscription Cancelled"; verb = "cancelled"; color = COLOR_WARNING;
} else if (scenario === "renew") {
emoji = "🔄"; header = "Subscription Uncancelled"; verb = "uncancelled"; color = COLOR_SUCCESS;
} else if (scenario === "expired") {
emoji = "💀"; header = "Subscription Expired"; verb = "expired on"; color = COLOR_DANGER;
} else if (scenario === "scheduled") {
emoji = "📅"; header = "Change Scheduled"; verb = "scheduled a change to"; color = COLOR_INFO;
}
var sentence;
if (scenario === "expired") {
sentence = "**" + customerName + "**'s **" + productName + "** expired";
} else {
sentence = "**" + customerName + "** " + verb + " **" + productName + "**";
}
var description = sentence;
if (customerId) {
description += "\n\n[View in Autumn](" + AUTUMN_BASE + customerId + ")";
}
var fields = [
{ name: "Customer", value: customerName, inline: true }
];
if (customerEmail) {
fields.push({ name: "Email", value: customerEmail, inline: true });
}
fields.push({ name: "Product", value: productName, inline: true });
fields.push({ name: "Scenario", value: "`" + scenario + "`", inline: true });
if (entityLabel) {
fields.push({ name: "Entity", value: entityLabel, inline: true });
}
var embed = {
title: emoji + " " + header,
description: description,
color: color,
fields: fields
};
if (customerId) {
embed.url = AUTUMN_BASE + customerId;
}
var footerParts = [];
if (customerId) footerParts.push("Customer ID: " + customerId);
if (entity && entity.id) footerParts.push("Entity: " + entity.id);
if (footerParts.length > 0) {
embed.footer = { text: footerParts.join(" | ") };
}
webhook.payload = {
username: AUTUMN_USERNAME,
avatar_url: AUTUMN_AVATAR_URL,
embeds: [embed]
};
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 lrCustomerDisplay = lrCustomerId
? "[`" + lrCustomerId + "`](" + AUTUMN_BASE + lrCustomerId + ")"
: "`unknown`";
var lrDescription =
lrCustomerDisplay + " hit their **" + lrFeatureId + "** `" + lrLimitType + "` limit";
if (lrCustomerId) {
lrDescription += "\n\n[View in Autumn](" + AUTUMN_BASE + lrCustomerId + ")";
}
var lrFields = [
{
name: "Customer",
value: lrCustomerId ? "`" + lrCustomerId + "`" : "—",
inline: true
},
{ name: "Feature", value: "`" + lrFeatureId + "`", inline: true },
{ name: "Limit Type", value: "`" + lrLimitType + "`", inline: true }
];
if (lrEntityId) {
lrFields.push({ name: "Entity", value: "`" + lrEntityId + "`", inline: true });
}
var lrEmbed = {
title: "🚫 Limit Reached",
description: lrDescription,
color: COLOR_DANGER,
fields: lrFields
};
if (lrCustomerId) {
lrEmbed.url = AUTUMN_BASE + lrCustomerId;
}
var lrFooterParts = [];
if (lrCustomerId) lrFooterParts.push("Customer ID: " + lrCustomerId);
if (lrEntityId) lrFooterParts.push("Entity: " + lrEntityId);
if (lrFooterParts.length > 0) {
lrEmbed.footer = { text: lrFooterParts.join(" | ") };
}
webhook.payload = {
username: AUTUMN_USERNAME,
avatar_url: AUTUMN_AVATAR_URL,
embeds: [lrEmbed]
};
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";
var uaThresholdLabel = "—";
if (uaThreshold !== undefined && uaThreshold !== null) {
if (uaThresholdType === "usage_percentage") {
uaThresholdLabel = uaThreshold + "% used";
} else if (uaThresholdType === "remaining_percentage") {
uaThresholdLabel = uaThreshold + "% remaining";
} else if (uaThresholdType === "remaining") {
uaThresholdLabel = uaThreshold + " remaining";
} else {
uaThresholdLabel = uaThreshold + " used";
}
}
var uaCustomerDisplay = uaCustomerId
? "[`" + uaCustomerId + "`](" + AUTUMN_BASE + uaCustomerId + ")"
: "`unknown`";
var uaDescription =
uaCustomerDisplay + " crossed the **" + uaAlertName + "** threshold on **" + uaFeatureId + "**";
if (uaCustomerId) {
uaDescription += "\n\n[View in Autumn](" + AUTUMN_BASE + uaCustomerId + ")";
}
var uaFields = [
{
name: "Customer",
value: uaCustomerId ? "`" + uaCustomerId + "`" : "—",
inline: true
},
{ name: "Feature", value: "`" + uaFeatureId + "`", inline: true },
{ name: "Alert", value: uaAlertName, inline: true },
{ name: "Threshold", value: uaThresholdLabel, inline: true }
];
if (uaEntityId) {
uaFields.push({ name: "Entity", value: "`" + uaEntityId + "`", inline: true });
}
var uaEmbed = {
title: "📊 Usage Alert: " + uaAlertName,
description: uaDescription,
color: COLOR_WARNING,
fields: uaFields
};
if (uaCustomerId) {
uaEmbed.url = AUTUMN_BASE + uaCustomerId;
}
var uaFooterParts = [];
if (uaCustomerId) uaFooterParts.push("Customer ID: " + uaCustomerId);
if (uaEntityId) uaFooterParts.push("Entity: " + uaEntityId);
if (uaFooterParts.length > 0) {
uaEmbed.footer = { text: uaFooterParts.join(" | ") };
}
webhook.payload = {
username: AUTUMN_USERNAME,
avatar_url: AUTUMN_AVATAR_URL,
embeds: [uaEmbed]
};
return webhook;
}
// Unmatched event type — cancel dispatch.
webhook.cancel = true;
return webhook;
}