PHP code example of j-muiruri / daraja-php-sdk

1. Go to this page and download the library: Download j-muiruri/daraja-php-sdk library. Choose the download type require.

2. Extract the ZIP file and open the index.php.

3. Add this code to the index.php.
    
        
<?php
require_once('vendor/autoload.php');

/* Start to develop here. Best regards https://php-download.com/ */

    

j-muiruri / daraja-php-sdk example snippets


use Daraja\DarajaClient;
use Daraja\Enums\Environment;

$mpesa = DarajaClient::make(
    consumerKey:    $_ENV['MPESA_CONSUMER_KEY'],
    consumerSecret: $_ENV['MPESA_CONSUMER_SECRET'],
    shortcode:      $_ENV['MPESA_SHORTCODE'],
    passkey:        $_ENV['MPESA_PASSKEY'],
    environment:    Environment::Sandbox,
    callbackUrl:    '[https://yourapp.co.ke/mpesa/callback](https://yourapp.co.ke/mpesa/callback)',
    resultUrl:      '[https://yourapp.co.ke/mpesa/result](https://yourapp.co.ke/mpesa/result)',
    timeoutUrl:     '[https://yourapp.co.ke/mpesa/timeout](https://yourapp.co.ke/mpesa/timeout)',
);

$mpesa = DarajaClient::fromEnv();

// Initiate an STK Push to a Paybill
$response = $mpesa->stk()->push(
    phone:            '0712345678',   // or '+254712345678' or '254712345678'
    amount:           1500,           // KES, minimum 1
    accountReference: 'INV-0042',    // Max 12 chars — shown to customer
    description:      'Order #42',   // Max 13 chars
    callbackUrl:      'https://yourapp.co.ke/mpesa/callback', // override per request
);

if ($response->isAccepted()) {
    $checkoutId = $response->checkoutRequestId();
    // Store $checkoutId to poll status or match against the callback
}

// Buy Goods (till number) variant
$response = $mpesa->stk()->pushBuyGoods(
    phone:       '0712345678',
    amount:      250,
    till:        '123456',
    callbackUrl: 'https://yourapp.co.ke/mpesa/callback',
);

// Query status (when callback isn't received)
$status = $mpesa->stk()->query($checkoutId);
echo $status->resultDescription(); // "The service request is processed successfully."

$mpesa->c2b()->registerUrls(
    confirmationUrl: 'https://yourapp.co.ke/mpesa/confirm',
    validationUrl:   'https://yourapp.co.ke/mpesa/validate', // optional
    responseType:    'Completed', // 'Completed' or 'Cancelled'
);

// Sandbox only — simulate a payment
$mpesa->c2b()->simulate(
    phone:         '0712345678',
    amount:        500,
    billRefNumber: 'TEST001',
    commandId:     'CustomerPayBillOnline',
);

// Salary payment
$mpesa->b2c()->sendSalary(
    phone:   '0712345678',
    amount:  45000,
    remarks: 'April Salary',
);

//Promotion/betting payout
$mpesa->b2c()->sendPromotion(
    phone:   '0733123456',
    amount:  500,
    remarks: 'Jackpot winnings',
);

// General payment
$mpesa->b2c()->sendBusinessPayment('0722123456', 1200, 'Refund - Order #112');

$mpesa->b2cAccountTopUp()->topUp(
    b2cShortcode:     '600000',
    amount:           239,
    accountReference: '353353',
);

$mpesa->businessToPochi()->pay(
    phone:   '0705912645',
    amount:  1500,
    remarks: 'Stock payment',
);

use Daraja\Enums\Frequency;

$response = $mpesa->mpesaRatiba()->createForPayBill(
    standingOrderName: 'Monthly Rent - Unit 4B',   // must be unique per customer
    startDate:          new DateTimeImmutable('2026-09-01'),
    endDate:             new DateTimeImmutable('2027-09-01'),
    amount:              4500,
    payerPhone:          '0708374149',
    accountReference:    'UNIT-4B',
    frequency:           Frequency::Monthly,
);

// Ratiba nests its status differently to every other Daraja response —
// use the service's own accessors rather than $response->isAccepted():
if ($mpesa->mpesaRatiba()->isAccepted($response)) {
    // accepted for processing
}

$processor->onMpesaRatiba(function (MpesaRatibaResult $result) {
    if ($result->isSuccessful()) {
        // $result->transactionId, $result->status
    }
});

// One-time setup
$mpesa->pullTransaction()->register(
    shortCode:       '600000',
    nominatedNumber: '254722000000',
);

// Reconcile a window
$response = $mpesa->pullTransaction()->query(
    startDate: new DateTimeImmutable('-2 days'),
    endDate:   new DateTimeImmutable('now'),
);

$transactions = $response->get('Transaction', []);

// Pay a supplier's paybill
$mpesa->b2b()->payBill(
    receiverShortcode: '000001',
    amount:            75000,
    accountReference:  'SUPP-ACC-001',
    remarks:           'Invoice #INV-2025-03',
);

// Pay a merchant till
$mpesa->b2b()->buyGoods('987654', 12000, 'Office supplies');

$response = $mpesa->b2bExpressCheckout()->push(
    primaryShortCode:  '000001',        // Merchant's till (debit party)
    receiverShortCode: '000002',        // Your paybill (credit party)
    amount:            100,
    paymentRef:        'INV-0042',      // Shown to the merchant in the USSD prompt
    partnerName:        'Acme Traders', // Your org's friendly name, shown to the merchant
    callbackUrl:        'https://yourapp.co.ke/mpesa/b2b-checkout/callback',
);

if ($response->isSuccessful()) {
    // "USSD Initiated Successfully" — final result arrives at callbackUrl
}

$processor->onB2BExpressCheckout(function (B2BExpressCheckoutResult $result) {
    if ($result->isSuccessful()) {
        // $result->transactionId, $result->amount
    } elseif ($result->wasCancelled()) {
        // Merchant cancelled the USSD prompt
    }
});

use Daraja\Enums\IdentifierType;

$status = $mpesa->transactionStatus()->query(
    transactionId:  'QHT3XXXXXXXXXXX',  // M-Pesa receipt number
    identifierType: IdentifierType::Shortcode,
    remarks:        'Reconciliation check',
);

use Daraja\Enums\IdentifierType;

$mpesa->accountBalance()->query(
    identifierType: IdentifierType::Shortcode,
    remarks:        'EOD balance check',
);
// Result arrives asynchronously on your resultUrl

$mpesa->reversal()->reverse(
    transactionId: 'QHT3XXXXXXXXXXX',
    amount:        1500,
    remarks:       'Customer cancellation',
);

use Daraja\Enums\QRCodeType;

$response = $mpesa->qr()->generate(
    merchantName: 'Asante Coffee',
    refNo:        'INV-001',
    amount:       350,
    type:         QRCodeType::DynamicMerchant,
    size:         400,
);

// Get the Base64 PNG to embed in an <img> tag
$base64 = $mpesa->qr()->extractImage($response);
echo '<img src="data:image/png;base64,' . $base64 . '">';

// Or save to disk
$mpesa->qr()->saveImage($response, '/var/www/html/qr/payment.png');

$response = $mpesa->simSwap()->checkLastSwapDate('254722000000');

$lastSwap = $response->getString('lastSwapDate'); // e.g. "01-01-1900 00:00"

$response = $mpesa->imsi()->check('254722000000');

$imsi                   = $response->getString('imsi');
$lastSwapDate           = $response->getString('lastSwapDate');
$msisdnRegistrationDate = $response->getString('msisdnRegistrationDate');

// Check a SIM's status
$response = $mpesa->iotSim()->queryLifeCycleStatus(
    msisdn:   '300000020000',
    vpnGroup: '1-225560081663_VPN',
    username: '[email protected]',
);

// Every response uses its own header/body envelope — use these helpers
// rather than Response::isAccepted():
if ($mpesa->iotSim()->isSuccessful($response)) {
    $status = $response->data()['body']['status'] ?? null;
}

// Activate a SIM
$mpesa->iotSim()->activateSim('300000443539', '1-225560081663_VPN', '[email protected]');

// Suspend a subscriber
use Daraja\Enums\SimSubscriberOperation;

$mpesa->iotSim()->suspendOrResumeSubscriber(
    msisdn:    '300000100000',
    username:  '[email protected]',
    vpnGroup:  '1-225560081663_VPN',
    product:   '14205000',
    operation: SimSubscriberOperation::Suspend,
);

// Send a message to a SIM
$mpesa->iotSim()->sendSingleMessage('300001172000', 'Hello device', '1-47820525000_VPN');

use Daraja\ValueObjects\PhoneNumber;

PhoneNumber::from('0712345678');     // → 254712345678
PhoneNumber::from('+254712345678'); // → 254712345678
PhoneNumber::from('254712345678'); // → 254712345678
PhoneNumber::from('712345678');    // → 254712345678

use Daraja\Concerns\HasSecurityCredential;

class CredentialGenerator
{
    use HasSecurityCredential;

    public function generate(string $password, string $certPath): string
    {
        return $this->generateSecurityCredential($password, $certPath);
    }
}

$gen        = new CredentialGenerator();
$credential = $gen->generate('MyInitiatorPassword', '/path/to/cert.cer');
// Store $credential in your .env as MPESA_SECURITY_CREDENTIAL

use Daraja\Exceptions\ApiException;
use Daraja\Exceptions\AuthenticationException;
use Daraja\Exceptions\ValidationException;

try {
    $response = $mpesa->stk()->push(...);
} catch (ValidationException $e) {
    // Bad parameters — check before hitting the API
    foreach ($e->errors() as $field => $message) {
        echo "{$field}: {$message}\n";
    }
} catch (AuthenticationException $e) {
    // OAuth token failure — check consumer key/secret
    logger()->error('M-Pesa auth failed', ['error' => $e->getMessage()]);
} catch (ApiException $e) {
    // API returned an error response
    logger()->error('M-Pesa API error', [
        'status' => $e->statusCode(),
        'code'   => $e->errorCode(),
        'msg'    => $e->getMessage(),
    ]);
}

// config/mpesa.php
return [
    'consumer_key'        => env('MPESA_CONSUMER_KEY'),
    'consumer_secret'     => env('MPESA_CONSUMER_SECRET'),
    'shortcode'           => env('MPESA_SHORTCODE'),
    'passkey'             => env('MPESA_PASSKEY'),
    'environment'         => env('MPESA_ENVIRONMENT', 'sandbox'),
    'security_credential' => env('MPESA_SECURITY_CREDENTIAL'),
    'initiator_name'      => env('MPESA_INITIATOR_NAME'),
    'callback_url'        => env('MPESA_CALLBACK_URL'),
    'result_url'          => env('MPESA_RESULT_URL'),
    'timeout_url'         => env('MPESA_TIMEOUT_URL'),
];

// app/Providers/AppServiceProvider.php
use Daraja\DarajaClient;
use Daraja\Enums\Environment;

$this->app->singleton(DarajaClient::class, function () {
    return DarajaClient::make(
        consumerKey:        config('mpesa.consumer_key'),
        consumerSecret:     config('mpesa.consumer_secret'),
        shortcode:          config('mpesa.shortcode'),
        passkey:            config('mpesa.passkey'),
        environment:        Environment::from(config('mpesa.environment')),
        securityCredential: config('mpesa.security_credential'),
        initiatorName:      config('mpesa.initiator_name'),
        callbackUrl:        config('mpesa.callback_url'),
        resultUrl:          config('mpesa.result_url'),
        timeoutUrl:         config('mpesa.timeout_url'),
    );
});