SellKuick Gateway — documentação oficial

Aceita pagamentos M-Pesa dentro da tua própria aplicação ou website. O SellKuick funciona como um gateway completo: os clientes pagam no telefone, nós processamos, creditamos a conta do vendedor e avisamos o teu backend via webhook.

M-Pesa C2B Webhooks assinados Chaves secretas (sk_live_) Checkout hospedado

Como funciona

  1. Fazes a conta de vendedor em SellKuick e crias uma chave em Dashboard → Integrações.
  2. A tua aplicação envia Authorization: Bearer sk_live_... no header de cada pedido.
  3. Envias o amount, o customerPhone e opcionalmente descrição/metadata.
  4. O cliente final confirma o pagamento com PIN M-Pesa no telemóvel.
  5. Nós marcamos o pagamento como authorized, creditamos o saldo do vendedor e emitimos um webhook.

Chaves de API

As chaves começam por sk_live_. Guardamos apenas o hash da chave — ela só volta a ser mostrada no momento da criação ou da regeneração. Se perderes a chave, regenera nota partir da página de integrações.

Base URL — todos os pedidos passam pelo domínio principal

https://sellkuick.forge.co.mz/api/gateway/v1

Header de autenticação

Authorization: Bearer sk_live_a1b2c3d4e5f6a7b8c9d0e1f2c3d4e5f6a7b8c9d0
Content-Type: application/json

Cada chave pode ter o seu próprio webhook URL — útil se tiveres várias apps ou ambientes (produção/staging).

Criar pagamento

POST/api/gateway/v1/payments

Cria um pagamento e tenta o débito M-Pesa do cliente.

Auth: Bearer secret key

Pedido

POST /api/gateway/v1/payments
Authorization: Bearer sk_live_...
Content-Type: application/json

{
  "amount": 250,
  "method": "mpesa",
  "customerPhone": "841234567",
  "customerName": "João",
  "customerEmail": "joao@exemplo.com",
  "description": "Pedido #123",
  "metadata": { "orderId": "123" }
}

Resposta 201

{
  "intent_id": "gw_3jK2mN8q4rWx1pQ",
  "status": "authorized",
  "amount": 250,
  "method": "mpesa",
  "customer_phone": "841234567",
  "gateway_fee": 17.5,
  "seller_amount": 232.5,
  "checkout_url": "https://sellkuick.forge.co.mz/gateway/gw_3jK2mN8q4rWx1pQ"
}

Se o M-Pesa recusar, recebes 502 com error e o pagamento fica com estadofailed.

Consultar estado

GET/api/gateway/v1/payments/{intent_id}

Vista completa (com key). Inclui taxas, seller_amount e metadata.

Auth: Bearer secret key

GET/api/gateway/v1/public/payments/{intent_id}

Vista pública (para o checkout). Apenas estado e dados de apresentação.

Auth: pública

Resposta pública

{
  "intent_id": "gw_3jK2mN8q4rWx1pQ",
  "status": "authorized",
  "amount": 250,
  "method": "mpesa",
  "description": "Pedido #123",
  "merchant_name": "Loja Exemplo"
}

Checkout hospedado

Se não quiseres construir um formulário próprio, envia o cliente para o checkout_urldevolvido na criação do pagamento. A página já mostra o valor, o nome do vendedor e pede o número M-Pesa.

POST/api/gateway/v1/public/payments/{intent_id}/pay

Dispara o C2B a partir do checkout (número introduzido pelo cliente final).

Auth: pública

Corpo do pedido

{ "customerPhone": "841234567" }

O checkout faz polling ao endpoint público até o estado ficar authorized ou failed.

Exemplos de código

Cria um pagamento a partir da tua stack preferida. Substitui sk_live_... pela tua chave secreta — nunca a uses em código que corre no browser.

curl -X POST https://sellkuick.forge.co.mz/api/gateway/v1/payments \
  -H "Authorization: Bearer sk_live_..." \
  -H "Content-Type: application/json" \
  -d '{
    "amount": 250,
    "method": "mpesa",
    "customerPhone": "841234567",
    "description": "Pedido #123"
  }'

Todas as respostas devolvem intent_id e checkout_url. Guarda o intent_id para consultares o estado mais tarde, e envia o checkout_url ao cliente se preferires o checkout hospedado.

Webhooks

Define o webhookUrl na chave (página de integrações). Enviamos um POST com JSON para cada payment.authorized ou payment.failed, com assinatura no header X-SellKuick-Signature. Em caso de falha, fazemos até 3 tentativas.

Payload de exemplo

{
  "id": "evt_gw_3jK2mN8q4rWx1pQ_1",
  "type": "payment.authorized",
  "created_at": "2026-09-08T10:00:00.000Z",
  "data": {
    "intent_id": "gw_3jK2mN8q4rWx1pQ",
    "amount": 250,
    "method": "mpesa",
    "status": "authorized",
    "customer_phone": "841234567",
    "customer_email": "joao@exemplo.com",
    "description": "Pedido #123",
    "metadata": { "orderId": "123" },
    "paid_at": "2026-09-08T10:00:01.000Z",
    "reference": "MPESA-TXN-001"
  }
}

Validação da assinatura (Node.js)

import crypto from "crypto";

// apiKeyHash: o hash SHA-256 da tua chave (guardado no sato)
const signature = req.headers["x-sellkuick-signature"];
const rawBody = await req.text();

const expected = crypto
  .createHmac("sha256", apiKeyHash)
  .update(rawBody)
  .digest("hex");

const isValid = signature && crypto.timingSafeEqual(
  Buffer.from(signature),
  Buffer.from(expected)
);

Guarda sempre o hash da chave (não a chave original) para validar webhooks.

Códigos de erro

API_KEY_REQUIRED
Chave ausente ou mal formatada.
API_KEY_INVALID
A chave não existe.
API_KEY_REVOKED
A chave foi revogada pelo vendedor.
INVALID_AMOUNT
O valor deve ser um número superior a zero.
INVALID_METHOD
Método suportado: mpesa (emola e mkesh em breve no gateway).
INVALID_PHONE
Telefone do cliente em falta ou inválido (mín. 8 dígitos).
PAYMENT_FAILED
O M-Pesa rejeitou a transação do cliente.
NOT_FOUND
Pagamento não encontrado.
ALREADY_PROCESSED
O pagamento já foi processado anteriormente.
METHOD_NOT_SUPPORTED
Método ainda não suportado no hosted checkout.

Taxas

Cada pagamento gateway cobra 5% + 5 MT. O vendedor recebe amount − fee creditado no saldo SellKuick (junto das vendas de produtos digitais).

Limites

RegraLimite
Pedidos por chave1.000/dia
Webhooks retries3 tentativas
intents activos200 a pagamento
Rate limit (auth)200 pedidos / 15 min
Rate limit (payments)30 pedidos / min por chave

Estes limites podem ser ajustados por chave. Se precisares de mais limite, contacta suporte@sellkuick.forge.co.mz.