Initiate STK Push
The STK Push endpoint allows you to initiate mobile payments by sending a payment request directly to your customer's phone. This is the primary method for collecting payments through the Lipia Online API.
Endpoint
POST /payments/stk-pushRequest Headers
Authorization: Bearer YOUR_API_KEY
Content-Type: application/jsonRequest Body
{
"phone_number": "0712345678",
"amount": 100,
"external_reference": "order_123",
"callback_url": "https://your-domain.com/callback",
"metadata": {
"order_id": "12345",
"customer_name": "John Doe"
}
}Request Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
phone_number | String | ✅ | Customer's phone number in (e.g., 0712345678 , 0112345678, 254712345678) |
amount | Number | ✅ | Payment amount in Kenyan Shillings (minimum 1) |
external_reference | String/Number | ❌ | Your reference ID for tracking this payment |
callback_url | String | ❌ | URL to receive payment confirmation updates via callback webhook |
metadata | Object | ❌ | Optional additional data to store with the payment (key-value pairs) |
Phone Number Format
Phone numbers must be a valid kenyan safaricom number:
- ✅
2547... , 2541... , +2547... , +2541... , 07... ,01...(correct)
Amount Validation
- Must be a positive integer
Success Response
{
"success": true,
"status": "success",
"message": "STK push initiated successfully",
"customerMessage": "STK push initiated successfully",
"data": {
"TransactionReference": "64f1a2b3c4d5e6f7g8h9i0j1",
"ResponseCode": 0,
"ResponseDescription": "Success. Request accepted for processing"
},
"timestamp": "2024-01-15T10:30:00.000Z"
}Response Fields
| Field | Type | Description |
|---|---|---|
TransactionReference | String | Unique identifier for tracking this payment |
ResponseCode | Number | M-Pesa response code (0 = success) |
ResponseDescription | String | Human-readable response description |
Error Responses
Validation Error
{
"success": false,
"status": "error",
"message": "Validation failed",
"customerMessage": "Please check your input and try again",
"error": {
"code": "VALIDATION_ERROR",
"field": "phone_number",
"location": "body",
"value": "0712345678",
"expected": "valid safaricom kenyan number"
},
"timestamp": "2024-01-15T10:30:00.000Z"
}Other errors
{
"success": false,
"status": "error",
"message": "error message",
"customerMessage": "the error message for display",
"error": {
"code": "ERROR_CODE",
... OTHER DEBUG ERROR DETAILS
},
"timestamp": "2024-01-15T10:30:00.000Z"
}Code Examples
JavaScript/Node.js
const initiatePayment = async (paymentData) => {
try {
const response = await fetch('https://lipia-api.kreativelabske.com/api/v2/payments/stk-push', {
method: 'POST',
headers: {
'Authorization': `Bearer ${process.env.LIPIA_API_KEY}`,
'Content-Type': 'application/json'
},
body: JSON.stringify(paymentData)
});
const result = await response.json();
if (result.success) {
console.log('Payment initiated:', result.data.TransactionReference);
return result.data;
} else {
console.error('Payment failed:', result.message);
throw new Error(result.customerMessage);
}
} catch (error) {
console.error('Error initiating payment:', error);
throw error;
}
};
// Usage
const paymentData = {
phone_number: '254712345678',
amount: 100,
external_reference: 'order_123', //optional
callback_url: 'https://your-domain.com/callback', //optional
metadata: {
order_id: '12345',
customer_name: 'John Doe'
} //optional
};
initiatePayment(paymentData);Python
import requests
import os
def initiate_payment(payment_data):
api_key = os.getenv('LIPIA_API_KEY')
base_url = os.getenv('LIPIA_BASE_URL')
headers = {
'Authorization': f'Bearer {api_key}',
'Content-Type': 'application/json'
}
try:
response = requests.post(
f'{base_url}/payments/stk-push',
headers=headers,
json=payment_data
)
result = response.json()
if result['success']:
print(f"Payment initiated: {result['data']['TransactionReference']}")
return result['data']
else:
print(f"Payment failed: {result['message']}")
raise Exception(result['customerMessage'])
except requests.exceptions.RequestException as e:
print(f"Error initiating payment: {e}")
raise
# Usage
payment_data = {
'phone_number': '254712345678',
'amount': 100,
'external_reference': 'order_123',
'callback_url': 'https://your-domain.com/callback',
'metadata': {
'order_id': '12345',
'customer_name': 'John Doe'
}
}
initiate_payment(payment_data)PHP
<?php
function initiatePayment($paymentData) {
$apiKey = $_ENV['LIPIA_API_KEY'];
$baseUrl = $_ENV['LIPIA_BASE_URL'];
$headers = [
'Authorization: Bearer ' . $apiKey,
'Content-Type: application/json'
];
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $baseUrl . '/payments/stk-push');
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($paymentData));
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']) {
echo "Payment initiated: " . $result['data']['TransactionReference'];
return $result['data'];
} else {
echo "Payment failed: " . $result['message'];
throw new Exception($result['customerMessage']);
}
} else {
throw new Exception("HTTP Error: " . $httpCode);
}
}
// Usage
$paymentData = [
'phone_number' => '254712345678',
'amount' => 100,
'external_reference' => 'order_123',
'callback_url' => 'https://your-domain.com/callback',
'metadata' => [
'order_id' => '12345',
'customer_name' => 'John Doe'
]
];
initiatePayment($paymentData);
?>Testing
Test Phone Numbers
Use test phone numbers registered in your apps dashboard for test apps:
Best Practices
1. Error Handling
Always implement proper error handling:
try {
const result = await initiatePayment(paymentData);
// Handle success
} catch (error) {
if (error.code === 'VALIDATION_ERROR') {
// Show user-friendly validation message
} else if (error.code === 'PAYMENT_ERROR') {
// Handle payment-specific errors
} else {
// Handle other errors
}
}Next Steps
After initiating a payment:
- Store the TransactionReference for status checking
- Set up webhook handling to receive real-time updates
- Implement status polling as a fallback
- Handle all payment states (pending, success, failed)
Continue to Transaction Status to learn how to check payment status.