Back to SDKs

Lipafy JavaScript / TypeScript Client

A type-safe client for interacting with the Lipafy Payment API. Works in Node.js, Next.js, and modern browsers.

Installation

Install via npm (Recommended):

npm install lipafy-sdk

Alternatively, you can copy the source code below into a file (e.g., `lib/lipafy.ts`) if you prefer zero dependencies.

// lipafy-client.ts

export type LipafyConfig = {
    apiKey: string; // Your Secret Key (sk_...) or Publishable Key (pk_...)
    baseUrl?: string;
};

export type PaymentRequest = {
    amount: number;
    phone: number | string;
    currency?: "KES" | "USD";
    paymentId?: string; // Optional custom reference
};

export type SubscriptionRequest = {
    amount: number;
    phone: number | string;
    planName: string;
    cycle: "weekly" | "monthly" | "yearly";
    currency?: "KES";
};

export class Lipafy {
    private apiKey: string;
    private baseUrl: string;

    constructor(config: LipafyConfig | string) {
        if (typeof config === "string") {
            this.apiKey = config;
            this.baseUrl = "https://lipafy.xyz/api";
        } else {
            this.apiKey = config.apiKey;
            this.baseUrl = config.baseUrl || "https://lipafy.xyz/api";
        }
    }

    private async request(endpoint: string, method: "GET" | "POST", body?: any) {
        const headers: Record<string, string> = {
            "Content-Type": "application/json",
            "Authorization": `Bearer ${this.apiKey}` // Or Basic auth depending on your backend setup
        };
        
        // Handle basic auth if needed, but for now assuming Bearer or simply passing key
        // Note: Our API docs say use -u sk_live_...: which is Basic Auth with username as key
        // So let's adjust to Basic Auth header if it starts with sk_
        if (this.apiKey.startsWith("sk_")) {
             headers["Authorization"] = `Basic ${btoa(this.apiKey + ':')}`;
        }

        const response = await fetch(`${this.baseUrl}${endpoint}`, {
            method,
            headers,
            body: body ? JSON.stringify(body) : undefined,
        });

        if (!response.ok) {
            const error = await response.json().catch(() => ({ message: "Unknown error" }));
            throw new Error(error.message || `Request failed with status ${response.status}`);
        }

        return response.json();
    }

    public payments = {
        /**
         * Initiate an STK Push (One-time payment)
         */
        create: async (data: PaymentRequest) => {
            return this.request("/mpesa/stk-push", "POST", {
                ...data,
                type: "one_time"
            });
        },

        /**
         * Get payment status
         */
        get: async (paymentId: string) => {
            return this.request(`/payments/${paymentId}`, "GET");
        }
    };

    public subscriptions = {
        /**
         * Create a new subscription (First payment + Autosave)
         */
        create: async (data: SubscriptionRequest) => {
             return this.request("/mpesa/stk-push", "POST", {
                ...data,
                type: "subscription"
            });
        },
        
        /**
         * Cancel a subscription
         */
        cancel: async (subscriptionId: string) => {
             return this.request(`/subscriptions/${subscriptionId}/cancel`, "POST");
        }
    };
}