aboutsummaryrefslogtreecommitdiffstats
path: root/packages/api
diff options
context:
space:
mode:
authorMohamed Bassem <me@mbassem.com>2025-07-13 09:28:24 +0000
committerMohamed Bassem <me@mbassem.com>2025-07-13 20:44:00 +0000
commitd1d5263486f96db578aad918a59007045c3c077f (patch)
treedf65f062b6eda93364f7d509fc2c52663561097a /packages/api
parent845ccf1ad46c8635782f8e10280b07c48c08eaf5 (diff)
downloadkarakeep-d1d5263486f96db578aad918a59007045c3c077f.tar.zst
feat: Add stripe based subscriptions
Diffstat (limited to 'packages/api')
-rw-r--r--packages/api/index.ts4
-rw-r--r--packages/api/routes/webhooks.ts44
2 files changed, 47 insertions, 1 deletions
diff --git a/packages/api/index.ts b/packages/api/index.ts
index 39075548..1e353f41 100644
--- a/packages/api/index.ts
+++ b/packages/api/index.ts
@@ -18,6 +18,7 @@ import rss from "./routes/rss";
import tags from "./routes/tags";
import trpc from "./routes/trpc";
import users from "./routes/users";
+import webhooks from "./routes/webhooks";
const v1 = new Hono<{
Variables: {
@@ -62,6 +63,7 @@ const app = new Hono<{
.route("/admin", admin)
.route("/assets", assets)
.route("/public", publicRoute)
- .route("/metrics", metrics);
+ .route("/metrics", metrics)
+ .route("/webhooks", webhooks);
export default app;
diff --git a/packages/api/routes/webhooks.ts b/packages/api/routes/webhooks.ts
new file mode 100644
index 00000000..66ce96d3
--- /dev/null
+++ b/packages/api/routes/webhooks.ts
@@ -0,0 +1,44 @@
+import { Hono } from "hono";
+
+import { Context, createCallerFactory } from "@karakeep/trpc";
+import { appRouter } from "@karakeep/trpc/routers/_app";
+
+const createCaller = createCallerFactory(appRouter);
+
+const app = new Hono<{
+ Variables: {
+ ctx: Context;
+ };
+}>().post("/stripe", async (c) => {
+ const body = await c.req.text();
+ const signature = c.req.header("stripe-signature");
+
+ if (!signature) {
+ return c.json({ error: "Missing stripe-signature header" }, 400);
+ }
+
+ try {
+ const api = createCaller(c.get("ctx"));
+ const result = await api.subscriptions.handleWebhook({
+ body,
+ signature,
+ });
+
+ return c.json(result);
+ } catch (error) {
+ console.error("Webhook processing failed:", error);
+
+ if (error instanceof Error) {
+ if (error.message.includes("Invalid signature")) {
+ return c.json({ error: "Invalid signature" }, 400);
+ }
+ if (error.message.includes("not configured")) {
+ return c.json({ error: "Stripe is not configured" }, 400);
+ }
+ }
+
+ return c.json({ error: "Internal server error" }, 500);
+ }
+});
+
+export default app;