### Run TanStack Example Source: https://github.com/alexasomba/better-auth-paystack/blob/main/README.md Runs the TanStack Start example development server. ```bash vp run examples/tanstack dev ``` -------------------------------- ### Install Dependencies Source: https://github.com/alexasomba/better-auth-paystack/blob/main/README.md Installs project dependencies using the 'vp' CLI. ```bash vp i ``` -------------------------------- ### Run Development Server Source: https://github.com/alexasomba/better-auth-paystack/blob/main/examples/tanstack/README.md Starts the TanStack Start development server. Access the application at http://localhost:8787. ```bash pnpm dev ``` -------------------------------- ### Sync Paystack Products (Initialization Script) Source: https://github.com/alexasomba/better-auth-paystack/blob/main/_autodocs/api-reference-server-operations.md Example of calling `syncPaystackProducts` within an initialization script to ensure products are synchronized when the application starts. ```typescript async function initializeProducts() { const ctx = { context: await auth.$context }; await syncPaystackProducts(ctx, paystackOptions); console.log("Products synced successfully"); } ``` -------------------------------- ### Run TanStack Example Tests Source: https://github.com/alexasomba/better-auth-paystack/blob/main/skills/paystack-client-api/SKILL.md Run tests for the TanStack example integration when making changes to client usage or examples. Use the pnpm filter command. ```bash pnpm --filter ./examples/tanstack test ``` -------------------------------- ### Example of Calling Sign-In with Cookies Handled Source: https://github.com/alexasomba/better-auth-paystack/blob/main/examples/tanstack/better-auth-tanstack.md Demonstrates calling a sign-in function after configuring Better Auth with TanStack Start's cookie handling. Cookies will be automatically managed. ```typescript import { auth } from "@/lib/auth"; const signIn = async () => { await auth.api.signInEmail({ body: { email: "user@email.com", password: "password", }, }); }; ``` -------------------------------- ### Install Dependencies with npm Source: https://github.com/alexasomba/better-auth-paystack/blob/main/_autodocs/README.md Install the necessary packages for Better Auth and its Paystack integration. ```bash npm install better-auth @alexasomba/better-auth-paystack @alexasomba/paystack-node ``` -------------------------------- ### Build for Production Source: https://github.com/alexasomba/better-auth-paystack/blob/main/examples/tanstack/README.md Compiles the TanStack Start application for production deployment. ```bash pnpm build ``` -------------------------------- ### Install Optional Browser SDK Source: https://github.com/alexasomba/better-auth-paystack/blob/main/README.md Install the @alexasomba/paystack-inline package if you need to support Paystack's inline checkout experience via popup modals. ```bash npm install @alexasomba/paystack-inline ``` -------------------------------- ### Hook for Free Trial Start Source: https://github.com/alexasomba/better-auth-paystack/blob/main/_autodocs/configuration.md Execute logic when a free trial period begins for a subscription plan. Typically used to send trial start notifications. ```typescript subscription: { plans: [ { name: "pro", freeTrial: { days: 14, onTrialStart: async (subscription) => { await sendEmail({ to: subscription.userEmail, template: "trial_started", data: { endDate: subscription.trialEnd, }, }); }, }, }, ], } ``` -------------------------------- ### Build TanStack Example for Cloudflare Workers Source: https://github.com/alexasomba/better-auth-paystack/blob/main/skills/paystack-tanstack-start/SKILL.md Use the provided commands to build and deploy the TanStack example to Cloudflare Workers. This helps in reproducing and debugging Worker-specific issues. ```bash pnpm --filter ./examples/tanstack build pnpm --filter ./examples/tanstack exec wrangler deploy --dry-run ``` -------------------------------- ### Install AI Agent Skills with skills-npm Source: https://github.com/alexasomba/better-auth-paystack/blob/main/README.md Install the package and then run the skills-npm command to symlink installed package skills for compatible AI agents. This makes package skills discoverable by agents. ```bash npm install @alexasomba/better-auth-paystack npx skills-npm --yes ``` -------------------------------- ### Install Dependencies with pnpm Source: https://github.com/alexasomba/better-auth-paystack/blob/main/examples/tanstack/README.md Installs project dependencies using the pnpm package manager. ```bash pnpm install ``` -------------------------------- ### Install Paystack Browser Plugin Source: https://github.com/alexasomba/better-auth-paystack/blob/main/skills/paystack-client-api/SKILL.md Import and create the auth client with the Paystack plugin. Ensure the subscription option is enabled if needed. ```typescript import { createAuthClient } from "better-auth/client"; import { paystackClient } from "@alexasomba/better-auth-paystack/client"; export const authClient = createAuthClient({ plugins: [paystackClient({ subscription: true })], }); ``` -------------------------------- ### Local Plan Subscription Example Source: https://github.com/alexasomba/better-auth-paystack/blob/main/_autodocs/database-schema.md Example of a subscription record for a local plan managed by the application. Uses an authorization code for renewals. ```typescript { id: "sub_456", userId: "user_456", plan: "starter", referenceId: "user_456", paystackSubscriptionCode: "LOC_sub_456", paystackAuthorizationCode: "AUTH_xyz789", status: "active", seats: 5, periodStart: new Date("2024-06-01"), periodEnd: new Date("2024-07-01"), } ``` -------------------------------- ### Configure Better Auth with TanStack Start Cookies (Solid.js) Source: https://github.com/alexasomba/better-auth-paystack/blob/main/examples/tanstack/better-auth-tanstack.md Integrate the `tanstackStartCookies` plugin for automatic cookie handling in Solid.js-based TanStack Start applications. Ensure this is the last plugin. ```typescript import { betterAuth } from "better-auth"; import { tanstackStartCookies } from "better-auth/tanstack-start/solid"; export const auth = betterAuth({ //...your config plugins: [tanstackStartCookies()], // make sure this is the last plugin in the array }); ``` -------------------------------- ### Organization Billing Subscription Example Source: https://github.com/alexasomba/better-auth-paystack/blob/main/_autodocs/database-schema.md Example of a subscription record for an organization, including organization ID and customer code for Paystack. ```typescript { id: "sub_org_789", userId: "user_789", organizationId: "org_789", plan: "pro", referenceId: "org_789", paystackCustomerCode: "CUS_org_789", status: "active", seats: 10, } ``` -------------------------------- ### Native Plan Subscription Example Source: https://github.com/alexasomba/better-auth-paystack/blob/main/_autodocs/database-schema.md Example of a subscription record for a native plan managed by Paystack. Includes Paystack-specific codes and dates. ```typescript { id: "sub_123", userId: "user_123", plan: "pro", referenceId: "user_123", paystackSubscriptionCode: "SUB_abc123", paystackPlanCode: "PLN_pro_code", status: "active", seats: 1, periodStart: new Date("2024-06-01"), periodEnd: new Date("2024-07-01"), cancelAtPeriodEnd: false, } ``` -------------------------------- ### Initialize Paystack Plugin Source: https://github.com/alexasomba/better-auth-paystack/blob/main/_autodocs/configuration.md Configure the Paystack plugin with essential keys and subscription details. This is the primary setup for integrating Paystack. ```typescript import { paystack } from "@alexasomba/better-auth-paystack"; const auth = betterAuth({ plugins: [ paystack({ secretKey: process.env.PAYSTACK_SECRET_KEY, webhook: { secret: process.env.PAYSTACK_WEBHOOK_SECRET, }, subscription: { enabled: true, plans: [ { name: "pro", planCode: "PLN_pro_code", amount: 100000, currency: "NGN", interval: "monthly", }, ], }, }), ], }); ``` -------------------------------- ### Paystack Plugin Initialization Source: https://github.com/alexasomba/better-auth-paystack/blob/main/_autodocs/api-reference-main-plugin.md Initialize the Paystack plugin for Better Auth. This example demonstrates setting up the Paystack client, webhook verification, subscription plans, product configurations, and event handling. ```typescript import { betterAuth } from "better-auth"; import { paystack } from "@alexasomba/better-auth-paystack"; import { createPaystack } from "@alexasomba/paystack-node"; import { admin } from "better-auth/plugins"; const paystackClient = createPaystack({ secretKey: process.env.PAYSTACK_SECRET_KEY!, }); export const auth = betterAuth({ database: { provider: "postgresql", url: process.env.DATABASE_URL!, }, plugins: [ admin(), paystack({ paystackClient, webhook: { secret: process.env.PAYSTACK_WEBHOOK_SECRET!, verifyIP: true, }, createCustomerOnSignUp: true, subscription: { enabled: true, allowedPaymentChannels: ["card"], plans: [ { name: "pro", planCode: "PLN_pro_code", freeTrial: { days: 14 }, limits: { teams: 10, seats: 20 }, }, { name: "starter", amount: 50000, currency: "NGN", interval: "monthly", }, ], }, products: { products: [ { name: "credits_50", amount: 200000, currency: "NGN", }, ], }, onEvent: async (event) => { console.log("Paystack event:", event.event); }, }), ], }); ``` -------------------------------- ### Initialize and Use Paystack Client Source: https://github.com/alexasomba/better-auth-paystack/blob/main/_autodocs/api-reference-client-plugin.md Demonstrates how to create an authenticated client with the Paystack plugin enabled for subscription management. Shows examples for initializing transactions, verifying payments, creating and managing subscriptions, and accessing Paystack-specific configurations. ```typescript import { createAuthClient } from "better-auth/client"; import { paystackClient } from "@alexasomba/better-auth-paystack/client"; import { adminClient } from "better-auth/client/plugins"; export const client = createAuthClient({ baseURL: "http://localhost:3000", plugins: [adminClient(), paystackClient({ subscription: true })], }); // Usage in components: // 1. Initialize a transaction for a plan const { data, error } = await client.transaction.initialize({ plan: "pro", quantity: 5, email: "user@example.com", metadata: { customField: "value" }, }); if (data?.accessCode) { window.location.href = data.url; // Redirect to Paystack checkout } // 2. Verify transaction after payment const verifyResult = await client.transaction.verify({ reference: "txn_1234567890", }); // 3. Create a subscription const subResult = await client.subscription.create({ plan: "starter", email: "user@example.com", }); // 4. List user's subscriptions const { data: subscriptions } = await client.subscription.list(); // 5. Cancel subscription (deferred to period end) const cancelResult = await client.subscription.cancel({ subscriptionCode: "SUB_xyz", atPeriodEnd: true, }); // 6. Upgrade to pro and charge prorated delta const upgradeResult = await client.transaction.initialize({ plan: "pro", quantity: 10, prorateAndCharge: true, }); // 7. List one-time transactions const transResult = await client.transaction.list(); // 8. Get subscription management link const portalResult = await client.subscription.billingPortal({ subscriptionCode: "SUB_xyz", }); if (portalResult.data?.link) { window.location.href = portalResult.data.link; // Open Paystack portal } // 9. Get plugin configuration const configResult = await client.paystack.config(); // 10. List products const productsResult = await client.paystack.listProducts(); ``` -------------------------------- ### Setup Paystack Plugin with Products and Subscriptions Source: https://github.com/alexasomba/better-auth-paystack/blob/main/skills/paystack-catalog-limits/SKILL.md Configure the Paystack plugin with products, subscription plans, free trials, and limits. Ensure your environment variables for PAYSTACK_SECRET_KEY and PAYSTACK_WEBHOOK_SECRET are set. ```typescript import { paystack, } from "@alexasomba/better-auth-paystack"; export const paystackPlugin = paystack({ secretKey: process.env.PAYSTACK_SECRET_KEY!, webhook: { secret: process.env.PAYSTACK_WEBHOOK_SECRET!, }, products: { products: [ { name: "credits_50", amount: 200_000, currency: "NGN", }, ], }, subscription: { enabled: true, plans: [ { name: "pro", amount: 500_000, currency: "NGN", interval: "monthly", planCode: "PLN_pro_monthly", paystackId: "1001", freeTrial: { days: 14, }, limits: { seats: 10, teams: 5, }, }, ], }, }); ``` -------------------------------- ### Vercel Cron Integration Example Source: https://github.com/alexasomba/better-auth-paystack/blob/main/_autodocs/api-reference-server-operations.md Shows how to set up a Vercel Cron job for subscription renewals, including authorization validation. ```typescript // api/cron/renew-subscriptions.ts export async function GET(request: Request) { // Validate request token to prevent abuse if (request.headers.get("authorization") !== `Bearer ${process.env.CRON_SECRET}`) { return new Response("Unauthorized", { status: 401 }); } // Call chargeSubscriptionRenewal for each subscription } ``` -------------------------------- ### Node.js node-cron Integration Example Source: https://github.com/alexasomba/better-auth-paystack/blob/main/_autodocs/api-reference-server-operations.md Demonstrates using the node-cron library to schedule daily subscription renewal tasks. ```typescript import cron from "node-cron"; cron.schedule("0 0 * * *", async () => { // Run renewal at midnight daily const ctx = { context: await auth.$context }; // Call chargeSubscriptionRenewal for each subscription }); ``` -------------------------------- ### GET /paystack/list-products Source: https://github.com/alexasomba/better-auth-paystack/blob/main/_autodocs/endpoints.md Lists all available products for one-time purchase. ```APIDOC ## GET /paystack/list-products ### Description List all available products for one-time purchase. ### Method GET ### Endpoint /paystack/list-products ### Parameters #### Query Parameters None. ### Response #### Success Response (200) - **products** (PaystackProduct[]) - List of available products. ### Response Example { "products": [ { "id": "prod_1", "name": "Widget", "price": 500, "description": "A useful widget" } ] } ``` -------------------------------- ### GET /paystack/list-plans Source: https://github.com/alexasomba/better-auth-paystack/blob/main/_autodocs/endpoints.md Lists all available subscription plans. ```APIDOC ## GET /paystack/list-plans ### Description List all available plans for subscriptions. ### Method GET ### Endpoint /paystack/list-plans ### Parameters #### Query Parameters None. ### Response #### Success Response (200) - **plans** (PaystackPlan[]) - List of available subscription plans. ### Response Example { "plans": [ { "id": "plan_1", "name": "Basic Plan", "amount": 1000, "currency": "NGN", "interval": "monthly" } ] } ``` -------------------------------- ### Server Setup with Paystack Plugin Source: https://github.com/alexasomba/better-auth-paystack/blob/main/skills/better-auth-paystack-setup/SKILL.md Configure the Paystack server plugin for Better Auth. Ensure Paystack SDK, secret key, and webhook secret are provided. Subscription plans can be enabled and defined here. ```typescript import { betterAuth, } from "better-auth"; import { createPaystack, } from "@alexasomba/paystack-node"; import { paystack, } from "@alexasomba/better-auth-paystack"; const paystackSdk = createPaystack({ secretKey: process.env.PAYSTACK_SECRET_KEY!, }); export const auth = betterAuth({ database: { provider: "sqlite", url: process.env.DATABASE_URL!, }, plugins: [ paystack({ paystackClient: paystackSdk, secretKey: process.env.PAYSTACK_SECRET_KEY!, webhook: { secret: process.env.PAYSTACK_WEBHOOK_SECRET!, }, subscription: { enabled: true, plans: [ { name: "pro", amount: 500_000, currency: "NGN", interval: "monthly", planCode: "PLN_pro_monthly", paystackId: "123456", }, ], }, }), ], }); ``` -------------------------------- ### Configure Better Auth with TanStack Start Cookies (React) Source: https://github.com/alexasomba/better-auth-paystack/blob/main/examples/tanstack/better-auth-tanstack.md Integrate the `tanstackStartCookies` plugin for automatic cookie handling in React-based TanStack Start applications. Ensure this is the last plugin. ```typescript import { betterAuth } from "better-auth"; import { tanstackStartCookies } from "better-auth/tanstack-start"; export const auth = betterAuth({ //...your config plugins: [tanstackStartCookies()], // make sure this is the last plugin in the array }); ``` -------------------------------- ### Setup Paystack Subscriptions Source: https://github.com/alexasomba/better-auth-paystack/blob/main/skills/paystack-billing-flows/SKILL.md Configure the Paystack integration to enable subscription functionality by defining plans with their respective amounts, currencies, intervals, and Paystack-specific identifiers. Ensure Paystack plan metadata is correctly set up. ```typescript import { paystack, } from "@alexasomba/better-auth-paystack"; paystack({ secretKey: process.env.PAYSTACK_SECRET_KEY!, webhook: { secret: process.env.PAYSTACK_WEBHOOK_SECRET!, }, subscription: { enabled: true, plans: [ { name: "starter", amount: 250_000, currency: "NGN", interval: "monthly", planCode: "PLN_starter", paystackId: "1001", }, { name: "team", amount: 1_000_000, currency: "NGN", interval: "monthly", planCode: "PLN_team", paystackId: "1002", limits: { seats: 10, teams: 3, }, }, ], }, }); ``` -------------------------------- ### Setup Server Plugin with Paystack Source: https://github.com/alexasomba/better-auth-paystack/blob/main/README.md Configure the Better Auth server plugin with Paystack integration, including subscription and product settings. Ensure Paystack secret keys and webhook secrets are set in environment variables. ```typescript import { betterAuth, } from "better-auth"; import { paystack, } from "@alexasomba/better-auth-paystack"; import { createPaystack, } from "@alexasomba/paystack-node"; import { admin } from "better-auth/plugins"; const paystackClient = createPaystack({ secretKey: process.env.PAYSTACK_SECRET_KEY!, }); export const auth = betterAuth({ plugins: [ admin(), paystack({ paystackClient, webhook: { secret: process.env.PAYSTACK_WEBHOOK_SECRET! }, createCustomerOnSignUp: true, subscription: { enabled: true, allowedPaymentChannels: ["card"], // Optional: enforce card-only subscriptions plans: [ { name: "pro", planCode: "PLN_pro_123", // Native: Managed by Paystack freeTrial: { days: 14 }, limits: { teams: 5, seats: 10 }, // Custom resource & member limits }, { name: "starter", amount: 50000, // Local: Managed by your app (500 NGN) currency: "NGN", interval: "monthly", }, ], }, products: { products: [{ name: "credits_50", amount: 200000, currency: "NGN" }], }, }), ], }); ``` -------------------------------- ### Sync Paystack Products (Server Endpoint) Source: https://github.com/alexasomba/better-auth-paystack/blob/main/_autodocs/api-reference-server-operations.md Example of creating a server-only endpoint to manually sync products from Paystack. Requires admin authorization and handles potential errors during the sync process. ```typescript import { syncPaystackProducts } from "@alexasomba/better-auth-paystack"; // Manual bulk sync endpoint (server-only, not exposed to client) app.post("/admin/sync-products", async (req, res) => { // Verify admin authorization if (!req.user.isAdmin) return res.status(403).json({ error: "Forbidden" }); try { const ctx = { context: await auth.$context }; const result = await syncPaystackProducts(ctx, paystackOptions); res.json({ status: result.status, synced: result.count, message: `Synced ${result.count} products from Paystack`, }); } catch (error) { res.status(500).json({ error: error instanceof Error ? error.message : "Sync failed", }); } }); ``` -------------------------------- ### Initialize Transaction Source: https://github.com/alexasomba/better-auth-paystack/blob/main/_autodocs/api-reference-client-plugin.md Starts a new transaction with Paystack. Requires a plan identifier. ```APIDOC ## POST /paystack/initialize-transaction ### Description Starts a new transaction with Paystack. This is the initial step to process a payment. ### Method POST ### Endpoint /paystack/initialize-transaction ### Parameters #### Request Body - **plan** (string) - Required - The identifier for the plan to be used for the transaction. ### Request Example ```json { "plan": "pro" } ``` ### Response #### Success Response (200) - **accessCode** (string) - The code required to initiate the checkout modal. ``` -------------------------------- ### Configure Better Auth with Paystack and TanStack Start Cookies Source: https://github.com/alexasomba/better-auth-paystack/blob/main/skills/paystack-tanstack-start/SKILL.md Set up the Better Auth server configuration, including the Paystack plugin and `tanstackStartCookies()`. Ensure `tanstackStartCookies()` is the last plugin to correctly wrap auth behavior. ```typescript import { betterAuth } from "better-auth"; import { tanstackStartCookies } from "better-auth/tanstack-start"; import { paystack } from "@alexasomba/better-auth-paystack"; export const auth = betterAuth({ baseURL: process.env.BETTER_AUTH_URL, plugins: [ paystack({ secretKey: process.env.PAYSTACK_SECRET_KEY!, webhook: { secret: process.env.PAYSTACK_WEBHOOK_SECRET!, }, subscription: { enabled: true, plans: [], }, }), tanstackStartCookies(), ], }); ``` -------------------------------- ### GET /paystack/config Source: https://github.com/alexasomba/better-auth-paystack/blob/main/_autodocs/endpoints.md Retrieves the plugin configuration, including available plans and products. ```APIDOC ## GET /paystack/config ### Description Get plugin configuration (available plans and products). ### Method GET ### Endpoint /paystack/config ### Parameters #### Query Parameters None. ### Response #### Success Response (200) - **plans** (PaystackPlan[]) - Optional - Available subscription plans. - **products** (PaystackProduct[]) - Optional - Available products for one-time purchase. ### Response Example { "plans": [ { "id": "plan_1", "name": "Basic Plan", "amount": 1000, "currency": "NGN", "interval": "monthly" } ], "products": [ { "id": "prod_1", "name": "Widget", "price": 500, "description": "A useful widget" } ] } ``` -------------------------------- ### Client Setup with Paystack Client Plugin Source: https://github.com/alexasomba/better-auth-paystack/blob/main/skills/better-auth-paystack-setup/SKILL.md Add the Paystack client plugin to your Better Auth client configuration. This enables client-side interactions with Paystack-related features. ```typescript import { createAuthClient, } from "better-auth/client"; import { paystackClient, } from "@alexasomba/better-auth-paystack/client"; export const authClient = createAuthClient({ plugins: [paystackClient()], }); ``` -------------------------------- ### Install AI Agent Skills with TanStack Intent Source: https://github.com/alexasomba/better-auth-paystack/blob/main/README.md Use TanStack Intent to list or load package-specific guidance for AI coding agents. Run this command in your project to enable agent discovery of package skills. ```bash npx @tanstack/intent@latest list npx @tanstack/intent@latest load @alexasomba/better-auth-paystack#better-auth-paystack-setup npx @tanstack/intent@latest load @alexasomba/better-auth-paystack#paystack-testing-fixtures ``` -------------------------------- ### Get Product by Name Source: https://github.com/alexasomba/better-auth-paystack/blob/main/_autodocs/database-schema.md This TypeScript snippet demonstrates how to find a specific product by its name using Prisma's `findFirst` method. ```typescript const product = await db.paystackProduct.findFirst({ where: { name: "credits_50", }, }); ``` -------------------------------- ### Mount Better Auth Handler in TanStack Start Source: https://github.com/alexasomba/better-auth-paystack/blob/main/examples/tanstack/better-auth-tanstack.md Mount the Better Auth handler to a TanStack API endpoint. This setup handles GET and POST requests for authentication. ```typescript import { auth } from "@/lib/auth"; import { createFileRoute } from "@tanstack/react-router"; export const Route = createFileRoute("/api/auth/$")({ server: { handlers: { GET: async ({ request }: { request: Request }) => { return await auth.handler(request); }, POST: async ({ request }: { request: Request }) => { return await auth.handler(request); }, }, }, }); ``` -------------------------------- ### Plan Configuration with Free Trial Source: https://github.com/alexasomba/better-auth-paystack/blob/main/skills/paystack-catalog-limits/SKILL.md Configure a subscription plan with a free trial. The `onTrialStart` callback can be used to trigger custom logic when a trial begins. The plugin prevents repeat trials for the same reference ID. ```json { name: "starter", amount: 250_000, currency: "NGN", interval: "monthly", planCode: "PLN_starter", paystackId: "1002", freeTrial: { days: 7, onTrialStart: async (subscription) => { await notifyTrialStarted(subscription.referenceId); }, }, } ``` -------------------------------- ### Applying Authentication Middleware to a Route Source: https://github.com/alexasomba/better-auth-paystack/blob/main/examples/tanstack/better-auth-tanstack.md Example of applying the custom authentication middleware to a specific route definition in TanStack Start to protect it. ```typescript import { createFileRoute } from "@tanstack/react-router"; import { authMiddleware } from "@/lib/middleware"; export const Route = createFileRoute("/dashboard")({ component: RouteComponent, server: { middleware: [authMiddleware], }, }); function RouteComponent() { return
Hello "/dashboard"!
; } ``` -------------------------------- ### Paystack Client Initialization Source: https://github.com/alexasomba/better-auth-paystack/blob/main/skills/paystack-client-api/SKILL.md Demonstrates how to create an authenticated client instance with the Paystack plugin enabled for subscription management. ```APIDOC ## Client Initialization ### Description Instantiate the `createAuthClient` from `better-auth/client` and include the `paystackClient` plugin. This enables access to Paystack-specific functionalities through the `authClient` object. ### Usage ```ts import { createAuthClient } from "better-auth/client"; import { paystackClient } from "@alexasomba/better-auth-paystack/client"; export const authClient = createAuthClient({ plugins: [paystackClient({ subscription: true })], }); ``` ### Public Surfaces - `authClient.paystack`: Top-level Paystack actions. - `authClient.transaction`: Namespace for transaction-related operations. - `authClient.subscription`: Namespace for subscription-related operations. - `authClient.paystack.paystack`: Alias for top-level Paystack actions for compatibility. ``` -------------------------------- ### TanStack Start Authentication Middleware Source: https://github.com/alexasomba/better-auth-paystack/blob/main/examples/tanstack/better-auth-tanstack.md Create a middleware to protect routes in TanStack Start by checking for a valid session. Redirects unauthenticated users to the login page. ```typescript import { redirect } from "@tanstack/react-router"; import { createMiddleware } from "@tanstack/react-start"; import { getRequestHeaders } from "@tanstack/react-start/server"; import { auth } from "@/lib/auth"; export const authMiddleware = createMiddleware().server(async ({ next, request }) => { const headers = getRequestHeaders(); const session = await auth.api.getSession({ headers }); if (!session) { throw redirect({ to: "/login" }); } return await next(); }); ``` -------------------------------- ### Run Database Migrations Source: https://github.com/alexasomba/better-auth-paystack/blob/main/_autodocs/README.md Execute database migrations to set up the necessary tables for Paystack data. ```bash npx better-auth migrate ``` -------------------------------- ### Usage Example: Renewing Subscriptions in a Cron Job Source: https://github.com/alexasomba/better-auth-paystack/blob/main/_autodocs/api-reference-server-operations.md Example of how to use chargeSubscriptionRenewal within a cron job to renew subscriptions whose periods are expiring. Ensure proper context and error handling. ```typescript import { chargeSubscriptionRenewal } from "@alexasomba/better-auth-paystack"; // In a cron handler or scheduled job: async function renewSubscriptions() { // Get all subscriptions with period expiring today const subscriptions = await db.query( `SELECT * FROM subscription WHERE status = 'active' AND periodEnd = CURRENT_DATE` ); for (const sub of subscriptions) { try { const ctx = { context: await auth.$context, } as GenericEndpointContext; const result = await chargeSubscriptionRenewal(ctx, paystackOptions, { subscriptionId: sub.id, }); if (result.status === "success") { console.log(`Renewed subscription ${sub.id}`); } else { console.error(`Failed to renew ${sub.id}:`, result.data); // Handle retry logic or notify user } } catch (error) { console.error(`Error renewing ${sub.id}:`, error); } } } ``` -------------------------------- ### Run Paystack Client API Tests Source: https://github.com/alexasomba/better-auth-paystack/blob/main/skills/paystack-client-api/SKILL.md Execute the typesafety and paystack specific tests for the client API using the 'vp test' command. ```bash vp test test/typesafety.test.ts vp test test/paystack.test.ts ``` -------------------------------- ### Build Core Library Source: https://github.com/alexasomba/better-auth-paystack/blob/main/README.md Builds the core library of the project. ```bash vp build ``` -------------------------------- ### GET /paystack/subscription-manage-link Source: https://github.com/alexasomba/better-auth-paystack/blob/main/_autodocs/endpoints.md Retrieves the Paystack billing portal URL for managing a subscription. ```APIDOC ## GET /paystack/subscription-manage-link ### Description Get Paystack billing portal URL for managing a subscription. ### Method GET ### Endpoint /paystack/subscription-manage-link ### Parameters #### Query Parameters - **subscriptionCode** (string) - Required - Paystack subscription code ### Response #### Success Response (200) - **link** (string) - Paystack portal URL #### Error Response - **404** - `SUBSCRIPTION_NOT_FOUND` - Subscription code not found. ### Response Example { "link": "https://billing.paystack.com/manage/sub_123" } ``` -------------------------------- ### GET /paystack/list-subscriptions Source: https://github.com/alexasomba/better-auth-paystack/blob/main/_autodocs/endpoints.md Lists all subscriptions associated with the current user or a specified organization. ```APIDOC ## GET /paystack/list-subscriptions ### Description List all subscriptions for the current user or organization. ### Method GET ### Endpoint /paystack/list-subscriptions ### Parameters #### Query Parameters - **referenceId** (string) - Optional - Filter by user/org ID (defaults to current user) ### Response #### Success Response (200) - **subscriptions** (Subscription[]) - List of subscription objects. #### Error Response - **401** - `UNAUTHORIZED` - Not authorized to list subscriptions for the specified reference. ### Response Example { "subscriptions": [ { "subscriptionCode": "sub_123", "planCode": "plan_abc", "status": "active", "createdAt": "2023-01-01T10:00:00Z" } ] } ``` -------------------------------- ### Example: Subscription renewal transaction Source: https://github.com/alexasomba/better-auth-paystack/blob/main/_autodocs/database-schema.md Illustrates the structure of a 'paystackTransaction' record for a subscription renewal. ```typescript { reference: "rec_sub_123_1719316800000", referenceId: "user_123", userId: "user_123", amount: 100000, currency: "NGN", status: "success", plan: "pro", metadata: JSON.stringify({ type: "renewal", subscriptionId: "sub_123", }), } ``` -------------------------------- ### Run Local Subscription Tests Source: https://github.com/alexasomba/better-auth-paystack/blob/main/skills/paystack-local-subscriptions/SKILL.md Execute focused tests for local subscription lifecycle and seat billing scenarios. ```bash vp test test/local_subscription.test.ts vp test test/seat_billing.test.ts ``` -------------------------------- ### Example: One-time product purchase transaction Source: https://github.com/alexasomba/better-auth-paystack/blob/main/_autodocs/database-schema.md Illustrates the structure of a 'paystackTransaction' record for a one-time product purchase. ```typescript { reference: "txn_abc123", referenceId: "user_123", userId: "user_123", amount: 200000, currency: "NGN", status: "success", product: "credits_50", metadata: null, } ``` -------------------------------- ### Configure Server Plugin with Paystack Source: https://github.com/alexasomba/better-auth-paystack/blob/main/_autodocs/README.md Set up the Better Auth server plugin with Paystack configuration, including secret keys and subscription plans. Ensure environment variables are set. ```typescript import { betterAuth, } from "better-auth"; import { paystack, } from "@alexasomba/better-auth-paystack"; import { createPaystack, } from "@alexasomba/paystack-node"; export const auth = betterAuth({ plugins: [ paystack({ secretKey: process.env.PAYSTACK_SECRET_KEY!, webhook: { secret: process.env.PAYSTACK_WEBHOOK_SECRET! }, subscription: { enabled: true, plans: [ { name: "pro", planCode: "PLN_pro_code" }, { name: "starter", amount: 50000, currency: "NGN", interval: "monthly" }, ], }, }), ], }); ``` -------------------------------- ### Get Paystack Plugin Configuration Source: https://github.com/alexasomba/better-auth-paystack/blob/main/_autodocs/api-reference-client-plugin.md Retrieves the current configuration of the Paystack plugin, including details about plans and products. ```typescript authClient.paystack.config(): Promise>> ``` -------------------------------- ### Get Subscription Manage Link Source: https://github.com/alexasomba/better-auth-paystack/blob/main/_autodocs/api-reference-client-plugin.md Provides a direct link for managing subscription details. This is an alias for the `billingPortal` function. ```typescript authClient.subscription.manageLink(data, options?): Promise> ``` -------------------------------- ### Configure Environment Variables Source: https://github.com/alexasomba/better-auth-paystack/blob/main/examples/tanstack/README.md Sets up essential environment variables for Paystack and Better Auth in a .dev.vars file for local development. ```env PAYSTACK_SECRET_KEY=sk_test_... PAYSTACK_WEBHOOK_SECRET=sk_test_... BETTER_AUTH_SECRET=your-secret-key BETTER_AUTH_URL=http://localhost:8787 VITE_BETTER_AUTH_URL=http://localhost:8787 ``` -------------------------------- ### Direct Get Subscription Manage Link Source: https://github.com/alexasomba/better-auth-paystack/blob/main/_autodocs/api-reference-client-plugin.md Provides direct access to retrieve the subscription management link from the Paystack plugin. ```typescript authClient.paystack.getSubscriptionManageLink(data, options?): Promise> ``` -------------------------------- ### Enable Subscription (Legacy) Source: https://github.com/alexasomba/better-auth-paystack/blob/main/_autodocs/api-reference-client-plugin.md Legacy endpoint to enable a subscription. Use `restore-subscription` instead. ```APIDOC ## POST /paystack/enable-subscription ### Description Legacy endpoint to enable a subscription. This method is maintained for backward compatibility and is planned for removal. Use `/paystack/restore-subscription` instead. ### Method POST ### Endpoint /paystack/enable-subscription ### Parameters #### Request Body - **subscriptionId** (string) - Required - The ID of the subscription to enable. - **referenceId** (string) - Optional - The ID of the reference (e.g., organization) associated with the subscription. ### Request Example ```json { "subscriptionId": "sub_abcde" } ``` ### Response #### Success Response (200) - **message** (string) - Confirmation message indicating the subscription has been enabled. ``` -------------------------------- ### Run Tests Source: https://github.com/alexasomba/better-auth-paystack/blob/main/README.md Executes the project's tests. ```bash vp test ``` -------------------------------- ### Paystack Secret Key Example Source: https://github.com/alexasomba/better-auth-paystack/blob/main/_autodocs/configuration.md Provide your Paystack API secret key. This key is used for SDK instantiation and API operations. ```typescript secretKey: "sk_live_abc123xyz" ``` -------------------------------- ### Cloudflare Workers Cron Integration Example Source: https://github.com/alexasomba/better-auth-paystack/blob/main/_autodocs/api-reference-server-operations.md Illustrates how to integrate subscription renewal logic within a Cloudflare Workers scheduled event. ```typescript export default { async scheduled(event, env) { const ctx = { context: await auth.$context }; // Iterate subscriptions and call chargeSubscriptionRenewal }, }; ``` -------------------------------- ### Define Subscription Plans Statically Source: https://github.com/alexasomba/better-auth-paystack/blob/main/_autodocs/configuration.md Provide a static array of `PaystackPlan` objects to define subscription plans. Each plan requires a name and can include details like amount, currency, interval, and limits. ```typescript subscription: { plans: [ { name: "pro", planCode: "PLN_pro_code", amount: 100000, currency: "NGN", interval: "monthly", limits: { teams: 10, seats: 20 }, freeTrial: { days: 14 }, }, { name: "starter", amount: 50000, currency: "NGN", interval: "monthly", }, ], } ``` -------------------------------- ### GET /paystack/list-transactions Source: https://github.com/alexasomba/better-auth-paystack/blob/main/_autodocs/endpoints.md Retrieves a list of all transactions, both one-time and subscription-related, for the current user or a specified organization. It supports filtering by a user/organization ID. ```APIDOC ## GET /paystack/list-transactions ### Description Lists all transactions (one-time and subscription-related) for the current user or organization. It validates the session and user, determines the reference ID, verifies authorization if a custom ID is provided, and queries the local database for matching transactions. ### Method GET ### Endpoint /paystack/list-transactions ### Parameters #### Query Parameters - **referenceId** (string) - Optional - Filter by user/org ID (defaults to current user) ### Response #### Success Response (200) - **transactions** (PaystackTransaction[]) - An array of transaction objects #### Response Example ```json { "transactions": [ { ... }, { ... } ] } ``` #### Error Responses - **401 UNAUTHORIZED**: Not authorized to list transactions for the specified reference ``` -------------------------------- ### Configure Client Plugin with Paystack Source: https://github.com/alexasomba/better-auth-paystack/blob/main/_autodocs/README.md Set up the Better Auth client plugin for interacting with Paystack services from the frontend. ```typescript import { createAuthClient, } from "better-auth/client"; import { paystackClient, } from "@alexasomba/better-auth-paystack/client"; export const client = createAuthClient({ plugins: [paystackClient()], }); ``` -------------------------------- ### Handle Email Verification Requirement Source: https://github.com/alexasomba/better-auth-paystack/blob/main/_autodocs/errors.md This example shows how to handle the EMAIL_VERIFICATION_REQUIRED error. If triggered, it suggests redirecting the user to an email verification page. ```typescript const result = await client.transaction.initialize({ plan: "pro", }); if (result.error?.code === "EMAIL_VERIFICATION_REQUIRED") { // Redirect to email verification navigate("/verify-email"); } ``` -------------------------------- ### Create the Better Auth Client Plugin Source: https://github.com/alexasomba/better-auth-paystack/blob/main/skills/paystack-tanstack-start/SKILL.md Initialize the client-side authentication client using `createAuthClient` and the Paystack client plugin. This is used in client components for authentication-related actions. ```typescript import { createAuthClient } from "better-auth/client"; import { paystackClient } from "@alexasomba/better-auth-paystack/client"; export const authClient = createAuthClient({ plugins: [paystackClient()], }); ``` -------------------------------- ### Enable Organization-Level Billing Source: https://github.com/alexasomba/better-auth-paystack/blob/main/_autodocs/configuration.md Enable organization-level billing by setting 'organization.enabled' to true. This requires the Better Auth organization and member plugins to be installed. ```typescript betterAuth({ plugins: [ organization(), // Required paystack({ organization: { enabled: true, }, subscription: { ... }, }), ], }) ``` -------------------------------- ### Get Billing Portal Link Source: https://github.com/alexasomba/better-auth-paystack/blob/main/_autodocs/api-reference-client-plugin.md Generates a URL for the Paystack billing portal, allowing users to manage their subscriptions. Returns the portal link. ```typescript authClient.subscription.billingPortal(data, options?): Promise> ``` -------------------------------- ### Environment Variables for Paystack and Better Auth Source: https://github.com/alexasomba/better-auth-paystack/blob/main/_autodocs/configuration.md Set up essential environment variables for Paystack credentials, webhook secrets, and Better Auth configuration. Optional variables for email verification are also included. ```bash # Paystack Credentials PAYSTACK_SECRET_KEY=sk_live_abc123xyz PAYSTACK_WEBHOOK_SECRET=sk_live_abc123xyz # Usually same as secret key # Better Auth BETTER_AUTH_SECRET=random_generated_secret BETTER_AUTH_URL=http://localhost:3000 # Optional: Email verification ENABLE_EMAIL_VERIFICATION=true ``` -------------------------------- ### authClient.subscription.create Source: https://github.com/alexasomba/better-auth-paystack/blob/main/README.md Initializes a transaction to create a subscription. ```APIDOC ## authClient.subscription.create ### Description Initializes a transaction to create a new subscription. This method is an alias for `authClient.transaction.initialize` when a `plan` is specified. ### Method `authClient.subscription.create(upgradeSubscription)` ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body * `upgradeSubscription` (object) - Configuration for creating the subscription. * `plan` (string) - The name of the plan to subscribe to. * `email` (string) - Optional. The email of the subscriber. Defaults to the current user's email. * `amount` (number) - Optional. Amount to charge (if not using a Paystack Plan Code). * `currency` (string) - Optional. Currency code (e.g., "NGN"). * `callbackURL` (string) - Optional. The callback URL to redirect to after payment. * `metadata` (Record) - Optional. Additional metadata to store with the transaction. * `referenceId` (string) - Optional. Reference ID for the subscription owner (User ID or Org ID). Defaults to the current user's ID. * `quantity` (number) - Optional. Number of seats to purchase (for team plans). ### Request Example ```ts await authClient.subscription.create({ plan: "basic", email: "user@example.com", referenceId: "user_123", }); ``` ### Response #### Success Response (Details not provided in source) #### Response Example (Details not provided in source) ``` -------------------------------- ### Get Plugin Configuration Success Response Source: https://github.com/alexasomba/better-auth-paystack/blob/main/_autodocs/endpoints.md The response when retrieving plugin configuration, including available plans and products. This endpoint does not require authentication. ```typescript { plans?: PaystackPlan[]; products?: PaystackProduct[]; } ``` -------------------------------- ### List Endpoints with Query Parameters Source: https://github.com/alexasomba/better-auth-paystack/blob/main/skills/paystack-client-api/SKILL.md When using list endpoints, pass query data within the 'query' object. These endpoints expect GET requests. ```typescript await authClient.subscription.list({ query: { referenceId: "org_123" } }); await authClient.transaction.list({ query: { referenceId: "org_123" } }); ``` -------------------------------- ### Initialize and Checkout Subscription Upgrade Source: https://github.com/alexasomba/better-auth-paystack/blob/main/README.md Use this snippet to upgrade a subscription and initiate a Paystack checkout if an access code is provided. ```typescript const { data } = await authClient.subscription.upgrade({ plan: "pro" }); if (data?.accessCode) { const paystack = createPaystack({ publicKey: "pk_test_..." }); paystack.checkout({ accessCode: data.accessCode, onSuccess: (res) => authClient.paystack.transaction.verify({ reference: res.reference }), }); } ``` -------------------------------- ### Initialize Transaction for Fixed Product Source: https://github.com/alexasomba/better-auth-paystack/blob/main/README.md Initiate a payment transaction for a pre-defined product by its name. This is used for fixed-price items like 'credits_50'. ```typescript await authClient.paystack.transaction.initialize({ product: "credits_50", }); ``` -------------------------------- ### Hook for New Subscription Creation Source: https://github.com/alexasomba/better-auth-paystack/blob/main/_autodocs/configuration.md Run custom code when a new subscription record is first initialized. This can be used for logging or initial setup analytics. ```typescript subscription: { onSubscriptionCreated: async ({ subscription }) => { // Log subscription start for analytics await analytics.track("subscription_created", { plan: subscription.plan, userId: subscription.userId, }); }, plans: [...], } ``` -------------------------------- ### Authorize Reference for Billing Management Source: https://github.com/alexasomba/better-auth-paystack/blob/main/README.md Control who can manage billing for specific references (Users or Organizations). This example restricts actions to Org Admins for organization-related references. ```typescript paystack({ subscription: { authorizeReference: async ({ user, referenceId, action }) => { // Example: Only allow Org Admins to initialize transactions if (referenceId.startsWith("org_")) { const member = await db.findOne({ model: "member", where: [ { field: "organizationId", value: referenceId }, { field: "userId", value: user.id }, ], }); return member?.role === "admin"; } return user.id === referenceId; }, }, }); ``` -------------------------------- ### Configure Paystack Plugin with Environment Variables Source: https://github.com/alexasomba/better-auth-paystack/blob/main/_autodocs/configuration.md Integrate Paystack using environment variables for secret keys and webhook configuration. Enables email verification for subscriptions if specified. ```typescript paystack({ secretKey: process.env.PAYSTACK_SECRET_KEY!, webhook: { secret: process.env.PAYSTACK_WEBHOOK_SECRET!, }, subscription: { enabled: true, requireEmailVerification: process.env.ENABLE_EMAIL_VERIFICATION === "true", plans: [...], }, }) ``` -------------------------------- ### Get Subscription by Paystack Code Source: https://github.com/alexasomba/better-auth-paystack/blob/main/_autodocs/database-schema.md This TypeScript snippet illustrates how to fetch a unique subscription using its Paystack subscription code with Prisma's `findUnique` method. ```typescript const subscription = await db.subscription.findUnique({ where: { paystackSubscriptionCode: "SUB_abc123", }, }); ``` -------------------------------- ### List Products Success Response Source: https://github.com/alexasomba/better-auth-paystack/blob/main/_autodocs/endpoints.md The response when listing all available products for one-time purchase. Returns an empty array if no products are configured. ```typescript { products: PaystackProduct[]; } ```