Documentação

Documentação API

Última atualização: setembro de 2026

Este guia reúne tudo o que precisa para aceitar M-Pesa, mKesh e cartões Visa/Mastercard na pay.co.mz, com os endpoints reais em produção. A integração M-Pesa Moçambique é exclusivamente de produção: não existe ambiente sandbox nem simulação.

1. Como funciona

A API pay.co.mz é REST, aceita e devolve JSON e exige HTTPS em todos os pedidos. Cada cobrança fica pendente até o provedor confirmar; só nessa altura o saldo é creditado. A comissão é sempre 10% do valor da transacção, sem mensalidade.

  • URL base de produção: https://pay.co.mz/api/public/v1
  • Endpoints disponíveis: POST /charges, GET /charges, POST /payouts
  • Cabeçalho obrigatório em pedidos com corpo: Content-Type: application/json
  • Corpo limitado a 8 KB; valores em MZN com duas casas decimais
  • M-Pesa e cartões/mKesh são exclusivamente de produção — não existe sandbox

2. Autenticação

Cada pedido é validado com quatro elementos: a URL base, a chave de API (Authorization: Bearer), o Wallet ID de 5 dígitos da carteira que recebe o dinheiro (X-Wallet-Id ou campo wallet_id) e o Merchant ID de 10 dígitos da sua conta (X-Merchant-Id, disponível em Definições). Gere as chaves no painel, em Developer, e veja o Wallet ID em Carteiras. A chave começa por sk_live_ e nunca deve ir para código de navegador ou repositórios públicos.

curl https://pay.co.mz/api/public/v1/charges \
  -H "Authorization: Bearer sk_live_xxx" \
  -H "X-Wallet-Id: 48213" \
  -H "X-Merchant-Id: 1234567890" \
  -H "Content-Type: application/json"

3. Criar uma cobrança

POST /charges. O corpo aceita apenas amount, method, customer_name, customer_contact e wallet_id (campos extra são recusados). O method aceita mpesa, mkesh ou card — e-Mola ainda não tem provedor activo em produção. Recomendamos sempre o cabeçalho Idempotency-Key (mínimo 8 caracteres): repetir o mesmo pedido nunca cria uma segunda cobrança. Resposta 201 quando o provedor aceita de imediato, 202 enquanto fica pendente.

curl https://pay.co.mz/api/public/v1/charges \
  -H "Authorization: Bearer sk_live_..." \
  -H "X-Merchant-Id: 1234567890" \
  -H "X-Wallet-Id: 48213" \
  -H "Idempotency-Key: encomenda-1042" \
  -H "Content-Type: application/json" \
  -d '{
    "method": "card",
    "amount": 1500.00,
    "customer_name": "Ana Cossa",
    "customer_contact": "ana@exemplo.mz"
  }'

HTTP/1.1 202 Accepted
{
  "data": {
    "reference": "PAY-48213-A55391CEBA",
    "transaction_reference": "PAY-48213-A55391CEBA",
    "amount": 1500.00,
    "method": "card",
    "state": "pending",
    "checkout_url": "https://pay.co.mz/checkout/cs_9f2c...",
    "source": "api"
  }
}

4. Cobranças por método

Cada método tem um comportamento próprio. Em baixo encontra a secção dedicada a M-Pesa, mKesh, Visa/Mastercard e e-Mola, com o campo method a usar, o formato do contacto do cliente e o que acontece a seguir.

  • M-Pesa — method: "mpesa" — confirmação por PIN no telemóvel
  • mKesh — method: "mkesh" — confirmação no telemóvel, acompanhada no checkout
  • Visa/Mastercard — method: "card" — checkout seguro com a sua marca
  • e-Mola — em breve; ainda sem provedor activo em produção

4.1 M-Pesa (Vodacom)

Use method "mpesa". O customer_contact tem de ser o número no formato 258XXXXXXXXX (84 ou 85). O pedido segue para a Vodacom em produção e o cliente confirma com o PIN; a resposta é 202 e o estado final chega por webhook. Os levantamentos M-Pesa seguem de imediato por B2C.

curl https://pay.co.mz/api/public/v1/charges \
  -H "Authorization: Bearer sk_live_..." \
  -H "X-Merchant-Id: 1234567890" \
  -H "X-Wallet-Id: 48213" \
  -H "Idempotency-Key: pedido-1042" \
  -H "Content-Type: application/json" \
  -d '{"method":"mpesa","amount":1500.00,"customer_contact":"258841234567"}'

HTTP/1.1 202 Accepted
{
  "data": {
    "reference": "PAY-48213-A55391CEBA",
    "amount": 1500.00,
    "method": "mpesa",
    "state": "pending",
    "source": "api"
  }
}

4.2 mKesh

Use method "mkesh" com o número do cliente (82 ou 83) em 258XXXXXXXXX. O pagamento corre pelo nosso provedor de produção: o cliente confirma no telemóvel e pode acompanhar o estado no checkout_url devolvido. Os levantamentos mKesh ficam pendentes de aprovação do administrador.

curl https://pay.co.mz/api/public/v1/charges \
  -H "Authorization: Bearer sk_live_..." \
  -H "X-Merchant-Id: 1234567890" \
  -H "X-Wallet-Id: 48213" \
  -H "Idempotency-Key: pedido-1043" \
  -H "Content-Type: application/json" \
  -d '{"method":"mkesh","amount":900.00,"customer_contact":"258821234567"}'

HTTP/1.1 202 Accepted
{
  "data": {
    "reference": "PAY-48213-7C1A0B44E2",
    "method": "mkesh",
    "state": "pending",
    "checkout_url": "https://pay.co.mz/checkout/cs_7c1a..."
  }
}

4.3 Visa/Mastercard

Use method "card". Encaminhe o cliente para o checkout_url devolvido — é uma página segura com a sua marca. O customer_contact pode ser o e-mail do cliente. É o único método com reembolsos, pedidos no painel e aprovados pelo administrador.

curl https://pay.co.mz/api/public/v1/charges \
  -H "Authorization: Bearer sk_live_..." \
  -H "X-Merchant-Id: 1234567890" \
  -H "X-Wallet-Id: 48213" \
  -H "Idempotency-Key: encomenda-1044" \
  -H "Content-Type: application/json" \
  -d '{"method":"card","amount":1500.00,"customer_name":"Ana Cossa","customer_contact":"ana@exemplo.mz"}'

HTTP/1.1 202 Accepted
{
  "data": {
    "reference": "PAY-48213-A55391CEBA",
    "method": "card",
    "state": "pending",
    "checkout_url": "https://pay.co.mz/checkout/cs_9f2c..."
  }
}

4.4 e-Mola (em breve)

O e-Mola ainda não tem provedor activo em produção, por isso method "emola" é recusado com invalid_method. Assim que a ligação estiver disponível, funcionará exactamente como os restantes métodos: mesmo endpoint, mesmos cabeçalhos e o mesmo webhook — só precisa de criar a carteira e-Mola e passar method "emola".

5. Consultar o estado

GET /charges devolve as suas transações mais recentes com o estado actual. O parâmetro limit aceita entre 1 e 100 (por omissão 20). Recomendamos confiar no webhook e usar esta consulta apenas como confirmação ou reconciliação.

curl "https://pay.co.mz/api/public/v1/charges?limit=20" \
  -H "Authorization: Bearer sk_live_..."

{
  "data": [{
    "id": "0f8c...",
    "reference": "PAY-48213-A55391CEBA",
    "amount": 1500.00,
    "fee": 150.00,
    "net": 1350.00,
    "method": "mpesa",
    "status": "pending",
    "operator_ref": "DI80LI5BYYM",
    "customer_name": "Ana Cossa",
    "customer_contact": "258841234567",
    "created_at": "2026-09-09T10:12:44.128Z"
  }]
}

6. Levantamentos (saque)

POST /payouts pede um levantamento da carteira indicada. O Wallet ID é obrigatório (X-Wallet-Id ou wallet_id) tal como o X-Merchant-Id. Em carteiras M-Pesa o pagamento segue de imediato para a Vodacom B2C; em mKesh e cartão/banco o pedido fica pendente de aprovação do administrador. Em alternativa, active o saque automático nas definições da carteira, com uma taxa de 5% sobre o valor líquido.

curl https://pay.co.mz/api/public/v1/payouts \
  -H "Authorization: Bearer sk_live_..." \
  -H "X-Wallet-Id: 48213" \
  -H "X-Merchant-Id: 1234567890" \
  -H "Content-Type: application/json" \
  -d '{"amount": 900.00}'

HTTP/1.1 201 Created
{
  "data": {
    "id": "5b21...",
    "amount": 900.00,
    "fee": 0,
    "destination": "258841234567",
    "status": "pending",
    "state": "processing",
    "auto": false,
    "created_at": "2026-09-09T10:15:02.441Z"
  }
}

8. Webhooks

Registe o endereço HTTPS do seu servidor em Developer → Webhooks. Enviamos um POST por evento, com até três tentativas até receber uma resposta 2xx. Endereços internos, IP directos e HTTP simples são recusados por segurança.

  • payment.succeeded — pagamento confirmado e saldo creditado
  • payment.failed — pagamento recusado, cancelado ou expirado
  • payout.paid — levantamento concluído no operador
  • payout.failed — levantamento recusado pelo operador
  • Cabeçalhos: X-Pay-Event, X-Pay-Event-Id e X-Pay-Signature
POST https://o-seu-servidor.com/webhooks/pay
X-Pay-Event: payment.succeeded
X-Pay-Event-Id: 2f1c9d64-...
X-Pay-Signature: t=1757246400,v1=8f3c...

{
  "id": "2f1c9d64-...",
  "event": "payment.succeeded",
  "created_at": "2026-09-09T10:20:31.004Z",
  "data": {
    "id": "0f8c...",
    "reference": "PAY-48213-A55391CEBA",
    "amount": 1500.00,
    "provider": "mpesa",
    "provider_transaction_id": "DI80LI5BYYM",
    "state": "successful"
  }
}

9. Validar a assinatura do webhook

A assinatura é um HMAC-SHA256 do texto "<timestamp>.<corpo em bruto>" com o segredo do webhook (visível uma vez em Developer). Valide sempre antes de actualizar a encomenda, usando o corpo em bruto (não o JSON reconstruído) e rejeitando marcas temporais com mais de 5 minutos.

import { createHmac, timingSafeEqual } from "crypto";

function verify(secret, rawBody, header) {
  const parts = Object.fromEntries(
    header.split(",").map((p) => p.trim().split("=")),
  );
  const ts = Number(parts.t);
  if (!Number.isFinite(ts) || Math.abs(Date.now() / 1000 - ts) > 300) return false;

  const expected = createHmac("sha256", secret)
    .update(`${ts}.${rawBody}`)
    .digest("hex");
  const a = Buffer.from(parts.v1 ?? "", "utf8");
  const b = Buffer.from(expected, "utf8");
  return a.length === b.length && timingSafeEqual(a, b);
}

10. Reembolsos

Os reembolsos existem apenas para Visa/Mastercard e são pedidos no painel, em Reembolsos, indicando o ID da transacção. Cada pedido carece de aprovação do administrador antes de ser executado. Não existe endpoint público de reembolso.

11. M-Pesa Moçambique (apenas produção)

A ligação à Vodacom M-Pesa Moçambique é exclusivamente de produção. Não existe, nem é aceite, qualquer ambiente sandbox ou de simulação: URLs como api.sandbox.vm.co.mz são recusadas e, se faltar uma credencial de produção, o pedido falha de imediato. Todas as chamadas partem do nosso servidor; a chave de API, a chave pública e o entity code nunca chegam ao navegador, aos registos ou às respostas.

  • C2B — o cliente paga ao negócio e confirma com o PIN no telemóvel
  • B2C — o negócio paga ao cliente; usado nos levantamentos M-Pesa
  • Estados: created, pending, processing, successful, failed, cancelled, expired, reversed
  • Callback C2B: https://pay.co.mz/api/public/v1/mpesa/c2b-callback
  • Callback B2C: https://pay.co.mz/api/public/v1/mpesa/b2c-callback
  • Nunca creditamos saldo com base numa confirmação do navegador

12. Visa/Mastercard e mKesh

Cartões e mKesh são processados em produção através do nosso provedor de cartões. A confirmação chega por callback assinado e é reconfirmada directamente no provedor antes de creditar o saldo, para que uma notificação falsa nunca gere um pagamento aprovado.

  • Callback do provedor: https://pay.co.mz/api/public/v1/netshop/callback
  • Checkout com a sua marca em https://pay.co.mz/checkout/<token>
  • Transações abertas expiram automaticamente e são reconciliadas
  • Levantamentos em mKesh e cartão exigem aprovação do administrador

13. Requisitos para entrar em produção

Antes de aceitar pagamentos reais confirme, com a Vodacom, os dados do contrato e, no painel de administração, o estado da configuração em Pagamentos.

  • Entity code (service provider code) de produção atribuído pela Vodacom
  • Chave de API e chave pública de produção guardadas apenas no servidor
  • URLs de callback registadas no operador e acessíveis por HTTPS
  • Conta verificada (KYC aprovado) e carteira activa com número válido
  • Verificação de ligação bem-sucedida na consola de administração

14. Erros

Respondemos com códigos HTTP padrão e um corpo no formato {"error": "codigo"}. Guarde sempre a referência da cobrança e trate pedidos repetidos com a mesma Idempotency-Key como um só.

  • 400 — invalid_request, invalid_json, invalid_amount, invalid_method, invalid_wallet, invalid_merchant_id, invalid_idempotency_key, amount_below_minimum, msisdn_required
  • 401 — invalid_api_key (chave inválida, revogada ou em falta)
  • 402 — insufficient_balance (levantamentos)
  • 403 — merchant_not_active, blocked_by_risk
  • 405 — method_not_allowed | 413 — payload_too_large | 415 — unsupported_media_type
  • 429 — rate_limited; aguarde e tente de novo
HTTP/1.1 401 Unauthorized
{ "error": "invalid_api_key" }

15. Apoio à integração

A nossa equipa acompanha a sua integração de ponta a ponta. Escreva para suporte@pay.co.mz ou ligue para +258 82 7369 480 com a referência da cobrança em causa e respondemos com o diagnóstico.