PHPackages                             brilliant\_mind/m-pesa - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Payment Processing](/categories/payments)
4. /
5. brilliant\_mind/m-pesa

ActiveLibrary[Payment Processing](/categories/payments)

brilliant\_mind/m-pesa
======================

MPesa package for laravel

v2.1.0(3w ago)0810↑214.3%MITPHPPHP ^8.1

Since Feb 28Pushed 3w agoCompare

[ Source](https://github.com/osvaldogeraldo/m-pesa)[ Packagist](https://packagist.org/packages/brilliant_mind/m-pesa)[ RSS](/packages/brilliant-mind-m-pesa/feed)WikiDiscussions main Synced 1w ago

READMEChangelogDependencies (8)Versions (6)Used By (0)

M-Pesa PHP SDK (Laravel)
========================

[](#m-pesa-php-sdk-laravel)

SDK para interagir com a API M-Pesa Moçambique: C2B, B2B, B2C, consulta de transação e reversão.

Feito para funcionar no Laravel **sem configuração manual**: instala, coloca duas variáveis no `.env` e já podes cobrar.

Índice
------

[](#índice)

- [Instalação](#instala%C3%A7%C3%A3o)
- [Configuração](#configura%C3%A7%C3%A3o)
    - [Variáveis de ambiente](#vari%C3%A1veis-de-ambiente)
    - [Tabela completa de variáveis](#tabela-completa-de-vari%C3%A1veis)
    - [Publicar o ficheiro de configuração](#publicar-o-ficheiro-de-configura%C3%A7%C3%A3o-opcional)
- [Utilização](#utiliza%C3%A7%C3%A3o)
    - [C2B — cliente paga à empresa](#c2b--cliente-paga-%C3%A0-empresa)
    - [B2C — empresa paga ao cliente](#b2c--empresa-paga-ao-cliente)
    - [B2B — empresa paga a outra empresa](#b2b--empresa-paga-a-outra-empresa)
    - [Consulta de transação](#consulta-de-transa%C3%A7%C3%A3o)
    - [Reversão](#revers%C3%A3o)
- [O objecto Transaction](#o-objecto-transaction)
- [Códigos de resposta](#c%C3%B3digos-de-resposta)
- [Modo fake (testes)](#modo-fake-testes)
- [Erros](#erros)
- [Fora do Laravel](#fora-do-laravel)
- [Notas sobre portos M-Pesa](#notas-sobre-portos-m-pesa)
- [Requisitos](#requisitos)

Instalação
----------

[](#instalação)

```
composer require brilliant_mind/m-pesa
```

É tudo. O pacote usa *package auto-discovery* do Laravel — o `ServiceProvider` e os aliases `MPesa` e `Mpesa` são registados automaticamente. **Não precisas** de publicar o config, nem de editar `config/app.php`, `bootstrap/providers.php` ou o `AppServiceProvider`.

Configuração
------------

[](#configuração)

### Variáveis de ambiente

[](#variáveis-de-ambiente)

Só `MPESA_API_KEY` e `MPESA_PUBLIC_KEY` são obrigatórias. Tudo o resto tem valores por omissão prontos para o sandbox.

#### Desenvolvimento (sandbox)

[](#desenvolvimento-sandbox)

```
# MPESA DEVELOPMENT
MPESA_API_KEY=sua_api_key_sandbox
MPESA_PUBLIC_KEY="MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB...FwIDAQAB"
MPESA_ENVIRONMENT=development
MPESA_SERVICE_PROVIDER_CODE=171717
```

#### Produção

[](#produção)

```
# MPESA PRODUCTION
MPESA_API_KEY=sua_api_key_producao
MPESA_PUBLIC_KEY="MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB...FwIDAQAB"
MPESA_ENVIRONMENT=production
MPESA_SERVICE_PROVIDER_CODE=903153
MPESA_INITIATOR_IDENTIFIER=seu_initiator
MPESA_SECURITY_CREDENTIAL=seu_credential_encriptado
```

> **A chave pública** é uma linha longa de base64 — envolve-a em aspas duplas. É aceite em qualquer formato: uma linha, com quebras de linha, ou o bloco PEM completo. Se preferires guardá-la num ficheiro, deixa `MPESA_PUBLIC_KEY` vazia e usa `MPESA_PUBLIC_KEY_PATH`.

> **Nota:** `MPESA_ENV` continua a ser aceite como alias retrocompatível de `MPESA_ENVIRONMENT`.

Se mudaste o `.env` e nada aconteceu, limpa a cache: `php artisan config:clear`.

### Tabela completa de variáveis

[](#tabela-completa-de-variáveis)

VariávelObrigatóriaDefaultDescrição`MPESA_API_KEY`**Sim**`''`Chave de API fornecida pelo portal da M-Pesa (sandbox ou produção).`MPESA_PUBLIC_KEY`**Sim**`''`Chave pública RSA em base64. Usada para encriptar o `MPESA_API_KEY` em cada chamada.`MPESA_PUBLIC_KEY_PATH`Não`''`Caminho para um ficheiro com a chave pública. Usado apenas se `MPESA_PUBLIC_KEY` estiver vazia.`MPESA_ENVIRONMENT`Não`development``development` (sandbox) ou `production`. Determina o host por defeito. Aceita também `sandbox`, `dev`, `prod` e `live`.`MPESA_SERVICE_PROVIDER_CODE`Não`171717`Código do *service provider*. `171717` é o de sandbox; em produção usa o teu (ex. `903153`).`MPESA_ORIGIN`Não`developer.mpesa.vm.co.mz`Valor do header `Origin` enviado a cada pedido.`MPESA_INITIATOR_IDENTIFIER`Apenas reversão`''`Identificador do *initiator* — obrigatório para `reversal()`.`MPESA_SECURITY_CREDENTIAL`Apenas reversão`''`Credencial encriptada do *initiator* — obrigatória para `reversal()`.`MPESA_HOST`NãoderivadoOverride manual do host. Por defeito escolhe `api.sandbox.vm.co.mz` ou `api.vm.co.mz`.`MPESA_PORT`Não`''`Força um único porto para todas as operações. Vazio usa o porto de cada operação.`MPESA_TIMEOUT`Não`90`Timeout de resposta em segundos. O C2B espera o PIN do cliente, por isso é longo.`MPESA_CONNECT_TIMEOUT`Não`30`Timeout de ligação em segundos.`MPESA_VERIFY_SSL`Não`true`Verificação do certificado TLS.### Publicar o ficheiro de configuração (opcional)

[](#publicar-o-ficheiro-de-configuração-opcional)

Só é necessário se quiseres alterar defaults além do `.env`:

```
php artisan vendor:publish --tag=mpesa-config
```

Utilização
----------

[](#utilização)

As operações existem em duas formas, ambas suportadas:

```
// Estática — como na v1.x
use BrilliantMind\MPesa\MPesa;

$transaction = MPesa::c2b(100, '841234567', 'ENC0001', 'TPR0001');

// De instância — via container, injecção de dependências ou facade
$transaction = app('mpesa')->c2b(100, '841234567', 'ENC0001', 'TPR0001');
```

A facade está disponível globalmente, sem `use`, em qualquer das grafias (`MPesa` ou `Mpesa`):

```
$transaction = MPesa::c2b(
    amount: 100,
    msisdn: '841234567',
    transactionReference: 'ENC0001',
    thirdPartyReference: 'TPR0001',
);

if ($transaction->isSuccessful()) {
    // guardar $transaction->getTransactionID()
}

return $transaction->getMessage();
```

O número de telemóvel é normalizado automaticamente — `841234567`, `0841234567`, `+258 84 123 4567` e `258841234567` produzem todos `258841234567`.

### C2B — cliente paga à empresa

[](#c2b--cliente-paga-à-empresa)

Debita a carteira do cliente e credita a da empresa. A M-Pesa envia um USSD Push ao cliente para confirmar o PIN.

```
$transaction = MPesa::c2b(100, '841234567', 'ENC0001', 'TPR0001');
```

### B2C — empresa paga ao cliente

[](#b2c--empresa-paga-ao-cliente)

```
$transaction = MPesa::b2c(100, '841234567', 'ENC0002', 'TPR0002');
```

### B2B — empresa paga a outra empresa

[](#b2b--empresa-paga-a-outra-empresa)

O segundo argumento é o **shortcode da empresa que recebe**, não um número de telemóvel.

```
$transaction = MPesa::b2b(100, '979797', 'ENC0003', 'TPR0003');
```

### Consulta de transação

[](#consulta-de-transação)

```
$transaction = MPesa::transaction('ENC0001', 'TPR0001');

$transaction->getTransactionStatus(); // ex.: 'Completed'
```

### Reversão

[](#reversão)

Requer `MPESA_INITIATOR_IDENTIFIER` e `MPESA_SECURITY_CREDENTIAL`.

```
$transaction = MPesa::reversal(100, '49XCDF6', 'TPR0001');
```

O objecto Transaction
---------------------

[](#o-objecto-transaction)

```
$transaction->isSuccessful();          // bool — true quando o código é INS-0
$transaction->failed();                // bool
$transaction->getResponseCode();       // 'INS-0'
$transaction->getMessage();            // descrição legível
$transaction->getTransactionID();      // id da transacção na M-Pesa
$transaction->getConversationID();
$transaction->getThirdPartReference();
$transaction->getTransactionStatus();  // só na consulta de estado
$transaction->getHttpStatus();         // HTTP devolvido pelo gateway
$transaction->getStatusCode();         // HTTP equivalente ao código INS
$transaction->raw();                   // payload original da M-Pesa
$transaction->toArray();
$transaction->toJson();
```

Nunca lança excepção por a M-Pesa ter recusado a transacção: uma recusa é sempre um `Transaction` com `failed() === true`. Excepções ficam reservadas para erros de configuração e de rede (ver [Erros](#erros)).

Códigos de resposta
-------------------

[](#códigos-de-resposta)

A tabela completa de códigos INS está em `BrilliantMind\MPesa\Response::$codes`:

```
use BrilliantMind\MPesa\Response;

Response::message('INS-2006');   // 'Insufficient balance'
Response::status('INS-2006');    // 422
Response::describe('INS-2006');  // ['code' => 422, 'message' => 'Insufficient balance']
Response::isSuccessful('INS-0'); // true
```

Modo fake (testes)
------------------

[](#modo-fake-testes)

Nos teus testes usa `fake()` para não tocar na rede:

```
use BrilliantMind\MPesa\MPesa;

MPesa::fake();                       // devolve sempre INS-0
MPesa::fake(422, 'INS-2006');        // simula saldo insuficiente
MPesa::fakeWith([                    // controlo total do payload
    'output_ResponseCode' => 'INS-0',
    'output_TransactionID' => '49XCDF6',
]);

MPesa::c2b(100, '841234567', 'REF', 'TPR');

MPesa::recorded();  // pedidos capturados, para asserções
MPesa::stopFaking();
```

Erros
-----

[](#erros)

ExcepçãoQuando aconteceComo resolver`MissingConfigurationException``MPESA_API_KEY` ou `MPESA_PUBLIC_KEY` em faltaPreenche o `.env` e corre `php artisan config:clear``EncryptionException`A chave pública não é válidaCopia outra vez a *Public Key* do portal da M-Pesa`InvalidEnvironmentException``MPESA_ENVIRONMENT` com valor desconhecidoUsa `development` ou `production``ConnectionException`O gateway não respondeuConfirma que o teu servidor permite tráfego de saída nos portos M-Pesa (ver abaixo)Todas herdam de `BrilliantMind\MPesa\Exceptions\MPesaException`, por isso podes apanhar tudo de uma vez:

```
use BrilliantMind\MPesa\Exceptions\MPesaException;

try {
    $transaction = MPesa::c2b(100, $msisdn, $reference, $thirdPartyReference);
} catch (MPesaException $e) {
    report($e);
}
```

Fora do Laravel
---------------

[](#fora-do-laravel)

O pacote também funciona em PHP puro; basta configurá-lo à mão:

```
require __DIR__ . '/vendor/autoload.php';

use BrilliantMind\MPesa\MPesa;

MPesa::config(
    api_key: 'a-tua-api-key',
    public_key: 'a-tua-public-key',
    environment: 'development',
    service_provider_code: '171717',
);

$transaction = MPesa::c2b(100, '841234567', 'ENC0001', 'TPR0001');
```

`MPesa::config()` aceita argumentos parciais — o que não passares mantém o valor actual.

Notas sobre portos M-Pesa
-------------------------

[](#notas-sobre-portos-m-pesa)

O gateway escuta num porto diferente por operação e a SDK trata disso sozinha:

OperaçãoPortoC2B`18352`B2C`18345`B2B`18349`Consulta de estado`18353`Reversão`18354`Como não são portos padrão, muitos alojamentos partilhados bloqueiam o tráfego de saída para eles — é a causa mais comum de `ConnectionException`. Se precisares de forçar um porto único (proxy, por exemplo), define `MPESA_PORT`.

Requisitos
----------

[](#requisitos)

- PHP `^8.1`
- Extensões `openssl`, `json`, `curl`
- Laravel 10, 11 ou 12 (opcional)

###  Health Score

45

—

FairBetter than 91% of packages

Maintenance96

Actively maintained with recent releases

Popularity18

Limited adoption so far

Community10

Small or concentrated contributor base

Maturity47

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 60.9% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~49 days

Total

4

Last Release

21d ago

Major Versions

v1.1.0 → v2.0.02026-07-23

### Community

Maintainers

![](https://avatars.githubusercontent.com/u/77959590?v=4)[Osvaldo Geraldo Manjate](/maintainers/osvaldogeraldo)[@osvaldogeraldo](https://github.com/osvaldogeraldo)

---

Top Contributors

[![osvaldogeraldo](https://avatars.githubusercontent.com/u/77959590?v=4)](https://github.com/osvaldogeraldo "osvaldogeraldo (14 commits)")[![paulo-maculuve](https://avatars.githubusercontent.com/u/75036310?v=4)](https://github.com/paulo-maculuve "paulo-maculuve (6 commits)")[![HelioHerculano](https://avatars.githubusercontent.com/u/66783101?v=4)](https://github.com/HelioHerculano "HelioHerculano (2 commits)")[![claude](https://avatars.githubusercontent.com/u/81847?v=4)](https://github.com/claude "claude (1 commits)")

---

Tags

laravelmpesamozambiquebrilliant\_mind

###  Code Quality

TestsPHPUnit

### Embed Badge

![Health badge](/badges/brilliant-mind-m-pesa/health.svg)

```
[![Health](https://phpackages.com/badges/brilliant-mind-m-pesa/health.svg)](https://phpackages.com/packages/brilliant-mind-m-pesa)
```

###  Alternatives

[craftcms/cms

Craft CMS

3.6k3.7M3.4k](/packages/craftcms-cms)[spatie/laravel-health

Monitor the health of a Laravel application

88212.7M188](/packages/spatie-laravel-health)[simplestats-io/laravel-client

Server-side analytics for Laravel that follows the full funnel from visit to registration to payment, attributed to the channel that drove it. Revenue, MRR, churn and ad-spend profit (ROAS/CAC) per channel. GDPR compliant, ad-blocker proof.

5226.7k](/packages/simplestats-io-laravel-client)[sebdesign/laravel-viva-payments

A Laravel package for integrating the Viva Payments gateway

4952.7k](/packages/sebdesign-laravel-viva-payments)[eslazarev/wildberries-sdk

Wildberries OpenAPI clients (generated).

353.6k](/packages/eslazarev-wildberries-sdk)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
