Singularity Payments LogoSingularity Payments

Advanced Configuration

Detailed configuration guide for B2C, B2B, reversals, and advanced M-Pesa operations

Overview

This guide covers advanced M-Pesa operations including B2C payments, B2B transfers, transaction reversals, status queries, and account balance checks. These operations require additional credentials beyond the basic STK Push configuration.

Required Credentials

Complete Configuration Interface

interface MpesaConfig {
  consumerKey: string;
  consumerSecret: string;
  passkey: string;
  shortcode: string;
  environment: "sandbox" | "production";
  callbackUrl?: string;
  initiatorName: string;
  securityCredential: string;
  resultUrl: string;
  timeoutUrl: string;
}

Full SDK Initialization

import { MpesaClient } from "@singularity-payments/nextjs";

const client = new MpesaClient({
  consumerKey: process.env.MPESA_CONSUMER_KEY,
  consumerSecret: process.env.MPESA_CONSUMER_SECRET,
  passkey: process.env.MPESA_PASSKEY,
  shortcode: process.env.MPESA_SHORTCODE,
  environment: "sandbox",
  callbackUrl: process.env.MPESA_CALLBACK_URL,
  initiatorName: process.env.MPESA_INITIATOR_NAME,
  securityCredential: process.env.MPESA_SECURITY_CREDENTIAL,
  resultUrl: process.env.MPESA_RESULT_URL,
  timeoutUrl: process.env.MPESA_TIMEOUT_URL,
});

Sandbox Test Credentials

STK Push Configuration

For STK Push operations, use shortcode 174379:

MPESA_CONSUMER_KEY=your_sandbox_consumer_key
MPESA_CONSUMER_SECRET=your_sandbox_consumer_secret
MPESA_PASSKEY=bfb279f9aa9bdbcf158e97dd71a467cd2e0c893059b10f78e6b72ada1ed2c919
MPESA_SHORTCODE=174379
MPESA_ENVIRONMENT=sandbox
MPESA_CALLBACK_URL=https://your-ngrok-url.ngrok.io/api/mpesa/callback

B2C, B2B, and Advanced Operations Configuration

For B2C, B2B, reversals, transaction status, and account balance operations, use shortcode 600998:

MPESA_CONSUMER_KEY=your_sandbox_consumer_key
MPESA_CONSUMER_SECRET=your_sandbox_consumer_secret
MPESA_SHORTCODE=600998
MPESA_ENVIRONMENT=sandbox
MPESA_INITIATOR_NAME=testapi
MPESA_RESULT_URL=https://your-ngrok-url.ngrok.io/api/mpesa/result
MPESA_TIMEOUT_URL=https://your-ngrok-url.ngrok.io/api/mpesa/timeout

Initiator Password: Safaricom123!!

Complete Environment Variables

MPESA_CONSUMER_KEY=your_sandbox_consumer_key
MPESA_CONSUMER_SECRET=your_sandbox_consumer_secret
MPESA_PASSKEY=bfb279f9aa9bdbcf158e97dd71a467cd2e0c893059b10f78e6b72ada1ed2c919
MPESA_SHORTCODE=174379
MPESA_ENVIRONMENT=sandbox
MPESA_CALLBACK_URL=https://your-ngrok-url.ngrok.io/api/mpesa/callback
MPESA_INITIATOR_NAME=testapi
MPESA_SECURITY_CREDENTIAL=your_generated_security_credential
MPESA_RESULT_URL=https://your-ngrok-url.ngrok.io/api/mpesa/result
MPESA_TIMEOUT_URL=https://your-ngrok-url.ngrok.io/api/mpesa/timeout

Generating Security Credential

The security credential is an encrypted version of your initiator password. Here's how to generate it:

Step 1: Access Credential Generator

  1. Go to Safaricom Developer Portal Test Credentials
  2. Log in to your account

Step 2: Generate Credential

  1. In the Initiator Security Password field, enter: Safaricom123!!
  2. Select Sandbox from the environment dropdown
  3. Click Generate Security Credential
  4. Copy the generated credential

Step 3: Add to Environment Variables

MPESA_SECURITY_CREDENTIAL=<paste_generated_credential_here>

Production Security Credential

For production:

  1. Use your production initiator password provided by Safaricom
  2. Select Production environment when generating
  3. Store securely in environment variables

Configuration Fields Explained

Consumer Key & Consumer Secret

OAuth credentials used to authenticate your application with the M-Pesa API.

Sandbox: Generated when you create an app on the developer portal

Production: Provided by Safaricom after going live

Security: Never commit to version control. Store in environment variables and rotate regularly.

MPESA_CONSUMER_KEY=your_consumer_key
MPESA_CONSUMER_SECRET=your_consumer_secret

Passkey

A unique key used to generate passwords for STK Push requests.

Sandbox Passkey:

bfb279f9aa9bdbcf158e97dd71a467cd2e0c893059b10f78e6b72ada1ed2c919

Production Passkey: Provided by Safaricom when your app goes live

The SDK automatically generates a password using:

Base64(Shortcode + Passkey + Timestamp)
MPESA_PASSKEY=bfb279f9aa9bdbcf158e97dd71a467cd2e0c893059b10f78e6b72ada1ed2c919

Shortcode

Your M-Pesa business number used for transactions.

Sandbox Shortcodes:

  • 174379: For STK Push operations
  • 600998: For B2C, B2B, reversals, transaction status, and account balance operations

Production Shortcode: Your actual business number provided by Safaricom

MPESA_SHORTCODE=174379
MPESA_SHORTCODE=600998

Environment

Specifies which M-Pesa environment to use.

Sandbox (Development/Testing):

  • Base URL: https://sandbox.safaricom.co.ke
  • Uses test credentials
  • No real money transactions
  • Transactions refunded automatically

Production (Live):

  • Base URL: https://api.safaricom.co.ke
  • Uses production credentials
  • Real money transactions
  • Requires Safaricom approval
environment: "sandbox";
environment: "production";

Callback URL

The URL where M-Pesa sends transaction notifications after processing STK Push requests.

Requirements:

  • Must be publicly accessible
  • Must use HTTPS in production
  • Must respond with status 200
  • Must respond within 30 seconds

Development: Use ngrok, Cloudflare Tunnel, or LocalTunnel

MPESA_CALLBACK_URL=https://abc123.ngrok.io/api/mpesa/callback
MPESA_CALLBACK_URL=https://yourdomain.com/api/mpesa/callback

Initiator Name

The username for initiating B2C, B2B, reversals, and other organizational transactions.

When Required:

  • B2C (Business to Customer)
  • B2B (Business to Business)
  • Transaction Reversal
  • Transaction Status Query
  • Account Balance Query

Sandbox Initiator: testapi

Production Initiator: Provided by Safaricom during onboarding

MPESA_INITIATOR_NAME=testapi

Security Credential

An encrypted password used to authenticate organizational transactions.

Generated using the Safaricom Developer Portal credential generator with your initiator password.

Sandbox: Generate using password Safaricom123!!

Production: Generate using your production initiator password

MPESA_SECURITY_CREDENTIAL=<paste_generated_credential_here>

Result URL

URL where M-Pesa sends the final result of organizational transactions. In the SDK the result url is usually passed when initiating transactions, but we set it globally if you are not doing multiple types of transactions eg( B2C and Reversals) and as a fallback.

When Required:

  • B2C payments
  • B2B payments
  • Transaction reversals
  • Transaction status queries
  • Account balance queries

Requirements:

  • Must be publicly accessible
  • Must use HTTPS in production
  • Should return status 200
MPESA_RESULT_URL=https://yourdomain.com/api/mpesa/result

Timeout URL

URL where M-Pesa sends a notification if a transaction times out.

When Called:

  • Transaction takes too long to process
  • No response from customer
  • System timeout (usually after 30-60 seconds)
MPESA_TIMEOUT_URL=https://yourdomain.com/api/mpesa/timeout

Advanced Client Options

Complete Configuration with Options

interface MpesaClientOptions {
  callbackOptions?: {
    onSuccess?: (data: ParsedCallbackData) => void | Promise<void>;
    onFailure?: (data: ParsedCallbackData) => void | Promise<void>;
    validateIp?: boolean;
    allowedIps?: string[];
    isDuplicate?: (checkoutRequestId: string) => boolean | Promise<boolean>;
  };

  retryOptions?: {
    maxRetries?: number;
    initialDelayMs?: number;
    maxDelayMs?: number;
    backoffMultiplier?: number;
  };

  rateLimitOptions?: {
    enabled?: boolean;
    maxRequests?: number;
    windowMs?: number;
    redis?: RedisLike;
  };

  requestTimeout?: number;
}

Full Implementation Example

import { MpesaClient } from "@singularity-payments/core";

const client = new MpesaClient(
  {
    consumerKey: process.env.MPESA_CONSUMER_KEY,
    consumerSecret: process.env.MPESA_CONSUMER_SECRET,
    passkey: process.env.MPESA_PASSKEY,
    shortcode: process.env.MPESA_SHORTCODE,
    environment: "sandbox",
    callbackUrl: process.env.MPESA_CALLBACK_URL,
    initiatorName: process.env.MPESA_INITIATOR_NAME,
    securityCredential: process.env.MPESA_SECURITY_CREDENTIAL,
    resultUrl: process.env.MPESA_RESULT_URL,
    timeoutUrl: process.env.MPESA_TIMEOUT_URL,
  },
  {
    callbackOptions: {
      onSuccess: async (data) => {
        console.log("Payment successful:", data);
      },
      onFailure: async (data) => {
        console.log("Payment failed:", data);
      },
      validateIp: true,
      isDuplicate: async (checkoutRequestId) => {
        return false;
      },
    },

    retryOptions: {
      maxRetries: 3,
      initialDelayMs: 1000,
      maxDelayMs: 10000,
      backoffMultiplier: 2,
    },

    rateLimitOptions: {
      enabled: true,
      maxRequests: 100,
      windowMs: 60000,
    },

    requestTimeout: 30000,
  },
);

Testing Different Operations

STK Push

await client.stkPush({
  amount: 1,
  phoneNumber: "254712345678",
  accountReference: "TEST-001",
  transactionDesc: "Test payment",
});

B2C Payment

await client.b2c({
  amount: 100,
  phoneNumber: "254712345678",
  commandID: "BusinessPayment",
  remarks: "Salary payment",
  occasion: "Monthly",
});

B2B Payment

await client.b2b({
  amount: 1000,
  receiverShortcode: "600000",
  commandID: "BusinessPayBill",
  remarks: "Payment for goods",
  accountReference: "INV-001",
});

Transaction Reversal

await client.reversal({
  transactionID: "NEF61H8J60",
  amount: 100,
  remarks: "Reversal request",
  occasion: "Customer refund",
});

Transaction Status

await client.transactionStatus({
  transactionID: "NEF61H8J60",
  remarks: "Status check",
  occasion: "Verification",
});

Account Balance

await client.accountBalance({
  remarks: "Balance check",
});

Moving to Production

Production Checklist

  • Applied for production access on Safaricom Developer Portal
  • Completed all compliance requirements
  • Received production credentials
  • Generated production security credential
  • Updated all environment variables
  • Changed environment to production
  • Updated callback URLs to production domains
  • Tested with real phone numbers
  • Implemented proper error handling
  • Set up monitoring and logging
  • Configured rate limiting
  • Implemented duplicate prevention
  • Secured all API keys

Production Configuration

MPESA_CONSUMER_KEY=prod_consumer_key_here
MPESA_CONSUMER_SECRET=prod_consumer_secret_here
MPESA_PASSKEY=prod_passkey_from_safaricom
MPESA_SHORTCODE=your_actual_business_number
MPESA_ENVIRONMENT=production
MPESA_CALLBACK_URL=https://api.yourdomain.com/api/mpesa/callback
MPESA_INITIATOR_NAME=your_production_initiator
MPESA_SECURITY_CREDENTIAL=prod_security_credential_here
MPESA_RESULT_URL=https://api.yourdomain.com/api/mpesa/result
MPESA_TIMEOUT_URL=https://api.yourdomain.com/api/mpesa/timeout

Security Best Practices

Environment Variables

Never commit .env to version control:

.env
.env.local
.env.production

Multiple Environments

MPESA_ENVIRONMENT=sandbox

MPESA_ENVIRONMENT=production

Credential Rotation

  • Change consumer keys every 90 days
  • Update security credentials quarterly

Secret Management Services

  • AWS Secrets Manager
  • Google Cloud Secret Manager
  • Azure Key Vault
  • Vercel Environment Variables
  • Railway Variables

Common Configuration Issues

401 Unauthorized

Cause: Invalid consumer key or consumer secret

Solution:

  • Verify credentials from developer portal
  • Ensure no extra spaces or quotes in .env
  • Check if credentials are for correct environment
  • Regenerate credentials if needed

400 Bad Request - Invalid Shortcode

Cause: Using wrong shortcode for operation

Solution:

  • STK Push: Use 174379
  • B2C/B2B/Advanced: Use 600998
  • Production: Use your actual business shortcode
  • Verify shortcode matches your app configuration

Callback Not Received

Cause: Callback URL not accessible

Solution:

  • Use ngrok or similar for local development
  • Ensure URL is publicly accessible
  • Check firewall settings
  • Verify route is correctly set up
  • Return status 200 from callback endpoint

Phone Number Format Error

Cause: Incorrect phone number format

Solution:

  • Use format: 254XXXXXXXXX (12 digits)
  • Start with country code 254
  • Remove spaces, dashes, plus signs
  • Example: 254712345678

Invalid Security Credential

Cause: Incorrectly generated or expired security credential

Solution:

  • Regenerate using Safaricom Developer Portal
  • Ensure using correct initiator password
  • Select correct environment when generating
  • Copy entire credential without modifications

Next Steps

Edit on GitHub

On this page