Code Examples

Real-world examples to help you get started

Basic Payment Charge

Initiate a simple M-Pesa payment charge:

import { pesastream } from '@/lib/pesastream';

async function processPayment(phone: string, amount: number) {
  try {
    const payment = await pesastream.charge({
      amount: amount,
      currency: 'KES',
      phone: phone,
      description: 'Order #123'
    });

    console.log('Payment initiated:', payment.transactionId);
    return payment;
  } catch (error) {
    console.error('Payment failed:', error);
    throw error;
  }
}

React Payment Component

Build a reusable payment component:

'use client';

import { useState } from 'react';
import { Loader } from 'lucide-react';

export function PaymentButton({ amount }: { amount: number }) {
  const [phone, setPhone] = useState('');
  const [loading, setLoading] = useState(false);
  const [error, setError] = useState('');
  const [success, setSuccess] = useState('');

  const handlePayment = async () => {
    setLoading(true);
    setError('');
    setSuccess('');

    try {
      const response = await fetch('/api/payments', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ phone, amount })
      });

      if (!response.ok) throw new Error('Payment failed');
      
      const data = await response.json();
      setSuccess(`Payment processing: ${data.transactionId}`);
    } catch (err) {
      setError(err instanceof Error ? err.message : 'Payment error');
    } finally {
      setLoading(false);
    }
  };

  return (
    <div className="space-y-4">
      <input
        type="tel"
        placeholder="+254712345678"
        value={phone}
        onChange={(e) => setPhone(e.target.value)}
        className="w-full px-4 py-2 border rounded-lg"
      />
      <button
        onClick={handlePayment}
        disabled={loading}
        className="w-full bg-blue-600 text-white py-2 rounded-lg hover:bg-blue-700 disabled:opacity-50"
      >
        {loading ? <Loader className="animate-spin" /> : `Pay KES ${amount}`}
      </button>
      {error && <p className="text-red-600">{error}</p>}
      {success && <p className="text-green-600">{success}</p>}
    </div>
  );
}

API Route Handler

Create an API endpoint to handle payments:

// app/api/payments/route.ts
import { pesastream } from '@/lib/pesastream';
import { NextRequest, NextResponse } from 'next/server';

export async function POST(request: NextRequest) {
  const { phone, amount } = await request.json();

  if (!phone || !amount) {
    return NextResponse.json(
      { error: 'Phone and amount required' },
      { status: 400 }
    );
  }

  try {
    const payment = await pesastream.charge({
      amount,
      currency: 'KES',
      phone,
      description: `Payment for Order`
    });

    return NextResponse.json(payment);
  } catch (error) {
    return NextResponse.json(
      { error: 'Payment processing failed' },
      { status: 500 }
    );
  }
}

Send Payout

Send money to a beneficiary:

async function sendPayout(phone: string, amount: number) {
  try {
    const payout = await pesastream.payout({
      amount: amount,
      phone: phone,
      reference: `salary-2024-${Date.now()}`
    });

    console.log('Payout sent:', payout.payoutId);
    return payout;
  } catch (error) {
    console.error('Payout failed:', error);
    throw error;
  }
}

Query Transaction Status

Check the status of a transaction:

async function getTransactionStatus(transactionId: string) {
  try {
    const transaction = await pesastream.getTransaction(transactionId);
    
    console.log('Status:', transaction.status);
    console.log('Amount:', transaction.amount);
    console.log('Timestamp:', transaction.createdAt);
    
    return transaction;
  } catch (error) {
    console.error('Failed to fetch transaction:', error);
    throw error;
  }
}