Transaction Status

Transaction Status

The transaction status endpoint allows you to check the current status of a payment using the transaction reference returned from the STK push initiation. This is useful for polling payment status or verifying payment completion.

Endpoint

GET /payments/status?reference=TRANSACTION_REFERENCE

Request Headers

Authorization: Bearer YOUR_API_KEY

Query Parameters

ParameterTypeRequiredDescription
referenceStringâś…The transaction reference returned from STK push initiation

Success Response

Pending Payment

{
  "success": true,
  "status": "success",
  "message": "Payment status: Payment is still being processed",
  "customerMessage": "Payment is still being processed",
  "data": {
    "response": {
      "Amount": 100,
      "ExternalReference": "order_123",
      "MerchantRequestID": "12345-67890-12345-67890",
      "MpesaReceiptNumber": "",
      "Phone": "254712345678",
      "ResultCode": 0,
      "ResultDesc": "Payment is still being processed",
      "Metadata": {
        "order_id": "12345",
        "customer_name": "John Doe"
      },
      "Status": "PENDING",
      "TransactionDate": "2024-01-15T10:30:00.000Z"
    },
    "status": false
  },
  "timestamp": "2024-01-15T10:30:00.000Z"
}

Successful Payment

{
  "success": true,
  "status": "success",
  "message": "Payment status: Payment completed successfully",
  "customerMessage": "Payment completed successfully",
  "data": {
    "response": {
      "Amount": 100,
      "ExternalReference": "order_123",
      "MerchantRequestID": "12345-67890-12345-67890",
      "MpesaReceiptNumber": "NEF61H8J60",
      "Phone": "254712345678",
      "ResultCode": 0,
      "ResultDesc": "Payment completed successfully",
      "Metadata": {
        "order_id": "12345",
        "customer_name": "John Doe"
      },
      "Status": "SUCCESS",
      "TransactionDate": "2024-01-15T10:35:00.000Z"
    },
    "status": true
  },
  "timestamp": "2024-01-15T10:35:00.000Z"
}

Failed Payment

{
  "success": true,
  "status": "success",
  "message": "Payment status: Payment failed",
  "customerMessage": "Payment failed",
  "data": {
    "response": {
      "Amount": 100,
      "ExternalReference": "order_123",
      "MerchantRequestID": "12345-67890-12345-67890",
      "MpesaReceiptNumber": "",
      "Phone": "254712345678",
      "ResultCode": 1,
      "ResultDesc": "The initiator information is invalid",
      "Metadata": {
        "order_id": "12345",
        "customer_name": "John Doe"
      },
      "Status": "FAILED",
      "TransactionDate": "2024-01-15T10:32:00.000Z"
    },
    "status": false
  },
  "timestamp": "2024-01-15T10:32:00.000Z"
}

Response Fields

FieldTypeDescription
AmountNumberPayment amount in Kenyan Shillings
ExternalReferenceStringYour reference ID for tracking
MerchantRequestIDStringInternal merchant request identifier
MpesaReceiptNumberStringReceipt number (empty for pending/failed payments)
PhoneStringCustomer's phone number
ResultCodeNumberPayment result code (0 = success, >0 = error)
ResultDescStringHuman-readable result description
MetadataObjectAdditional data stored with the payment
StatusStringPayment status: PENDING, SUCCESS, or FAILED
TransactionDateStringISO timestamp of last status update
statusBooleantrue for successful payments, false for failed/pending

Payment States

PENDING

  • Payment has been initiated
  • Customer has not yet entered their PIN
  • No receipt number available
  • status field is false

SUCCESS

  • Payment completed successfully
  • Customer has entered PIN and payment processed
  • Receipt number is available
  • status field is true

FAILED

  • Payment failed for various reasons
  • Customer cancelled, insufficient funds, or system error
  • No receipt number available
  • status field is false

Error Responses

Transaction Not Found

{
  "success": false,
  "status": "error",
  "message": "Transaction not found",
  "customerMessage": "Transaction not found",
  "error": {
    "code": "NOT_FOUND",
    "field": "reference",
    "location": "query",
    "value": "invalid_reference",
    "expected": "Valid transaction reference"
  },
  "timestamp": "2024-01-15T10:30:00.000Z"
}

Invalid Reference Format

{
  "success": false,
  "status": "error",
  "message": "Invalid reference format",
  "customerMessage": "Please provide a valid transaction reference",
  "error": {
    "code": "VALIDATION_ERROR",
    "field": "reference",
    "location": "query",
    "value": "",
    "expected": "Non-empty transaction reference"
  },
  "timestamp": "2024-01-15T10:30:00.000Z"
}

Code Examples

JavaScript/Node.js

const checkPaymentStatus = async (transactionReference) => {
  try {
    const response = await fetch(
      `https://lipia-api.kreativelabske.com/api/v2/payments/status?reference=${transactionReference}`,
      {
        method: 'GET',
        headers: {
          'Authorization': `Bearer ${process.env.LIPIA_API_KEY}`
        }
      }
    );
 
    const result = await response.json();
    
    if (result.success) {
      const paymentData = result.data.response;
      console.log('Payment Status:', paymentData.Status);
      console.log('Amount:', paymentData.Amount);
      console.log('Receipt Number:', paymentData.MpesaReceiptNumber);
      return paymentData;
    } else {
      console.error('Status check failed:', result.message);
      throw new Error(result.customerMessage);
    }
  } catch (error) {
    console.error('Error checking payment status:', error);
    throw error;
  }
};
 
// Usage
const transactionRef = '64f1a2b3c4d5e6f7g8h9i0j1';
checkPaymentStatus(transactionRef);

Python

import requests
import os
 
def check_payment_status(transaction_reference):
    api_key = os.getenv('LIPIA_API_KEY')
    base_url = os.getenv('LIPIA_BASE_URL')
    
    headers = {
        'Authorization': f'Bearer {api_key}'
    }
    
    try:
        response = requests.get(
            f'{base_url}/payments/status',
            headers=headers,
            params={'reference': transaction_reference}
        )
        
        result = response.json()
        
        if result['success']:
            payment_data = result['data']['response']
            print(f"Payment Status: {payment_data['Status']}")
            print(f"Amount: {payment_data['Amount']}")
            print(f"Receipt Number: {payment_data['MpesaReceiptNumber']}")
            return payment_data
        else:
            print(f"Status check failed: {result['message']}")
            raise Exception(result['customerMessage'])
            
    except requests.exceptions.RequestException as e:
        print(f"Error checking payment status: {e}")
        raise
 
# Usage
transaction_ref = '64f1a2b3c4d5e6f7g8h9i0j1'
check_payment_status(transaction_ref)

PHP

<?php
function checkPaymentStatus($transactionReference) {
    $apiKey = $_ENV['LIPIA_API_KEY'];
    $baseUrl = $_ENV['LIPIA_BASE_URL'];
    
    $headers = [
        'Authorization: Bearer ' . $apiKey
    ];
    
    $url = $baseUrl . '/payments/status?reference=' . urlencode($transactionReference);
    
    $ch = curl_init();
    curl_setopt($ch, CURLOPT_URL, $url);
    curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    
    $response = curl_exec($ch);
    $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
    curl_close($ch);
    
    if ($httpCode === 200) {
        $result = json_decode($response, true);
        
        if ($result['success']) {
            $paymentData = $result['data']['response'];
            echo "Payment Status: " . $paymentData['Status'] . "\n";
            echo "Amount: " . $paymentData['Amount'] . "\n";
            echo "Receipt Number: " . $paymentData['MpesaReceiptNumber'] . "\n";
            return $paymentData;
        } else {
            echo "Status check failed: " . $result['message'] . "\n";
            throw new Exception($result['customerMessage']);
        }
    } else {
        throw new Exception("HTTP Error: " . $httpCode);
    }
}
 
// Usage
$transactionRef = '64f1a2b3c4d5e6f7g8h9i0j1';
checkPaymentStatus($transactionRef);
?>

Polling Strategy(optional)

Polling is a technique where your application repeatedly checks the transaction status at regular intervals using the transaction reference. This allows you to provide users with real-time feedback on the progress of their payment—whether it is still pending, has succeeded, or has failed.

By implementing polling, you can keep your users informed about their payment status directly within your app or website, without waiting for a callback or manual refresh.

Simple Polling

const pollPaymentStatus = async (transactionReference, maxAttempts = 30) => {
  for (let i = 0; i < maxAttempts; i++) {
    try {
      const status = await checkPaymentStatus(transactionReference);
      
      if (status.Status === 'SUCCESS') {
        console.log('Payment successful!');
        return status;
      } else if (status.Status === 'FAILED') {
        console.log('Payment failed:', status.ResultDesc);
        throw new Error('Payment failed');
      }
      
      // Wait 5 seconds before next check
      await new Promise(resolve => setTimeout(resolve, 5000));
    } catch (error) {
      console.error('Error polling status:', error);
      throw error;
    }
  }
  
  throw new Error('Payment timeout');
};

Continue to Handling Callback to learn about callback webhook notifications.