Skip to main content

Basic Express Payment

The most common use case is making a simple express payment. Here’s how to do it:
import { Moflay } from "@moflay/sdk";

const moflay = new Moflay({
  token: process.env.MOFLAY_API_KEY,
});

async function makePayment() {
  try {
    const result = await moflay.express.pay({
      phoneNumber: "254712345678",
      customerName: "John Doe",
      customerEmail: "[email protected]",
      amount: 100,
      description: "Payment for services",
      accountReference: "moflay",
    });

    console.log("Payment initiated:", result);
    return result;
  } catch (error) {
    console.error("Payment failed:", error);
    throw error;
  }
}

Express Payment with Customer Details

For better customer tracking and support, include detailed customer information:
import { Moflay } from "@moflay/sdk";

const moflay = new Moflay({
  token: process.env.MOFLAY_API_KEY,
});

async function makeDetailedPayment() {
  const result = await moflay.express.pay({
    phoneNumber: "254712345678",
    customerName: "John Doe",
    customerEmail: "[email protected]",
    customerDescription: "VIP Customer",
    customerMetadata: {
      "user_id": "12345",
      "subscription_type": "premium",
      "last_purchase": "2024-01-15",
    },
    amount: 2500,
    description: "Premium subscription renewal",
    accountReference: "moflay",
    metadata: {
      "order_id": "ORD-2024-001",
      "product_type": "subscription",
      "discount_applied": 10,
    },
  });

  return result;
}

E-commerce Payment Example

Here’s a complete example for an e-commerce checkout process:
import { Moflay } from "@moflay/sdk";

const moflay = new Moflay({
  token: process.env.MOFLAY_API_KEY,
});

interface CartItem {
  id: string;
  name: string;
  price: number;
  quantity: number;
}

interface Customer {
  phoneNumber: string;
  name: string;
  email: string;
}

async function processEcommercePayment(
  customer: Customer,
  items: CartItem[],
  orderId: string
) {
  const totalAmount = items.reduce(
    (sum, item) => sum + (item.price * item.quantity),
    0
  );

  const itemDescriptions = items
    .map(item => `${item.name} x${item.quantity}`)
    .join(", ");

  try {
    const payment = await moflay.express.pay({
      phoneNumber: customer.phoneNumber,
      customerName: customer.name,
      customerEmail: customer.email,
      customerDescription: "E-commerce Customer",
      customerMetadata: {
        "order_id": orderId,
        "total_items": items.length,
        "cart_value": totalAmount,
      },
      amount: totalAmount,
      description: `Order ${orderId}: ${itemDescriptions}`,
      accountReference: "moflay",
      metadata: {
        "order_id": orderId,
        "items": JSON.stringify(items),
        "payment_method": "mpesa_express",
        "checkout_session": Date.now().toString(),
      },
    });

    console.log(`Payment initiated for order ${orderId}:`, payment);
    return payment;
  } catch (error) {
    console.error(`Payment failed for order ${orderId}:`, error);
    throw error;
  }
}

// Usage example
const customer = {
  phoneNumber: "254712345678",
  name: "Jane Smith",
  email: "[email protected]",
};

const cartItems = [
  { id: "1", name: "Laptop", price: 50000, quantity: 1 },
  { id: "2", name: "Mouse", price: 2000, quantity: 2 },
];

processEcommercePayment(customer, cartItems, "ORD-2024-001");

Subscription Payment Example

For recurring subscription payments:
import { Moflay } from "@moflay/sdk";

const moflay = new Moflay({
  token: process.env.MOFLAY_API_KEY,
});

async function processSubscriptionPayment(
  customerPhone: string,
  customerName: string,
  customerEmail: string,
  subscriptionPlan: string,
  amount: number,
  billingCycle: string
) {
  const result = await moflay.express.pay({
    phoneNumber: customerPhone,
    customerName: customerName,
    customerEmail: customerEmail,
    customerDescription: "Subscription Customer",
    customerMetadata: {
      "subscription_plan": subscriptionPlan,
      "billing_cycle": billingCycle,
      "customer_type": "subscriber",
    },
    amount: amount,
    description: `${subscriptionPlan} subscription - ${billingCycle}`,
    accountReference: "moflay",
    metadata: {
      "subscription_id": `SUB-${Date.now()}`,
      "plan_name": subscriptionPlan,
      "billing_cycle": billingCycle,
      "renewal_date": new Date(Date.now() + 30 * 24 * 60 * 60 * 1000).toISOString(),
    },
  });

  return result;
}

// Usage
processSubscriptionPayment(
  "254712345678",
  "John Doe",
  "[email protected]",
  "Premium Plan",
  5000,
  "monthly"
);

Error Handling

Always handle errors appropriately when making payments:
import { Moflay } from "@moflay/sdk";
import * as errors from "@moflay/sdk/models/errors";

const moflay = new Moflay({
  token: process.env.MOFLAY_API_KEY,
});

async function makePaymentWithErrorHandling() {
  try {
    const result = await moflay.express.pay({
      phoneNumber: "254712345678",
      customerName: "John Doe",
      customerEmail: "[email protected]",
      amount: 100,
      description: "Test payment",
      accountReference: "moflay",
    });

    return result;
  } catch (error) {
    if (error instanceof errors.MissingApiKeyError) {
      console.error("API key is missing");
    } else if (error instanceof errors.InvalidApiKeyError) {
      console.error("Invalid API key");
    } else if (error instanceof errors.ValidationError) {
      console.error("Validation error:", error.data$);
    } else if (error instanceof errors.RateLimitExceededError) {
      console.error("Rate limit exceeded, please try again later");
    } else if (error instanceof errors.MoflayError) {
      console.error("Payment error:", error.message);
    } else {
      console.error("Unexpected error:", error);
    }
    
    throw error;
  }
}

Webhook Integration

After initiating a payment, you’ll typically want to handle the webhook response:
import { Moflay } from "@moflay/sdk";

const moflay = new Moflay({
  token: process.env.MOFLAY_API_KEY,
});

// In your webhook handler
export async function handlePaymentWebhook(webhookData: any) {
  const { transactionId, status, amount, phoneNumber } = webhookData;
  
  if (status === "completed") {
    // Update your database
    await updateOrderStatus(transactionId, "paid");
    await sendConfirmationEmail(phoneNumber, amount);
    console.log(`Payment completed for transaction ${transactionId}`);
  } else if (status === "failed") {
    // Handle failed payment
    await updateOrderStatus(transactionId, "failed");
    await sendFailureNotification(phoneNumber, amount);
    console.log(`Payment failed for transaction ${transactionId}`);
  }
}