Stripe creating subscription: Unauthorized 401

Hello, I'm running into an issue with Stripe Subscriptions whereas I cannot generate a new subscription for an user. I'm using @better-auth/strip and receive a 401 Unauthorized when I'm creating a subscription on the client. The only weird thing AFAIK is that I use the convexAdapter, so I cannot run migrations for stripe myself (but this seems unrelated to the unauthorized).

I've checked the .env.local keys a dozen times. I'm running a Tanstack Start app.

auth.tsx
import { betterAuth } from "better-auth";
import { APP_NAME, DEFAULT_AVATAR, DEFAULT_LANGUAGE } from "@/config/constants";
import { ConvexHttpClient } from "convex/browser";
import { convexAdapter } from "@better-auth-kit/convex";
import { stripe } from "@better-auth/stripe";
import Stripe from "stripe";

const convexClient = new ConvexHttpClient(import.meta.env.VITE_CONVEX_URL);
const stripeClient = new Stripe(import.meta.env.VITE_STRIPE_SECRET_KEY);

export const AUTH_PROVIDERS = {
  CREDENTIAL: "credential",
  APPLE: "apple",
  GOOGLE: "google",
} as const;

export const auth = betterAuth({
  appName: APP_NAME,
  secret: import.meta.env.VITE_BETTER_AUTH_SECRET,
  baseURL: import.meta.env.VITE_BETTER_AUTH_URL,
  database: convexAdapter(convexClient),
  plugins: [
    stripe({
      stripeClient,
      stripeWebhookSecret: import.meta.env.VITE_STRIPE_WEBHOOKS_ENDPOINT_SECRET,
      createCustomerOnSignUp: true,
      subscription: {
        enabled: true,
        plans: [
          {
            name: "monthly", // the name of the plan, it'll be automatically lower cased when stored in the database
            priceId: import.meta.env.VITE_STRIPE_MONTHLY_PRICE_ID, // the price id from stripe
          },
          {
            name: "yearly",
            priceId: import.meta.env.VITE_STRIPE_YEARLY_PRICE_ID,
          },
        ],
      },
    }),
  ],
Solution
 subscription: defineTable({
    id: v.string(), // <-- this was the problem
    plan: v.string(),
    referenceId: v.id("user"),
    stripeCustomerId: v.optional(v.string()),
    stripeSubscriptionId: v.optional(v.string()),
    status: v.string(),
    periodStart: v.optional(v.string()),
    periodEnd: v.optional(v.string()),
    cancelAtPeriodEnd: v.optional(v.boolean()),
    seats: v.optional(v.number()),
    trialStart: v.optional(v.string()),
    trialEnd: v.optional(v.string()),
  }),
Was this page helpful?