@alexasomba/better-auth-paystack
Version:
Production-ready Paystack billing plugin for Better Auth. Supports subscriptions, one-time payments, organization billing, secure webhooks and more
781 lines • 30.2 kB
text/typescript
import { AuthContext, BetterAuthPlugin, GenericEndpointContext, InferOptionSchema, MiddlewareInputContext, MiddlewareOptions, Session, StrictEndpoint, User, defineErrorCodes } from "better-auth";
import { z } from "zod";
import { PaystackCustomerClient, PaystackPlanClient, PaystackProductClient, PaystackSubscriptionClient, PaystackTransactionClient, PaystackWebhookEvent, TransactionChargeAuthorizationResponseData, TransactionVerifyResponseData } from "@alexasomba/paystack-node";
import { BetterAuthPluginDBSchema, DBFieldAttribute } from "better-auth/db";
import "better-auth/plugins/organization";
//#region src/schema.d.ts
type PluginSchemaTable<TableName extends string, FieldName extends string> = Record<TableName, {
fields: Record<FieldName, DBFieldAttribute>;
disableMigration?: boolean;
modelName?: string;
}>;
type TransactionsSchema = PluginSchemaTable<"paystackTransaction", "reference" | "paystackId" | "referenceId" | "userId" | "amount" | "currency" | "status" | "plan" | "product" | "metadata" | "createdAt" | "updatedAt">;
type SubscriptionsSchema = PluginSchemaTable<"subscription", "plan" | "referenceId" | "paystackCustomerCode" | "paystackSubscriptionCode" | "paystackTransactionReference" | "paystackAuthorizationCode" | "paystackEmailToken" | "status" | "periodStart" | "periodEnd" | "trialStart" | "trialEnd" | "cancelAtPeriodEnd" | "cancelAt" | "canceledAt" | "endedAt" | "billingInterval" | "groupId" | "seats" | "pendingPlan">;
type UserSchema = PluginSchemaTable<"user", "paystackCustomerCode">;
type OrganizationSchema = PluginSchemaTable<"organization", "paystackCustomerCode" | "email">;
type ProductsSchema = PluginSchemaTable<"paystackProduct", "name" | "description" | "price" | "currency" | "quantity" | "unlimited" | "paystackId" | "slug" | "metadata" | "createdAt" | "updatedAt">;
type PlansSchema = PluginSchemaTable<"paystackPlan", "name" | "description" | "amount" | "currency" | "interval" | "group" | "planCode" | "paystackId" | "metadata" | "createdAt" | "updatedAt">;
type PaystackPluginSchema = SubscriptionsSchema & TransactionsSchema & UserSchema & OrganizationSchema & ProductsSchema & PlansSchema;
declare const getSchema: (options: PaystackOptions) => BetterAuthPluginDBSchema;
//#endregion
//#region src/types.d.ts
type PaystackCheckoutChannel = "card" | "bank" | "ussd" | "qr" | "mobile_money" | "bank_transfer" | "eft" | "apple_pay";
/**
* Custom models for Paystack Plugin
* These align with the database schema in src/schema.ts
*/
interface PaystackTransaction {
id: string;
reference: string;
paystackId?: string;
referenceId: string;
userId: string;
amount: number;
currency: string;
status: string;
plan?: string | null;
product?: string | null;
metadata?: string | null;
createdAt: Date;
updatedAt: Date;
}
interface PaystackProduct {
id?: string;
name: string;
description?: string;
price: number;
currency: string;
quantity?: number;
unlimited?: boolean;
paystackId?: string;
slug?: string;
metadata?: string | null;
createdAt?: Date;
updatedAt?: Date;
}
interface PaystackPlan {
id?: string;
name: string;
description?: string;
amount?: number;
currency?: string;
interval?: string;
planCode?: string;
paystackId?: string;
seatAmount?: number;
/**
* Deprecated legacy alias for `seatAmount`.
* If used, it must still be a numeric amount in the smallest currency unit.
*/
seatPriceId?: number | string;
seatPlanCode?: string;
invoiceLimit?: number;
/**
* Optional subscription group. A reference may hold one active or trialing
* subscription per normalized group. Omitted values use the legacy default group.
*/
group?: string;
freeTrial?: {
days?: number;
onTrialStart?: (subscription: Subscription) => Promise<void>;
onTrialEnd?: (subscription: Subscription) => Promise<void>;
onTrialExpired?: (subscription: Subscription) => Promise<void>;
};
limits?: Record<string, unknown>;
features?: string[];
metadata?: string | null;
createdAt?: Date;
updatedAt?: Date;
}
/**
* Paystack Webhook Payload structure
*/
type PaystackWebhookPayload = PaystackWebhookEvent;
/**
* Paystack SDK Result types
*/
type PaystackTransactionResponse = TransactionVerifyResponseData;
type PaystackChargeAuthorizationResponse = TransactionChargeAuthorizationResponseData;
type PaystackInitializeResult = {
kind: "checkout";
url: string;
reference: string;
accessCode: string;
redirect: true;
} | {
kind: "scheduled";
status: "success";
message: string;
scheduled: true;
} | {
kind: "prorated";
status: "success";
message: string;
prorated: true;
};
interface SubscriptionOptions {
/**
* Enable subscriptions
*/
enabled?: boolean;
/**
* Plans configuration
*/
plans: PaystackPlan[] | (() => Promise<PaystackPlan[]>);
/**
* Automatically sync quantity from local DB to Paystack (if seats are used)
*/
autoSyncQuantity?: boolean;
/**
* Handling of subscription cancellation
* @default "at_period_end"
*/
cancelBehavior?: "at_period_end" | "immediately";
/**
* Handlers for subscription events
*/
onSubscriptionComplete?: (data: {
event: PaystackWebhookPayload;
subscription: Subscription;
plan: PaystackPlan;
}, ctx: GenericEndpointContext) => Promise<void>;
onSubscriptionCreated?: (data: {
event: PaystackWebhookPayload;
subscription: Subscription;
plan: PaystackPlan;
}, ctx: GenericEndpointContext) => Promise<void>;
onSubscriptionUpdate?: (data: {
event: PaystackWebhookPayload;
subscription: Subscription;
plan: PaystackPlan;
}, ctx: GenericEndpointContext) => Promise<void>;
onSubscriptionCancel?: (data: {
event: PaystackWebhookPayload;
subscription: Subscription;
}, ctx: GenericEndpointContext) => Promise<void>;
/**
* Authorization handler for reference checks
*/
authorizeReference?: (data: {
user: User;
session: Session;
referenceId: string;
action: string;
}, ctx: GenericEndpointContext) => Promise<boolean>;
/**
* Require email verification before subscription
*/
requireEmailVerification?: boolean;
/**
* Restrict checkout to specific Paystack channels for subscription flows.
* Use `["card"]` to enforce card-only subscriptions.
*/
allowedPaymentChannels?: PaystackCheckoutChannel[];
}
interface PaystackOptions<TPaystackClient extends PaystackClientLike = PaystackClientLike> {
/**
* Paystack Secret Key
*/
secretKey: string;
/**
* @deprecated Paystack signs webhooks with `secretKey`; this option is ignored.
*/
paystackWebhookSecret?: string;
/**
* Paystack Client Instance
* If provided, will be used instead of creating a new one with secretKey
*/
paystackClient?: TPaystackClient;
/**
* Webhook configuration
*/
webhook?: {
/**
* @deprecated Paystack signs webhooks with `secretKey`; this option is ignored.
*/
secret?: string;
/**
* Whether to verify the request origin IP address
* @default false
*/
verifyIP?: boolean;
/**
* List of trusted IP addresses for webhooks.
* Defaults to official Paystack IPs if verifyIP is true and this is empty.
*/
trustedIPs?: string[];
};
/**
* Subscription configuration
*/
subscription?: SubscriptionOptions;
/**
* Billing pattern
* @default "native"
*/
billingPattern?: "native" | "local";
/**
* Global event handler
*/
onEvent?: (event: PaystackWebhookEvent) => Promise<void>;
/**
* Organization billing configuration
*/
organization?: {
enabled?: boolean;
/**
* Organization member roles allowed to manage billing when `subscription.authorizeReference`
* is not provided.
*
* @default ["owner", "admin"]
*/
billingRoles?: string[];
getCustomerCreateParams?: (org: {
id: string;
name: string;
email?: string | null;
}, ctx: GenericEndpointContext) => Promise<Record<string, unknown>>;
onCustomerCreate?: (data: {
paystackCustomer: Record<string, unknown>;
organization: unknown;
}, ctx: GenericEndpointContext) => Promise<void>;
};
/**
* Products configuration
*/
products?: {
products?: PaystackProduct[] | (() => Promise<PaystackProduct[]>);
};
createCustomerOnSignUp?: boolean;
onCustomerCreate?: (data: {
paystackCustomer: Record<string, unknown>;
user: unknown;
}, ctx: GenericEndpointContext) => Promise<void>;
/**
* Custom database schema / model names
*/
schema?: InferOptionSchema<PaystackPluginSchema>;
}
interface Subscription {
id: string;
userId: string;
organizationId?: string;
plan: string;
pendingPlan?: string | null;
paystackSubscriptionCode?: string;
paystackCustomerCode?: string;
paystackPlanCode?: string;
paystackAuthorizationCode?: string;
paystackTransactionReference?: string;
paystackEmailToken?: string;
status: string;
seats: number;
referenceId: string;
periodStart?: Date | null;
periodEnd?: Date | null;
cancelAtPeriodEnd: boolean;
cancelAt?: Date | null;
canceledAt?: Date | null;
endedAt?: Date | null;
billingInterval?: string | null;
trialStart?: Date | null;
trialEnd?: Date | null;
groupId?: string | null;
createdAt: Date;
updatedAt: Date;
}
interface ChargeRecurringSubscriptionInput {
subscriptionId: string;
amount?: number;
}
interface ChargeRecurringSubscriptionResult {
status: "success" | "failed";
data: PaystackChargeAuthorizationResponse;
}
interface PaystackSyncResult {
status: "success";
count: number;
}
type AnyPaystackOptions = PaystackOptions<PaystackClientLike>;
/**
* Exact grouped SDK slices used by this plugin.
* This deliberately matches the official SDK surface instead of a handwritten approximation.
*/
interface PaystackClientLike {
transaction: Pick<PaystackTransactionClient, "initialize" | "verify" | "chargeAuthorization">;
customer: Pick<PaystackCustomerClient, "create" | "update" | "fetch">;
subscription: Pick<PaystackSubscriptionClient, "create" | "fetch" | "disable" | "enable" | "manageLink">;
product: Pick<PaystackProductClient, "fetch" | "list">;
plan: Pick<PaystackPlanClient, "list" | "create">;
}
//#endregion
//#region src/routes.d.ts
declare const paystackWebhook: <P extends string = "/webhook">(options: AnyPaystackOptions, path?: P) => StrictEndpoint<P, {
method: "POST";
metadata: {
openapi: {
operationId: string;
};
scope: "server";
};
cloneRequest: true;
disableBody: true;
}, {
received: boolean;
}>;
declare const initializeTransaction: <P extends string = "/initialize-transaction">(options: AnyPaystackOptions, path?: P) => StrictEndpoint<P, {
method: "POST";
body: z.ZodObject<{
plan: z.ZodOptional<z.ZodString>;
product: z.ZodOptional<z.ZodString>;
amount: z.ZodOptional<z.ZodNumber>;
currency: z.ZodOptional<z.ZodString>;
email: z.ZodOptional<z.ZodString>;
metadata: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
referenceId: z.ZodOptional<z.ZodString>;
subscriptionId: z.ZodOptional<z.ZodString>;
callbackURL: z.ZodOptional<z.ZodString>;
quantity: z.ZodOptional<z.ZodNumber>;
scheduleAtPeriodEnd: z.ZodOptional<z.ZodBoolean>;
cancelAtPeriodEnd: z.ZodOptional<z.ZodBoolean>;
prorateAndCharge: z.ZodOptional<z.ZodBoolean>;
}, z.core.$strip>;
use: (((getValue: (ctx: GenericEndpointContext) => string | string[]) => (inputContext: MiddlewareInputContext<MiddlewareOptions>) => Promise<void>) | ((inputContext: MiddlewareInputContext<MiddlewareOptions>) => Promise<unknown>))[];
}, PaystackInitializeResult | undefined>;
declare const createSubscription: <P extends string = "/create-subscription">(options: AnyPaystackOptions, path?: P) => StrictEndpoint<P, {
method: "POST";
body: z.ZodObject<{
plan: z.ZodOptional<z.ZodString>;
product: z.ZodOptional<z.ZodString>;
amount: z.ZodOptional<z.ZodNumber>;
currency: z.ZodOptional<z.ZodString>;
email: z.ZodOptional<z.ZodString>;
metadata: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
referenceId: z.ZodOptional<z.ZodString>;
subscriptionId: z.ZodOptional<z.ZodString>;
callbackURL: z.ZodOptional<z.ZodString>;
quantity: z.ZodOptional<z.ZodNumber>;
scheduleAtPeriodEnd: z.ZodOptional<z.ZodBoolean>;
cancelAtPeriodEnd: z.ZodOptional<z.ZodBoolean>;
prorateAndCharge: z.ZodOptional<z.ZodBoolean>;
}, z.core.$strip>;
use: (((getValue: (ctx: GenericEndpointContext) => string | string[]) => (inputContext: MiddlewareInputContext<MiddlewareOptions>) => Promise<void>) | ((inputContext: MiddlewareInputContext<MiddlewareOptions>) => Promise<unknown>))[];
}, PaystackInitializeResult | undefined>;
declare const upgradeSubscription: <P extends string = "/upgrade-subscription">(options: AnyPaystackOptions, path?: P) => StrictEndpoint<P, {
method: "POST";
body: z.ZodObject<{
plan: z.ZodOptional<z.ZodString>;
product: z.ZodOptional<z.ZodString>;
amount: z.ZodOptional<z.ZodNumber>;
currency: z.ZodOptional<z.ZodString>;
email: z.ZodOptional<z.ZodString>;
metadata: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
referenceId: z.ZodOptional<z.ZodString>;
subscriptionId: z.ZodOptional<z.ZodString>;
callbackURL: z.ZodOptional<z.ZodString>;
quantity: z.ZodOptional<z.ZodNumber>;
scheduleAtPeriodEnd: z.ZodOptional<z.ZodBoolean>;
cancelAtPeriodEnd: z.ZodOptional<z.ZodBoolean>;
prorateAndCharge: z.ZodOptional<z.ZodBoolean>;
}, z.core.$strip>;
use: (((getValue: (ctx: GenericEndpointContext) => string | string[]) => (inputContext: MiddlewareInputContext<MiddlewareOptions>) => Promise<void>) | ((inputContext: MiddlewareInputContext<MiddlewareOptions>) => Promise<unknown>))[];
}, PaystackInitializeResult | undefined>;
declare const cancelSubscription: <P extends string = "/cancel-subscription">(options: AnyPaystackOptions, path?: P) => StrictEndpoint<P, {
method: "POST";
body: z.ZodObject<{
referenceId: z.ZodOptional<z.ZodString>;
subscriptionCode: z.ZodString;
emailToken: z.ZodOptional<z.ZodString>;
atPeriodEnd: z.ZodOptional<z.ZodBoolean>;
}, z.core.$strip>;
use: (((getValue: (ctx: GenericEndpointContext) => string | string[]) => (inputContext: MiddlewareInputContext<MiddlewareOptions>) => Promise<void>) | ((inputContext: MiddlewareInputContext<MiddlewareOptions>) => Promise<unknown>))[];
}, {
status: string;
}>;
declare const restoreSubscription: <P extends string = "/restore-subscription">(options: AnyPaystackOptions, path?: P) => StrictEndpoint<P, {
method: "POST";
body: z.ZodObject<{
referenceId: z.ZodOptional<z.ZodString>;
subscriptionCode: z.ZodString;
emailToken: z.ZodOptional<z.ZodString>;
atPeriodEnd: z.ZodOptional<z.ZodBoolean>;
}, z.core.$strip>;
use: (((getValue: (ctx: GenericEndpointContext) => string | string[]) => (inputContext: MiddlewareInputContext<MiddlewareOptions>) => Promise<void>) | ((inputContext: MiddlewareInputContext<MiddlewareOptions>) => Promise<unknown>))[];
}, {
status: string;
}>;
declare const verifyTransaction: <P extends string = "/verify-transaction">(options: AnyPaystackOptions, path?: P) => StrictEndpoint<P, {
method: "POST";
body: z.ZodObject<{
reference: z.ZodString;
}, z.core.$strip>;
use: (((getValue: (ctx: GenericEndpointContext) => string | string[]) => (inputContext: MiddlewareInputContext<MiddlewareOptions>) => Promise<void>) | ((inputContext: MiddlewareInputContext<MiddlewareOptions>) => Promise<unknown>))[];
}, {
status: string;
reference: string;
data: {
id: number;
domain: string;
status: string;
reference: string;
receipt_number: string | null;
amount: number;
message: string | null;
gateway_response: string;
channel: string;
currency: string;
ip_address: string | null;
metadata: (string | Record<string, never> | number) | null;
log: {
start_time: number;
time_spent: number;
attempts: number;
errors: number;
success: boolean;
mobile: boolean;
input: unknown[];
history: {
type: string;
message: string;
time: number;
}[];
} | null;
fees: number | null;
fees_split: unknown;
authorization: {
authorization_code?: string;
bin?: string | null;
last4?: string;
exp_month?: string;
exp_year?: string;
channel?: string;
card_type?: string;
bank?: string;
country_code?: string;
brand?: string;
reusable?: boolean;
signature?: string;
account_name?: string | null;
receiver_bank_account_number?: string | null;
receiver_bank?: string | null;
};
customer: {
id: number;
first_name: string | null;
last_name: string | null;
email: string;
customer_code: string;
phone: string | null;
metadata: Record<string, never> | null;
risk_action: string;
international_format_phone?: string | null;
};
plan: (string | Record<string, never>) | null;
split: Record<string, never> | null;
order_id: unknown;
paidAt: string | null;
createdAt: string;
requested_amount: number;
pos_transaction_data: unknown;
source: unknown;
fees_breakdown: unknown;
connect: unknown;
transaction_date: string;
plan_object: {
id?: number;
name?: string;
plan_code?: string;
description?: unknown;
amount?: number;
interval?: string;
send_invoices?: boolean;
send_sms?: boolean;
currency?: string;
};
subaccount: Record<string, never> | null;
};
}>;
declare const listSubscriptions: <P extends string = "/list-subscriptions">(options: AnyPaystackOptions, path?: P) => StrictEndpoint<P, {
method: "GET";
query: z.ZodObject<{
referenceId: z.ZodOptional<z.ZodString>;
}, z.core.$strip>;
use: (((getValue: (ctx: GenericEndpointContext) => string | string[]) => (inputContext: MiddlewareInputContext<MiddlewareOptions>) => Promise<void>) | ((inputContext: MiddlewareInputContext<MiddlewareOptions>) => Promise<unknown>))[];
}, {
subscriptions: Subscription[];
}>;
declare const listTransactions: <P extends string = "/list-transactions">(options: AnyPaystackOptions, path?: P) => StrictEndpoint<P, {
method: "GET";
query: z.ZodObject<{
referenceId: z.ZodOptional<z.ZodString>;
}, z.core.$strip>;
use: (((getValue: (ctx: GenericEndpointContext) => string | string[]) => (inputContext: MiddlewareInputContext<MiddlewareOptions>) => Promise<void>) | ((inputContext: MiddlewareInputContext<MiddlewareOptions>) => Promise<unknown>))[];
}, {
transactions: PaystackTransaction[];
}>;
declare const disablePaystackSubscription: <P extends string = "/disable-subscription">(options: AnyPaystackOptions, path?: P) => StrictEndpoint<P, {
method: "POST";
body: z.ZodObject<{
referenceId: z.ZodOptional<z.ZodString>;
subscriptionCode: z.ZodString;
emailToken: z.ZodOptional<z.ZodString>;
atPeriodEnd: z.ZodOptional<z.ZodBoolean>;
}, z.core.$strip>;
use: (((getValue: (ctx: GenericEndpointContext) => string | string[]) => (inputContext: MiddlewareInputContext<MiddlewareOptions>) => Promise<void>) | ((inputContext: MiddlewareInputContext<MiddlewareOptions>) => Promise<unknown>))[];
}, {
status: string;
}>;
declare const enablePaystackSubscription: <P extends string = "/enable-subscription">(options: AnyPaystackOptions, path?: P) => StrictEndpoint<P, {
method: "POST";
body: z.ZodObject<{
referenceId: z.ZodOptional<z.ZodString>;
subscriptionCode: z.ZodString;
emailToken: z.ZodOptional<z.ZodString>;
atPeriodEnd: z.ZodOptional<z.ZodBoolean>;
}, z.core.$strip>;
use: (((getValue: (ctx: GenericEndpointContext) => string | string[]) => (inputContext: MiddlewareInputContext<MiddlewareOptions>) => Promise<void>) | ((inputContext: MiddlewareInputContext<MiddlewareOptions>) => Promise<unknown>))[];
}, {
status: string;
}>;
declare const getSubscriptionManageLink: <P extends string = "/subscription-manage-link">(options: AnyPaystackOptions, path?: P) => StrictEndpoint<P, {
method: "GET";
query: z.ZodObject<{
subscriptionCode: z.ZodString;
}, z.core.$strip>;
use: (((getValue: (ctx: GenericEndpointContext) => string | string[]) => (inputContext: MiddlewareInputContext<MiddlewareOptions>) => Promise<void>) | ((inputContext: MiddlewareInputContext<MiddlewareOptions>) => Promise<unknown>))[];
}, {
link: string | null;
}>;
declare const listProducts: <P extends string = "/list-products">(_options: AnyPaystackOptions, path?: P) => StrictEndpoint<P, {
method: "GET";
metadata: {
openapi: {
operationId: string;
};
};
}, {
products: PaystackProduct[];
}>;
declare const listPlans: <P extends string = "/list-plans">(_options: AnyPaystackOptions, path?: P) => StrictEndpoint<P, {
method: "GET";
metadata: {
scope: "server";
};
use: ((inputContext: MiddlewareInputContext<MiddlewareOptions>) => Promise<{
session: {
session: Record<string, unknown> & {
id: string;
createdAt: Date;
updatedAt: Date;
userId: string;
expiresAt: Date;
token: string;
ipAddress?: string | null | undefined;
userAgent?: string | null | undefined;
};
user: Record<string, unknown> & {
id: string;
createdAt: Date;
updatedAt: Date;
email: string;
emailVerified: boolean;
name: string;
image?: string | null | undefined;
};
};
}>)[];
}, {
plans: PaystackPlan[];
}>;
declare const getConfig: <P extends string = "/get-config">(options: AnyPaystackOptions, path?: P) => StrictEndpoint<P, {
method: "GET";
metadata: {
openapi: {
operationId: string;
};
};
}, {
plans: PaystackPlan[];
products: PaystackProduct[];
}>;
//#endregion
//#region src/version.d.ts
declare const PACKAGE_VERSION = "3.1.1";
//#endregion
//#region src/metadata.d.ts
type PaystackMetadata = Record<string, unknown>;
interface CheckoutMetadataInput {
referenceId: string;
userId: string;
plan?: string;
groupId?: string | null;
product?: string;
extra?: PaystackMetadata;
trial: {
isTrial: boolean;
requested: boolean;
granted: boolean;
deniedReason?: "already_used";
endsAt?: Date;
};
}
interface ProrationMetadataInput {
subscriptionId: string;
referenceId: string;
newPlan: string;
oldPlan: string;
newSeatCount: number;
remainingDays: number;
}
interface RenewalMetadataInput {
subscriptionId: string;
referenceId: string;
}
declare function parsePaystackMetadata(value: unknown): PaystackMetadata;
declare function stringifyPaystackMetadata(value: unknown): string | undefined;
declare function hasPaystackMetadata(value: unknown): boolean;
declare function getMetadataString(metadata: PaystackMetadata, key: string): string | undefined;
declare function getMetadataNumber(metadata: PaystackMetadata, key: string): number | undefined;
declare function getMetadataBoolean(metadata: PaystackMetadata, key: string): boolean;
declare function createCheckoutMetadata(input: CheckoutMetadataInput): PaystackMetadata;
declare function createProrationMetadata(input: ProrationMetadataInput): PaystackMetadata;
declare function createRenewalMetadata(input: RenewalMetadataInput): PaystackMetadata;
//#endregion
//#region src/operations.d.ts
declare function syncPaystackProducts(ctx: GenericEndpointContext, options: AnyPaystackOptions): Promise<PaystackSyncResult>;
declare function syncPaystackPlans(ctx: GenericEndpointContext, options: AnyPaystackOptions): Promise<PaystackSyncResult>;
declare function chargeSubscriptionRenewal(ctx: GenericEndpointContext, options: AnyPaystackOptions, input: ChargeRecurringSubscriptionInput): Promise<ChargeRecurringSubscriptionResult>;
//#endregion
//#region src/limits.d.ts
declare function getOrganizationEntitlements(ctx: GenericEndpointContext, organizationId: string, options: AnyPaystackOptions): Promise<{
limits: Record<string, number>;
features: string[];
}>;
//#endregion
//#region src/reconciliation.d.ts
type PaystackReconciliationSource = "webhook" | "queue" | "admin" | "server" | "browser";
interface ReconcilePaystackTransactionInput {
reference: string;
source?: PaystackReconciliationSource;
referenceId?: string;
actor?: {
user: User;
session: Session;
};
throwOnError?: boolean;
}
interface PaystackReconciliationError {
code: string;
message: string;
status?: number;
}
interface PaystackReconciliationSummary {
transaction: {
found: boolean;
updated: boolean;
referenceId?: string;
previousStatus?: string;
status?: string;
};
subscription: {
found: boolean;
updated: boolean;
id?: string;
status?: string;
prorationApplied: boolean;
};
customer: {
saved: boolean;
referenceId?: string;
customerCode?: string;
model?: "user" | "organization";
};
product: {
synced: boolean;
name?: string;
};
}
interface ReconcilePaystackTransactionSuccess extends PaystackReconciliationSummary {
ok: true;
source: PaystackReconciliationSource;
status: string;
reference: string;
data: PaystackTransactionResponse;
error?: undefined;
}
interface ReconcilePaystackTransactionFailure extends PaystackReconciliationSummary {
ok: false;
source: PaystackReconciliationSource;
status: string;
reference: string;
data: PaystackTransactionResponse | null;
error: PaystackReconciliationError;
}
type ReconcilePaystackTransactionResult = ReconcilePaystackTransactionSuccess | ReconcilePaystackTransactionFailure;
declare function reconcilePaystackTransaction(ctx: GenericEndpointContext, options: AnyPaystackOptions, input: ReconcilePaystackTransactionInput): Promise<ReconcilePaystackTransactionResult>;
//#endregion
//#region src/index.d.ts
declare module "better-auth" {
interface BetterAuthPluginRegistry<AuthOptions, Options> {
paystack: {
creator: typeof paystack;
};
}
}
declare const INTERNAL_ERROR_CODES: ReturnType<typeof defineErrorCodes>;
/**
* Must stay a `type` rather than an `interface`.
*
* `BetterAuthPlugin["endpoints"]` is `{ [key: string]: Endpoint }`, and only object literal
* *type aliases* get TypeScript's implicit index signature — interfaces do not. Declaring
* this as `interface ... extends Record<string, Endpoint>` satisfies that constraint but
* gives the plugin a real string index signature. Better Auth merges every plugin's
* endpoints into `auth.api`, so that signature spreads across the whole API surface and,
* under `noUncheckedIndexedAccess`, makes *every* `auth.api.*` call possibly `undefined`.
*/
type PaystackPluginEndpoints = {
initializeTransaction: ReturnType<typeof initializeTransaction>;
verifyTransaction: ReturnType<typeof verifyTransaction>;
listSubscriptions: ReturnType<typeof listSubscriptions>;
paystackWebhook: ReturnType<typeof paystackWebhook>;
listTransactions: ReturnType<typeof listTransactions>;
getConfig: ReturnType<typeof getConfig>;
disableSubscription: ReturnType<typeof disablePaystackSubscription>;
enableSubscription: ReturnType<typeof enablePaystackSubscription>;
getSubscriptionManageLink: ReturnType<typeof getSubscriptionManageLink>;
subscriptionManageLink: ReturnType<typeof getSubscriptionManageLink>;
createSubscription: ReturnType<typeof createSubscription>;
upgradeSubscription: ReturnType<typeof upgradeSubscription>;
cancelSubscription: ReturnType<typeof cancelSubscription>;
restoreSubscription: ReturnType<typeof restoreSubscription>;
listProducts: ReturnType<typeof listProducts>;
listPlans: ReturnType<typeof listPlans>;
};
type PaystackHookHandler = (...args: unknown[]) => unknown;
interface PaystackPluginInitResult {
options: {
databaseHooks: Record<string, unknown> & {
organization: {
create: {
after: PaystackHookHandler;
};
};
};
};
}
type PaystackPluginInit = ((ctx: AuthContext) => PaystackPluginInitResult) & NonNullable<BetterAuthPlugin["init"]>;
type PaystackPluginInstance<O extends AnyPaystackOptions> = Omit<BetterAuthPlugin, "id" | "version" | "endpoints" | "schema" | "init" | "$ERROR_CODES" | "options"> & {
id: "paystack";
version: typeof PACKAGE_VERSION;
endpoints: PaystackPluginEndpoints;
schema: ReturnType<typeof getSchema>;
init: PaystackPluginInit;
$ERROR_CODES: typeof INTERNAL_ERROR_CODES;
options: NoInfer<O>;
};
declare const createPaystackPlugin: <TPaystackClient extends PaystackClientLike = PaystackClientLike, O extends PaystackOptions<TPaystackClient> = PaystackOptions<TPaystackClient>>(options: O) => PaystackPluginInstance<O>;
declare const paystack: typeof createPaystackPlugin;
type PaystackPlugin<TPaystackClient extends PaystackClientLike = PaystackClientLike, O extends PaystackOptions<TPaystackClient> = PaystackOptions<TPaystackClient>> = ReturnType<typeof paystack<TPaystackClient, O>>;
//#endregion
export { PaystackPlan as A, parsePaystackMetadata as C, PaystackClientLike as D, ChargeRecurringSubscriptionResult as E, Subscription as F, SubscriptionOptions as I, PaystackSyncResult as M, PaystackTransaction as N, PaystackInitializeResult as O, PaystackTransactionResponse as P, hasPaystackMetadata as S, AnyPaystackOptions as T, createProrationMetadata as _, PaystackReconciliationSummary as a, getMetadataNumber as b, ReconcilePaystackTransactionResult as c, getOrganizationEntitlements as d, chargeSubscriptionRenewal as f, createCheckoutMetadata as g, PaystackMetadata as h, PaystackReconciliationSource as i, PaystackProduct as j, PaystackOptions as k, ReconcilePaystackTransactionSuccess as l, syncPaystackProducts as m, paystack as n, ReconcilePaystackTransactionFailure as o, syncPaystackPlans as p, PaystackReconciliationError as r, ReconcilePaystackTransactionInput as s, PaystackPlugin as t, reconcilePaystackTransaction as u, createRenewalMetadata as v, stringifyPaystackMetadata as w, getMetadataString as x, getMetadataBoolean as y };
//# sourceMappingURL=index-ZqRgI9wR.d.mts.map