capture cancellation reason/comment, add callback docs

This commit is contained in:
Shawn Erquhart
2025-03-03 12:06:13 -05:00
parent cf207e45a4
commit cc884fdde6
4 changed files with 50 additions and 0 deletions

View File

@@ -104,6 +104,32 @@ polar.registerRoutes(http as any);
export default http; export default http;
``` ```
You can also provide callbacks for webhook events:
```ts
polar.registerRoutes(http, {
// Optional custom path, default is "/events/polar"
path: "/events/polar",
// Optional callbacks for webhook events
onSubscriptionUpdated: async (ctx, event) => {
// Handle subscription updates, like cancellations
if (event.data.customerCancellationReason) {
console.log("Customer cancelled:", event.data.customerCancellationReason);
}
},
onSubscriptionCreated: async (ctx, event) => {
// Handle new subscriptions
},
onProductCreated: async (ctx, event) => {
// Handle new products
},
onProductUpdated: async (ctx, event) => {
// Handle product updates
},
});
```
4. Be sure to run `npx convex dev` to start your Convex app with the Polar 4. Be sure to run `npx convex dev` to start your Convex app with the Polar
component enabled, which will deploy the webhook handler to your Convex component enabled, which will deploy the webhook handler to your Convex
instance. instance.

View File

@@ -6,6 +6,26 @@ const http = httpRouter();
polar.registerRoutes(http, { polar.registerRoutes(http, {
// Optional custom path, default is "/events/polar" // Optional custom path, default is "/events/polar"
path: "/events/polar", path: "/events/polar",
// Optional callback for when a subscription is updated
onSubscriptionUpdated: async (ctx, event) => {
console.log("Subscription updated", event);
if (event.data.customerCancellationReason) {
console.log(
"Customer cancellation reason",
event.data.customerCancellationReason
);
console.log(
"Customer cancellation comment",
event.data.customerCancellationComment
);
}
// This callback is run in an Action, so you could pipe this customer
// cancellation reason to another service, for example.
},
// Other available callbacks:
onSubscriptionCreated: undefined,
onProductCreated: undefined,
onProductUpdated: undefined,
}); });
export default http; export default http;

View File

@@ -83,6 +83,8 @@ export default defineSchema(
priceId: v.string(), priceId: v.string(),
checkoutId: v.union(v.string(), v.null()), checkoutId: v.union(v.string(), v.null()),
metadata: v.record(v.string(), v.any()), metadata: v.record(v.string(), v.any()),
customerCancellationReason: v.optional(v.union(v.string(), v.null())),
customerCancellationComment: v.optional(v.union(v.string(), v.null())),
}) })
.index("id", ["id"]) .index("id", ["id"])
.index("customerId", ["customerId"]) .index("customerId", ["customerId"])

View File

@@ -89,6 +89,8 @@ export const convertToDatabaseSubscription = (
currentPeriodStart: subscription.currentPeriodStart.toISOString(), currentPeriodStart: subscription.currentPeriodStart.toISOString(),
currentPeriodEnd: subscription.currentPeriodEnd?.toISOString() ?? null, currentPeriodEnd: subscription.currentPeriodEnd?.toISOString() ?? null,
cancelAtPeriodEnd: subscription.cancelAtPeriodEnd, cancelAtPeriodEnd: subscription.cancelAtPeriodEnd,
customerCancellationReason: subscription.customerCancellationReason,
customerCancellationComment: subscription.customerCancellationComment,
startedAt: subscription.startedAt?.toISOString() ?? null, startedAt: subscription.startedAt?.toISOString() ?? null,
endedAt: subscription.endedAt?.toISOString() ?? null, endedAt: subscription.endedAt?.toISOString() ?? null,
metadata: subscription.metadata, metadata: subscription.metadata,