— Documentação Pública

Documentação API — NetShop

Referência oficial da Gateway NetShop. Integração com Wallet ID, API Key e a Base URL abaixo.

Base URLhttps://www.netshop.co.mz/api/v1

Fluxo de fundos

ProvedoresNetShopMerchant. As cobranças liquidam para a conta NetShop do seu merchant e ficam disponíveis já com a comissão deduzida.

1. Autenticação

Todos os pedidos exigem três credenciais obrigatórias:

  • Wallet ID — identificador único de 6 dígitos do merchant (header X-Wallet-ID).
  • API Key — chave secreta começada por ns_live_ ou ns_test_ (header Authorization: Bearer …).
  • Base URLhttps://www.netshop.co.mz/api/v1 (100% LIVE, sem subdomínios e sem ambiente de testes).
curl https://www.netshop.co.mz/api/v1/charges \
  -H "Authorization: Bearer ns_live_sk_4f8a2c…" \
  -H "X-Wallet-ID: 418207" \
  -H "Idempotency-Key: 550e8400-e29b-41d4-a716-446655440000" \
  -H "Content-Type: application/json"

O Wallet ID é mostrado no canto superior direito do painel de cada merchant e em /app/definicoes. Pedidos sem Wallet ID válido devolvem 401 missing_or_invalid_wallet_id.

2. Base URL & Versões

A API é versionada por URL. A versão estável actual é v1. Servimos toda a plataforma a partir de netshop.co.mz — sem subdomínios (nada de pay., api. ou split.). Use sempre o domínio whitelabel:

Base URL (LIVE):    https://www.netshop.co.mz/api/v1
Links de pagamento: www.netshop.co.mz/pay/{code}
Hosted checkout:    www.netshop.co.mz/link/{id}
Split landing:      www.netshop.co.mz/split/{id}

Health-check: antes de ir a produção, valide a Base URL com GET https://www.netshop.co.mz/api/v1/ping — deve devolver { "ok": true, "canonical_host": true }. Se canonical_host vier false, a URL configurada no seu backend está errada.

curl -i https://www.netshop.co.mz/api/v1/ping

3. Cobranças (Charges)

Criar uma cobrança Visa/Mastercard, M-Pesa, e-Mola ou mKesh. Para method:"card" a resposta inclui um checkout.hosted_url (página segura hospedada pelo NetShop); para carteiras móveis a transacção é confirmada em tempo real pelo cliente no telemóvel.

POST https://www.netshop.co.mz/api/v1/charges

{
  "amount": 2500,
  "currency": "MZN",
  "method": "mpesa",          // card | mpesa | emola | mkesh
  "msisdn": "+258842828600",  // obrigatório para wallets móveis (omitir em card)
  "customer_email": "cli@ex.mz", // recomendado para cartões
  "tokenize_for_recurring": false, // true → prepara o cartão para subscrições
  "reference": "Fatura #2410",
  "metadata": { "order_id": "ord_001" }
}

Redirecionar o cliente para o seu site (return_url)

Envie return_url (HTTPS) no POST /charges. Após o pagamento, o cliente é reencaminhado para esse endereço em vez de ficar numa página NetShop. Aplica-se ao checkout de cartão e ao checkout hospedado e-Mola.

{
  "amount": 2500,
  "method": "card",
  "reference": "Fatura #2410",
  "return_url": "https://minhaloja.mz/checkout/retorno"
}

# NetShop acrescenta os parâmetros ao seu URL:
#   https://minhaloja.mz/checkout/retorno?status=paid&id=ch_API-XXXX&reference=Fatura%20%232410
#   status ∈ paid | failed | pending

O return_url é apenas uma conveniência de UX: confirme sempre o pagamento pelo webhook ou por GET /charges/{id} antes de libertar o produto.

Resposta:

{
  "id": "ch_01HZ…",
  "status": "paid",            // paid | pending | failed
  "amount": 2500,
  "currency": "MZN",
  "fees": { "platform": 375 },
  "net": 2125,
  "provider": { "transactionID": "DFR5KMP1B65", "thirdPartyReference": "ord_001" }
}

Resposta (cartão / Checkout hospedado NetShop):

{
  "id": "ch_PL-XXXX",
  "status": "pending",
  "method": "card",
  "amount": 2500,
  "currency": "MZN",
  "reference": "Fatura #2410",
  "checkout": {
    "type": "hosted_url",
    "hosted_url": "https://netshop.co.mz/pay/card/PL-XXXX?session=...",
    "order_id": "PL-XXXX"
  }
}

Fluxo cartão: redireccione o cliente para hosted_url — a página de pagamento é servida pelo NetShop com a marca do seu merchant. Após a autorização, a transacção converge para paid ou failed e o evento é enviado para o webhook que configurou no dashboard.

Consultar estado de uma cobrança

Se o seu sistema não receber a confirmação pelo webhook (ou pela resposta síncrona), consulte o estado actual da transacção. Este endpoint é a fonte de verdade — pode chamar sempre que precisar de reconciliar.

GET https://www.netshop.co.mz/api/v1/charges/{id}

# {id} aceita:
#   • o "id" devolvido no POST /charges (ex.: ch_NSABC123)
#   • o "reference" que enviou (ex.: Fatura #2410)
curl https://www.netshop.co.mz/api/v1/charges/ch_NSABC123 \
  -H "Authorization: Bearer ns_live_sk_4f8a2c…" \
  -H "X-Wallet-ID: 418207"

Resposta:

{
  "id": "ch_NSABC123",
  "status": "paid",              // paid | pending | failed
  "amount": 2500,
  "currency": "MZN",
  "method": "mpesa",
  "reference": "Fatura #2410",
  "msisdn": "842828600",
  "fee": 250,
  "net": 2250,
  "provider": {
    "transactionID": "DFR5KMP1B65",
    "thirdPartyReference": "NSABC123",
    "responseCode": "INS-0",
    "responseDesc": "Request processed successfully"
  },
  "failed_reason": null,
  "card": {
    "masked_pan": "512345xxxxxx0008",
    "first6": "512345",
    "last4": "0008",
    "brand": "MASTERCARD",
    "scheme": "MASTERCARD",
    "funding_method": "CREDIT",
    "issuer": "BANCO XYZ",
    "issuer_country": "MOZ",
    "expiry_month": 5,
    "expiry_year": 30
  },
  "created_at": "2026-07-14T14:03:11.000Z",
  "processed_at": "2026-07-14T14:03:22.000Z"
}

O objecto card só é devolvido em cobranças method: "card" e contém apenas dados não sensíveis (PAN mascarado com os primeiros 6 e últimos 4 dígitos, marca/scheme, país emissor). O mesmo objecto é enviado no webhook charge.paid / charge.failed.

Cobranças presas em pending há mais de 5 minutos disparam automaticamente a rotina de reconciliação com o provedor antes de responderem, pelo que o estado devolvido reflecte o mais recente disponível. Se a cobrança não existir para o Wallet ID autenticado, a API devolve 404 charge_not_found.

5. Split Payments

Distribuir uma cobrança por várias sub-contas (regras criadas em /app/sub-contas):

POST https://www.netshop.co.mz/api/v1/splits/process

{
  "split_id": "uuid-do-split",
  "transaction_reference": "ord_001",
  "gross_amount": 10000,
  "platform_fee": 1500,
  "gateway_fee": 0,
  "payment_method": "mpesa",
  "currency": "MZN",
  "metadata": {}
}

É idempotente por (merchant, transaction_reference): o mesmo pedido nunca distribui duas vezes.

6. Subscrições / Débito Directo (Visa·Mastercard)

Débito automático recorrente está disponível exclusivamente em Visa/Mastercard. Carteiras móveis (M-Pesa, e-Mola, mKesh) não suportam mandatos recorrentes — para cobranças únicas use POST /charges.

POST https://www.netshop.co.mz/api/v1/subscriptions

{
  "amount": 1200,
  "currency": "MZN",
  "frequency": "monthly",
  "custom_interval_days": null,
  "reference": "PLAN-PRO-2026-001",
  "label": "Subscrição Plano Pro",
  "customer_name": "Ana Macuácua",
  "customer_email": "ana@exemplo.mz",
  "metadata": { "plan": "pro" }
}

Frequências aceites: daily, weekly, monthly, yearly, custom (obriga custom_interval_days entre 1 e 365).

Resposta:

{
  "id": "sub_01HZ…",
  "reference": "PLAN-PRO-2026-001",
  "status": "pending",
  "amount": 1200,
  "currency": "MZN",
  "frequency": "monthly",
  "customer": { "name": "Ana Macuácua", "email": "ana@exemplo.mz" },
  "checkout": { "type": "hosted_url", "url": "https://www.netshop.co.mz/s/PLAN-PRO-2026-001" }
}

Abra checkout.url para o cliente aceitar o mandato, autorizar o 1º ciclo e tokenizar o cartão. Após o pagamento paid, a subscrição passa a active e os ciclos seguintes são debitados automaticamente pelo NetShop nas datas do plano (sem nova interacção do cliente).

7. Payouts (B2C)

Envie dinheiro da sua carteira NetShop para qualquer MSISDN M-Pesa ou e-Mola. Mesmo modelo de autenticação, idempotência e webhooks das cobranças. Sem mínimo em B2C automatizado.

O payout debita apenas o saldo disponível na sua conta NetShop (cobranças liquidadas menos comissões e payouts anteriores). Pedidos acima do disponível são rejeitados com 422 insufficient_balance.

POST https://www.netshop.co.mz/api/v1/payouts

{
  "amount": 1500,
  "currency": "MZN",
  "method": "mpesa",            // mpesa | emola
  "msisdn": "+258842828600",    // MSISDN do destinatário
  "reference": "SAL-2410-001",  // identificador único no seu sistema
  "metadata": { "purpose": "salario" }
}

Resposta:

{
  "id": "po_NB01HZ…",
  "status": "completed",         // completed | pending | failed
  "amount": 1500,
  "currency": "MZN",
  "method": "mpesa",
  "fees": { "our": 90, "provider": 60 },
  "net": 1350,
  "reference": "SAL-2410-001",
  "provider": {
    "transactionID": "DFR5KMP1B65",
    "thirdPartyReference": "NB01HZ…"
  }
}

Payouts assíncronos (status:"pending") convergem via callback do provedor. Assim que confirmados, disparamos payout.completed ou payout.failed no seu webhook. Cartões (Visa/Mastercard) não suportam B2C — para reembolsos use POST /refunds.

Consultar estado de um payout

Se não receber a confirmação pelo webhook (ou pela resposta síncrona), consulte o estado actual do payout. Fonte de verdade — pode chamar sempre que precisar de reconciliar.

GET https://www.netshop.co.mz/api/v1/payouts/{id}

# {id} aceita:
#   • o "id" devolvido no POST /payouts (ex.: po_NB01HZ…)
#   • o "reference" que enviou (ex.: SAL-2410-001)
curl https://www.netshop.co.mz/api/v1/payouts/po_NB01HZ \
  -H "Authorization: Bearer ns_live_sk_4f8a2c…" \
  -H "X-Wallet-ID: 418207"

Resposta:

{
  "id": "po_NB01HZ…",
  "status": "completed",         // completed | pending | failed
  "amount": 1500,
  "currency": "MZN",
  "method": "mpesa",
  "reference": "SAL-2410-001",
  "msisdn": "842828600",
  "fees": { "our": 90, "provider": 60 },
  "net": 1350,
  "provider": {
    "transactionID": "DFR5KMP1B65",
    "thirdPartyReference": "NB01HZ…",
    "responseCode": "INS-0",
    "responseDesc": "Request processed successfully"
  },
  "failed_reason": null,
  "created_at": "2026-07-14T14:03:11.000Z",
  "processed_at": "2026-07-14T14:03:22.000Z"
}

Payouts presos em pending há mais de 5 minutos disparam automaticamente a rotina de reconciliação com o provedor antes de responderem. Se o payout não existir para o Wallet ID autenticado, a API devolve 404 payout_not_found.

8. Reembolsos (Refunds)

Reembolsos totais ou parciais de uma cobrança liquidada. Cartões são reembolsados pela gateway para o mesmo cartão; carteiras móveis (M-Pesa, e-Mola, mKesh) são devolvidas ao MSISDN pagador. O pedido entra como pending e é executado pela NetShop.

POST https://www.netshop.co.mz/api/v1/refunds

{
  "charge_id": "ch_API-MSNBAIES-XS13D",   // id ou reference da cobrança
  "amount": 500,                            // opcional → omitir reembolsa o total
  "reason": "requested_by_customer",       // duplicate | fraudulent | requested_by_customer
                                            // | product_not_received | other
  "note": "Cliente cancelou a encomenda"
}

Resposta 202:

{
  "id": "re_RF8KD2P1",
  "status": "pending",                 // pending | completed | failed | rejected
  "charge_id": "ch_API-MSNBAIES-XS13D",
  "amount": 500,
  "currency": "MZN",
  "method": "card",
  "is_partial": true,
  "fee_refund": 50,
  "net": 450,
  "reason": "requested_by_customer",
  "failed_reason": null,
  "reference": "RF8KD2P1",
  "created_at": "2026-08-10T15:02:11.000Z"
}
GET https://www.netshop.co.mz/api/v1/refunds/{id}     # id: re_RF8KD2P1, RF8KD2P1 ou o id da cobrança

curl https://www.netshop.co.mz/api/v1/refunds/re_RF8KD2P1 \
  -H "Authorization: Bearer ns_live_sk_4f8a2c…" \
  -H "X-Wallet-ID: 418207"

Erros específicos: 404 charge_not_found, 422 charge_not_refundable (a cobrança não está paid), 422 refund_exceeds_charge e 422 refund_exceeds_remaining (já reembolsado no todo ou em parte).

9. Webhooks

Eventos enviados ao seu endpoint HTTPS, com retentativas exponenciais até 72h:

  • charge.paid
  • charge.failed
  • charge.pending
  • refund.created
  • payout.completed
  • payout.failed
  • dispute.opened
  • subscription.renewed

Cada pedido inclui o header X-NetShop-Signature (HMAC-SHA256 sobre o corpo). Valide sempre antes de processar:

const expected = hmacSha256(secret, rawBody);
if (!timingSafeEqual(expected, signatureHeader)) reject(401);

10. Idempotência

Todos os POST aceitam Idempotency-Key (UUID único). Pedidos repetidos com a mesma chave devolvem a resposta original — seguro para retries com timeout.

11. Limites & Mínimos

Valores mínimos por método de pagamento e por payout, aplicáveis em LIVE:

OperaçãoMétodoMínimo
CobrançaM-Pesa10 MT
CobrançamKesh10 MT
Cobrançae-Mola10 MT
CobrançaVisa / Mastercard50 MT
Cobrança ZARVisa / MastercardR 10
Payout manualBanco / Wallet1 000 MT
Payout automático / B2CM-Pesa, e-Mola, mKeshSem mínimo

12. Estados & Códigos de Erro

Estado é a fonte de verdade

Use sempre o campo status devolvido por GET /charges/{id} (ou pelo webhook) como decisão final. Só paid e failed são estados terminais.

statusSignificadoAcção
paidPago e liquidado (terminal)Libertar produto/serviço
failedRecusado ou cancelado (terminal)Mostrar failed_reason
pendingEm curso: cliente ainda não confirmou no telemóvel, 3DS por concluir ou callback do provedor por chegarVoltar a consultar (polling 5–10 s, até 30 min)

Nos payouts o estado terminal de sucesso chama-se completed (equivalente a paid). Nos reembolsos: pendingcompleted | failed | rejected.

responseCode / responseDesc / failed_reason

  • provider.responseCode e provider.responseDesc — preenchidos assim que o provedor (M-Pesa, PaySuite/e-Mola, mKesh, MPGS) responde, em qualquer estado. São o código e a mensagem crus do provedor; use-os para diagnóstico, nunca para decidir o estado.
  • failed_reason — preenchido apenas quando status = failed. É a mensagem legível a mostrar ao merchant/cliente. Em paid e pending vem null.
  • Em cartões (MPGS) o responseCode pode vir null e a razão da recusa aparece em failed_reason.
responseCodeMensagem típicastatus resultante
INS-0Request processed successfullypaid
INS-1Internal error / transacção não concluídafailed
INS-6Transaction failedfailed
INS-2006Saldo insuficiente do clientefailed
INS-2051MSISDN inválidofailed
INS-9Request timeout — cliente não confirmou a tempopending
TIMEOUTSem resposta do provedor; o pagador pode ter sido debitadopending
min_amountValor abaixo do mínimo do métodofailed
processinge-Mola/mKesh: push enviado, a aguardar o PIN do clientepending
DECLINED / 3DS_FAILEDCartão recusado pelo emissor ou 3DS falhadofailed

A lista de códigos dos provedores pode crescer — trate qualquer código desconhecido pelo status e mostre responseDesc/failed_reason como texto.

Erros HTTP da API

401 missing_or_invalid_api_key
401 missing_or_invalid_wallet_id
403 wallet_id_mismatch
400 validation_error
422 processing_failed
422 amount_below_minimum · amount_above_maximum · method_disabled
422 charge_not_refundable · refund_exceeds_charge · refund_exceeds_remaining
404 charge_not_found · payout_not_found · refund_not_found
409 idempotency_conflict
429 rate_limited
500 internal_error

13. SDKs Oficiais

  • Node.js / TypeScript — npm i @netshop/node
  • Python — pip install netshop
  • PHP — composer require netshop/netshop-php
  • Java — com.netshop:netshop-java:1.x

Plugins prontos: WooCommerce e WHMCS. Para Shopify use o guia NetShop + Shopify (Custom Payment).