diff options
| author | Mohamed Bassem <me@mbassem.com> | 2025-07-13 09:28:24 +0000 |
|---|---|---|
| committer | Mohamed Bassem <me@mbassem.com> | 2025-07-13 20:44:00 +0000 |
| commit | d1d5263486f96db578aad918a59007045c3c077f (patch) | |
| tree | df65f062b6eda93364f7d509fc2c52663561097a /packages/api | |
| parent | 845ccf1ad46c8635782f8e10280b07c48c08eaf5 (diff) | |
| download | karakeep-d1d5263486f96db578aad918a59007045c3c077f.tar.zst | |
feat: Add stripe based subscriptions
Diffstat (limited to 'packages/api')
| -rw-r--r-- | packages/api/index.ts | 4 | ||||
| -rw-r--r-- | packages/api/routes/webhooks.ts | 44 |
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; |
