Um SDK robusto e completo para integração com a API M-Pesa da Vodacom em Moçambique, desenvolvido em TypeScript/JavaScript. Suporta todas as operações principais: C2B, B2C, B2B, Query e Reversal.
- Autenticação Segura: Criptografia RSA do apiKey com a publicKey
- Seleção de Ambiente: Suporte automático para sandbox e produção
- Tratamento de Erros Robusto: Classe MpesaError personalizada
- Logging Detalhado: Para depuração e monitoramento
- TypeScript: Tipagem completa para melhor experiência de desenvolvimento
- Testes Unitários: Cobertura completa com Jest
- API Simplificada: Métodos curtos e intuitivos
- Respostas Legíveis: Formato de resposta limpo e organizado
npm install mpesa-mz-sdk
Crie um arquivo .env
na raiz do seu projeto:
# Credenciais M-Pesa
MPESA_API_KEY=sua_api_key_aqui
MPESA_PUBLIC_KEY=sua_public_key_aqui
MPESA_SERVICE_PROVIDER_CODE=seu_service_provider_code
MPESA_ORIGIN=seu_origin_aqui
# Ambiente (sandbox ou live)
MPESA_ENV=sandbox
import { MpesaService } from 'mpesa-sdk-mozambique';
const mpesa = new MpesaService({
apiKey: process.env.MPESA_API_KEY!,
publicKey: process.env.MPESA_PUBLIC_KEY!,
serviceProviderCode: process.env.MPESA_SERVICE_PROVIDER_CODE!,
origin: process.env.MPESA_ORIGIN!,
env: process.env.MPESA_ENV as 'sandbox' | 'live', // Define automaticamente o host
timeout: 60000 // Timeout opcional em ms
});
Todos os métodos retornam um objeto padronizado com a seguinte estrutura:
{
status: 'success' | 'error',
message: string,
data?: T, // Dados específicos da operação
code?: string, // Código de resposta da M-Pesa
httpStatus?: number,
transactionId?: string,
conversationId?: string,
thirdPartyReference?: string,
timestamp?: string
}
try {
const response = await mpesa.c2b({
amount: 100.00,
number: '25884xxxxxxx', // MSISDN (número) do cliente
transactionReference: 'TXN123',
thirdPartyReference: 'REF456'
});
if (response.status === 'success') {
console.log('Transação realizada com sucesso!');
console.log('Transaction ID:', response.data?.transactionId);
console.log('Amount:', response.data?.amount);
console.log('Customer:', response.data?.customerMsisdn);
} else {
console.error('Erro na transação:', response.message);
}
} catch (error) {
console.error('C2B Error:', error.message);
}
try {
const response = await mpesa.b2c({
amount: 50.00,
number: '25884xxxxxxx', // MSISDN (número) do destinatário
transactionReference: 'TXN789',
thirdPartyReference: 'REF101',
paymentServices: 'BusinessPayBill' // Opcional, padrão: BusinessPayBill
});
if (response.status === 'success') {
console.log('Pagamento enviado com sucesso!');
console.log('Transaction ID:', response.data?.transactionId);
console.log('Recipient:', `${response.data?.recipientFirstName || ''} ${response.data?.recipientLastName || ''}`.trim());
console.log('Settlement Amount:', response.data?.settlementAmount);
}
} catch (error) {
console.error('B2C Error:', error.message);
}
try {
const response = await mpesa.b2b({
amount: 1000.00,
primaryPartyCode: 'COMPANY001', // Código da empresa que envia
recipientPartyCode: 'COMPANY002', // Código da empresa que recebe
transactionReference: 'TXN202',
thirdPartyReference: 'REF303',
paymentServices: 'BusinessToBusinessTransfer' // Opcional, padrão: BusinessToBusinessTransfer
});
if (response.status === 'success') {
console.log('Transferência B2B realizada!');
console.log('From:', response.data?.primaryPartyCode);
console.log('To:', response.data?.recipientPartyCode);
console.log('Amount:', response.data?.amount);
console.log('Settlement:', response.data?.settlementAmount);
}
} catch (error) {
console.error('B2B Error:', error.message);
}
try {
const response = await mpesa.query({
queryReference: 'TXN123', // Transaction ID ou Conversation ID
thirdPartyReference: 'REF456'
});
if (response.status === 'success') {
console.log('Status da transação consultado!');
console.log('Transaction Status:', response.data?.transactionStatus);
console.log('Payment Status:', response.data?.paymentStatusDesc);
console.log('Payment Code:', response.data?.paymentStatusCode);
}
} catch (error) {
console.error('Query Error:', error.message);
}
try {
const response = await mpesa.reversal({
originalTransactionId: 'MPA_TRANS_ID_FROM_PREVIOUS_SUCCESSFUL_C2B',
reversalAmount: 50.00,
thirdPartyReference: 'REF789'
});
if (response.status === 'success') {
console.log('Reversão realizada com sucesso!');
console.log('Original Transaction:', response.data?.originalTransactionId);
console.log('Reversal Amount:', response.data?.reversalAmount);
console.log('New Transaction ID:', response.data?.transactionId);
}
} catch (error) {
console.error('Reversal Error:', error.message);
}
O SDK utiliza criptografia RSA para gerar o token Bearer:
-
Criptografia: O
apiKey
é criptografado usando apublicKey
com RSA PKCS1_PADDING -
Formatação: A
publicKey
é automaticamente formatada no padrão PEM - Token: O resultado criptografado é usado como Bearer token
// O SDK faz isso automaticamente:
// 1. Formata a publicKey para PEM
// 2. Criptografa o apiKey com a publicKey
// 3. Usa o resultado como Bearer token
-
Host:
api.sandbox.vm.co.mz:18352
- Uso: Para testes e desenvolvimento
-
Configuração:
env: 'sandbox'
-
Host:
api.vm.co.mz:18352
- Uso: Para operações reais
-
Configuração:
env: 'live'
O SDK inclui tratamento robusto de erros com mensagens descritivas baseadas na documentação oficial da M-Pesa API. Todos os códigos de erro oficiais estão mapeados para mensagens claras e compreensíveis.
class MpesaError extends Error {
constructor(
message: string,
public code: string,
public statusCode: number,
public details?: any
) {
super(message);
this.name = 'MpesaError';
}
}
O SDK inclui todos os códigos de erro oficiais da documentação da M-Pesa API:
- INS-0: Request processed successfully
- INS-1: Internal Error
- INS-2: Invalid API Key
- INS-4: User is not active
- INS-5: Transaction cancelled by customer
- INS-6: Transaction Failed
- INS-9: Request timeout
- INS-10: Duplicate Transaction
- INS-13: Invalid Shortcode Used
- INS-14: Invalid Reference Used
- INS-15: Invalid Amount Used
- INS-16: Unable to handle the request due to a temporary overloading
- INS-17: Invalid Transaction Reference. Length Should Be Between 1 and 20.
- INS-18: Invalid TransactionID Used
- INS-19: Invalid ThirdPartyReference Used
- INS-20: Not All Parameters Provided. Please try again.
- INS-21: Parameter validations failed. Please try again.
- INS-22: Invalid Operation Type
- INS-23: Unknown Status. Contact M-Pesa Support
- INS-24: Invalid InitiatorIdentifier Used
- INS-25: Invalid SecurityCredential Used
- INS-26: Not authorized
- INS-993: Direct Debit Missing
- INS-994: Direct Debit Already Exists
- INS-995: Customer's Profile Has Problems
- INS-996: Customer Account Status Not Active
- INS-997: Linking Transaction Not Found
- INS-998: Invalid Market
- INS-2001: Initiator authentication error.
- INS-2002: Receiver invalid.
- INS-2006: Insufficient balance
- INS-2051: Invalid number
- INS-2057: Language code invalid.
Execute os testes unitários:
npm test
- ✅ C2B (Customer to Business)
- ✅ B2C (Business to Customer)
- ✅ B2B (Business to Business)
- ✅ Query (Consulta de Status)
- ✅ Reversal (Reversão)
- ✅ Tratamento de Erros
- ✅ Autenticação
- ✅ Formato de Resposta Simplificado
const mpesa = new MpesaService({
// ... outras configurações
timeout: 120000 // 2 minutos
});
const mpesa = new MpesaService({
// ... outras configurações
apiHost: 'api.custom.vm.co.mz:18352' // Host personalizado
});
-
Verifique as credenciais:
echo $MPESA_API_KEY echo $MPESA_PUBLIC_KEY
-
Confirme o ambiente:
echo $MPESA_ENV
-
Teste a criptografia:
import { generateBearerToken, formatPublicKey } from 'mpesa-sdk-mozambique'; const token = generateBearerToken(apiKey, formatPublicKey(publicKey)); console.log('Generated Token:', token);
-
Aumente o timeout:
const mpesa = new MpesaService({ // ... outras configurações timeout: 120000 // 2 minutos });
-
Verifique a conectividade:
ping api.sandbox.vm.co.mz
O SDK formata automaticamente a public key, mas se houver problemas:
import { formatPublicKey } from 'mpesa-sdk-mozambique';
const formattedKey = formatPublicKey(publicKey);
console.log('Formatted Key:', formattedKey);
MIT License - veja o arquivo LICENSE para detalhes.
Contribuições são bem-vindas! Por favor:
- Fork o projeto
- Crie uma branch para sua feature (
git checkout -b feature/AmazingFeature
) - Commit suas mudanças (
git commit -m 'Add some AmazingFeature'
) - Push para a branch (
git push origin feature/AmazingFeature
) - Abra um Pull Request
Para suporte e dúvidas:
- 📧 Email: abelbartolomeu06@gmail.com
- 🐛 Issues: GitHub Issues
Desenvolvido com ❤️ para a comunidade M-Pesa em Moçambique