Documentação PayMoz

Integre pagamentos com uma documentação clara.

Guias, autenticação, endpoints e webhooks para conectar o seu produto ao PayMoz com segurança.

javascript
const payment = await fetch('/api/v1/payments', {
  method: 'POST',
  headers: {
    Authorization: 'Bearer YOUR_API_KEY'
  },
  body: JSON.stringify({
    amount: 1000,
    method: 'MPESA'
  })
});

Guia inicial

Início rápido

01

Crie sua conta

Acesse o dashboard e configure o perfil da empresa.

02

Gere uma API Key

Use a chave para autenticar as requisições.

03

Configure webhooks

Obrigatório para pagamentos eMola (assíncrono) e recomendado para todos os casos.

Segurança

Autenticação

Todas as requisições devem incluir a sua API Key no header Authorization usando o formato Bearer.

bash
curl -X POST https://paymozapi.saphirat.co.mz/api/v1/payments   -H "Authorization: Bearer YOUR_API_KEY"   -H "Content-Type: application/json"

Formato

Referência de Transação

A referência de transação deve ser uma string aleatória de exatamente 11 caracteres para garantir compatibilidade com o M-Pesa. Se o tamanho não for respeitado ou se houver colisão com uma referência existente, a transação falhará.

Requisitos da Referência

  • Tamanho: Exatamente 11 caracteres
  • Conteúdo: Qualquer combinação de letras (maiúsculas/minúsculas) e números
  • Unicidade: Deve ser única para cada transação para evitar colisões

Use a função abaixo como exemplo para gerar referências válidas e únicas no seu código:

javascript
function generateReference() {
  const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
  let result = '';
  for (let i = 0; i < 11; i++) {
    result += chars.charAt(Math.floor(Math.random() * chars.length));
  }
  return result;
}

// Exemplo de uso
const reference = generateReference();
console.log(reference); // Saída: aB3x9pQ2z7 (exemplo)

Referência

Endpoints

POST/api/v1/payments

Cria um novo pagamento e retorna a URL de checkout. O campo reference é opcional (se não fornecido, será gerado automaticamente).

Requisição:

javascript
const response = await fetch('https://paymozapi.saphirat.co.mz/api/v1/payments', {
  method: 'POST',
  headers: {
    'Authorization': 'Bearer YOUR_API_KEY',
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    amount: 1000,
    method: 'MPESA',
    callbackUrl: 'https://seu-site.com/webhook',
    returnUrl: 'https://seu-site.com/sucesso'
  })
});

Resposta:

json
{
  "status": "success",
  "data": {
    "id": "pay_abc123",
    "amount": 1000,
    "reference": "aB3x9pQ2z7K",
    "status": "PENDING",
    "checkout_url": "https://paymoz.saphirat.co.mz/checkout/pay_abc123",
    "checkoutUrl": "https://paymoz.saphirat.co.mz/checkout/pay_abc123"
  }
}
POST/api/v1/payments/direct

Processa um pagamento direto (sem URL de checkout). Requer número de telefone do cliente. O comportamento difere consoante o método de pagamento:

Comportamento por método

M-Pesa

Resposta síncrona e imediata — recebes 200 OK com SUCCESS ou 400/500 com FAILED na própria resposta.

eMola

Resposta assíncrona — recebes 202 Accepted com PROCESSING imediatamente. O estado final (SUCCESS / FAILED) é enviado via webhook quando o cliente confirma no telefone.

⚠️ eMola requer webhook: Para pagamentos eMola via Direct Payment, configura sempre um callbackUrl (na requisição ou no perfil da wallet) para receberes o evento payment.success ou payment.failed. Sem webhook, nunca saberás se o cliente confirmou ou rejeitou o pagamento.

🎯 Deduplicação de Pixel (Facebook/Meta): O PayMoz envia sempre o evento Purchase via Conversions API com event_id = payment.id. No teu website, dispara o fbq com o mesmo eventID — o Meta deduplica automaticamente os dois eventos numa janela de 7 dias, contando apenas uma conversão.

Deduplicação no teu website:

javascript
// 1. Chama o Direct Payment e guarda o id da resposta
const { data } = await response.json(); // data.id = "pay_abc123"

// 2. Dispara o fbq com eventID = data.id (mesmo que o PayMoz usa no CAPI)
//    O Meta deduplica — só conta uma conversão
fbq('track', 'Purchase', {
  value: 1000,
  currency: 'MZN',
  order_id: data.reference
}, { eventID: data.id }); // ← mesmo event_id que o servidor envia

Parâmetros opcionais:

  • fbc (string) — Cookie _fbc do browser do cliente. Melhora significativamente o match rate da Conversions API.
  • fbp (string) — Cookie _fbp do browser do cliente. Melhora o match rate da Conversions API.
  • customerEmail (string) — Email do cliente para melhor matching.
  • customerName (string) — Nome do cliente.

Requisição:

javascript
const response = await fetch('https://paymozapi.saphirat.co.mz/api/v1/payments/direct', {
  method: 'POST',
  headers: {
    'Authorization': 'Bearer YOUR_API_KEY',
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    amount: 1000,
    reference: 'aB3x9pQ2z7K',
    method: 'MPESA',
    customerPhone: '258841234567',
    callbackUrl: 'https://seu-site.com/webhook',
    description: 'Pagamento de exemplo',
    // Opcional: cookies do browser para melhor match rate + deduplicação
    fbc: getCookie('_fbc'),   // cookie _fbc do browser do cliente
    fbp: getCookie('_fbp'),   // cookie _fbp do browser do cliente
    customerEmail: 'cliente@example.com',
    customerName: 'João Silva'
  })
});

Resposta (M-Pesa — Sucesso imediato):

O M-Pesa devolve o resultado final na própria resposta HTTP (200 OK).

json
{
  "status": "success",
  "message": "Payment processed successfully",
  "data": {
    "id": "pay_abc123",
    "reference": "aB3x9pQ2z7K",
    "amount": 1000,
    "method": "MPESA",
    "status": "SUCCESS",
    "transactionId": "MP123456789",
    "customerPhone": "258841234567",
    "platformFee": 20,
    "gatewayFee": 10,
    "totalFee": 30,
    "netAmount": 970,
    "paidAt": "2026-07-13T12:34:56.789Z",
    "createdAt": "2026-07-13T12:34:56.123Z"
  }
}

Resposta (eMola — Processando):

O eMola devolve 202 Accepted com estado PROCESSING. O resultado final (SUCCESS ou FAILED) será enviado via webhook após confirmação do cliente no telemóvel.

json
{
  "status": "success",
  "message": "Pagamento eMola iniciado. Aguarde a confirmação no seu telefone.",
  "data": {
    "id": "pay_abc123",
    "reference": "aB3x9pQ2z7K",
    "amount": 1000,
    "method": "EMOLA",
    "status": "PROCESSING",
    "pagarPaymentId": "pag_xyz789",
    "createdAt": "2026-07-13T12:34:56.123Z"
  }
}
GET/api/v1/payments/reference/:ref

Consulta o estado de um pagamento por referência.

Requisição:

javascript
const response = await fetch(
  'https://paymozapi.saphirat.co.mz/api/v1/payments/reference/aB3x9pQ2z7K',
  {
    headers: {
      'Authorization': 'Bearer YOUR_API_KEY'
    }
  }
);

Resposta:

json
{
  "status": "success",
  "data": {
    "id": "pay_abc123",
    "amount": 1000,
    "reference": "aB3x9pQ2z7K",
    "status": "SUCCESS",
    "method": "MPESA",
    "transactionId": "MP123456789",
    "createdAt": "2026-07-13T12:34:56.123Z",
    "paidAt": "2026-07-13T12:35:01.456Z"
  }
}

Eventos

Webhooks

Pagamentos eMola são sempre assíncronos. Quer seja via Checkout ou Direct Payment, o estado final do pagamento eMola só é conhecido quando recebes o webhook payment.success ou payment.failed. Sem webhook configurado, não tens forma de saber se o cliente confirmou o pagamento no telemóvel.

payment.created

Pagamento criado (ainda não processado)

payment.success

Pagamento aprovado — liberta o produto/serviço

payment.failed

Pagamento falhado — notifica o utilizador

Fluxo por método

  • M-Pesa (Direct): Recebes 200 SUCCESS na própria resposta e o webhook payment.success é enviado em paralelo (redundância).
  • eMola (Direct / Checkout): O pagamento fica em PROCESSING. Só quando o cliente confirma/rejeita no telemóvel é que o webhook payment.success ou payment.failed chega ao teu sistema.
javascript
app.post('/webhook', (req, res) => {
  const { event, data } = req.body;

  if (event === 'payment.success') {
    console.log(`Pagamento ${data.reference} confirmado!`);
  }

  res.status(200).send('OK');
});