Nextbase Docs
Nextbase Docs
HomeBlogWelcome to Nextbase v3!Getting Started with NextBaseQuick setup
Stripe ConfigurationStripe Webhooks
Payments

Stripe Configuration

Stripe is implemented using an Abstract payment provider. It has the following shape.

import { DBTable } from "@/types";
import { Dictionary } from "lodash";

export interface PaginationOptions {
  limit?: number;
  startingAfter?: string;
  endingBefore?: string;
}

export interface PaginatedResponse<T> {
  data: T[];
  hasMore: boolean;
  totalCount?: number;
}

export type CustomerData = {
  id?: string;
  email: string;
  metadata?: { [key: string]: any };
};

export type SubscriptionData = DBTable<"billing_subscriptions"> & {
  billing_prices: DBTable<"billing_prices"> | null;
  billing_products: DBTable<"billing_products"> | null;
};

export type ProductData = DBTable<"billing_products"> & {
  billing_prices: DBTable<"billing_prices">[];
};

export type ProductAndPrice = {
  product: DBTable<"billing_products">;
  price: DBTable<"billing_prices">;
};

export type InvoiceData = DBTable<"billing_invoices"> & {
  billing_products: DBTable<"billing_products"> | null;
  billing_prices: DBTable<"billing_prices"> | null;
};

export type OneTimePaymentData = DBTable<"billing_one_time_payments"> & {
  billing_products: DBTable<"billing_products"> | null;
  billing_prices: DBTable<"billing_prices"> | null;
  billing_invoices: DBTable<"billing_invoices"> | null;
};

export interface CheckoutSessionData {
  id: string;
  url: string;
}

export interface CustomerPortalData {
  url: string;
}

export interface PaymentMethodData {
  id: string;
  customerId: string;
  type: "card" | "bank_account" | "other";
  last4: string;
  expiryMonth?: number;
  expiryYear?: number;
}

export type CheckoutSessionOptions = {
  freeTrialDays?: number;
};

export abstract class PaymentGateway {
  abstract getName(): string;

  /**
   * These are methods which perform operations on the database.
   */
  abstract db: {
    createCustomer(
      customerData: Partial<DBTable<"billing_customers">>,
      workspaceId: string,
    ): Promise<DBTable<"billing_customers">>;
    getCustomerByCustomerId(
      customerId: string,
    ): Promise<DBTable<"billing_customers">>;
    getCustomerByWorkspaceId(
      workspaceId: string,
    ): Promise<DBTable<"billing_customers"> | null>;
    hasCustomer(customerId: string): Promise<boolean>;
    updateCustomer(
      customerId: string,
      updateData: Partial<DBTable<"billing_customers">>,
    ): Promise<DBTable<"billing_customers">>;
    deleteCustomer(customerId: string): Promise<void>;
    listCustomers(
      options?: PaginationOptions,
    ): Promise<PaginatedResponse<DBTable<"billing_customers">>>;
    // Subscription methods
    getSubscriptionsByCustomerId(
      customerId: string,
    ): Promise<SubscriptionData[]>;
    getSubscriptionsByWorkspaceId(
      workspaceId: string,
    ): Promise<SubscriptionData[]>;
    getSubscription(subscriptionId: string): Promise<SubscriptionData>;
    listSubscriptions(
      customerId: string,
      options?: PaginationOptions,
    ): Promise<PaginatedResponse<SubscriptionData>>;
    // Invoice methods
    getInvoice(invoiceId: string): Promise<InvoiceData>;
    listInvoicesByCustomerId(
      customerId: string,
      options?: PaginationOptions,
    ): Promise<PaginatedResponse<InvoiceData>>;
    listInvoicesByWorkspaceId(
      workspaceId: string,
      options?: PaginationOptions,
    ): Promise<PaginatedResponse<InvoiceData>>;
    // Product methods
    getProduct(productId: string): Promise<ProductData>;
    listProducts(options?: PaginationOptions): Promise<Array<ProductData>>;
  };

  abstract util: {
    createCustomerForWorkspace(
      workspaceId: string,
    ): Promise<DBTable<"billing_customers">>;
    getCustomerByWorkspaceId(
      workspaceId: string,
    ): Promise<DBTable<"billing_customers"> | null>;
    supportsFeature(featureName: string): boolean;
    isTestMode(): boolean;
  };

  /**
   * These are methods which perform operations on the payment gateway.
   */
  abstract gateway: {
    createGatewayCustomer(
      userData: Partial<CustomerData>,
    ): Promise<CustomerData>;
    // Webhook methods
    handleGatewayWebhook(body: any, signature: string): Promise<void>;
  };
  abstract anonScope: {
    listAllProducts(): Promise<ProductAndPrice[]>;
    /**
     * List all subscription products that are visible to the user.
     */
    listAllSubscriptionProducts(): Promise<Dictionary<ProductAndPrice[]>>;
    /**
     * List all one-time products that are visible to the user.
     */
    listAllOneTimeProducts(): Promise<ProductAndPrice[]>;
  };
  abstract userScope: {
    getWorkspaceDatabaseSubscriptions(
      workspaceId: string,
    ): Promise<DBTable<"billing_subscriptions">[]>;
    getWorkspaceDatabaseOneTimePurchases(
      workspaceId: string,
    ): Promise<OneTimePaymentData[]>;
    getWorkspaceDatabaseInvoices(
      workspaceId: string,
    ): Promise<PaginatedResponse<InvoiceData>>;
    getWorkspaceDatabasePaymentMethods(
      workspaceId: string,
    ): Promise<DBTable<"billing_payment_methods">[]>;
    getWorkspaceDatabaseCustomer(
      workspaceId: string,
    ): Promise<DBTable<"billing_customers">>;
    // Checkout methods
    createGatewayCheckoutSession({
      productId,
      priceId,
      options,
      workspaceId,
    }: {
      workspaceId: string;
      productId: string;
      priceId: string;
      options?: CheckoutSessionOptions;
    }): Promise<CheckoutSessionData>;
    // Customer portal methods
    createGatewayCustomerPortalSession(
      workspaceId: string,
      returnUrl: string,
    ): Promise<CustomerPortalData>;
  };
  abstract superAdminScope: {
    syncProducts(): Promise<void>;
    syncCustomers(): Promise<void>;
    toggleProductVisibility(
      productId: string,
      isVisible: boolean,
    ): Promise<void>;
    listAllProducts(): Promise<ProductData[]>;
    getCurrentMRR(): Promise<number>;
    getSubscriptionsByMonthBetween(
      startDate: Date,
      endDate: Date,
    ): Promise<{ month: Date; subscriptions: number }[]>;
    getCurrentRevenueByProduct(): Promise<
      { productId: string; revenue: number }[]
    >;
    getCurrentMonthRevenue(): Promise<number>;
    getLastMonthRevenue(): Promise<number>;
    listCurrentMonthInvoices(): Promise<InvoiceData[]>;
    listCurrentMonthSubscriptions(): Promise<SubscriptionData[]>;
    listCustomers(): Promise<DBTable<"billing_customers">[]>;
  };
}

Login with API Key

Nextbase Ultimate supports authentication using API keys, which is useful for integrating with external services or for machine-to-machine communication.

Stripe Webhooks

Next Page