Integre a Tecnologia líder em Moçambique
Nossa API robusta e segura permite que você conecte o seu sistema aos principais métodos de pagamento e serviços digitais em minutos.
Documentação Técnica
Aceite pagamentos via M-Pesa, e-Mola, mKesh, Visa/Mastercard (MZN) e PayFast (ZAR) com uma única integração REST. Todos os métodos retornam JSON e usam autenticação Bearer.
Overview
#A EasyHost API foi desenhada para ser rápida e segura. Expondo três endpoints principais que permitem desde a criação de pagamentos até a consulta de saldos em tempo real.
M-Pesa
STK Push direto para o telemóvel
e-Mola
Integração via USSD Push
Segurança
HMAC-SHA256 & TLS 1.3
Autenticação
#Todas as chamadas server-side usam Bearer com a chave de API do comerciante (sk_live_... ou sk_sandbox_...). As chaves podem ser geradas no painel em Configurações → Chaves de API.
Authorization: Bearer sk_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
Content-Type: application/json
Accept: application/jsonAtenção: Nunca exponha a sua chave secreta em código front-end. Para o browser, utilize apenas o session_token emitido pelo endpoint /payment-session.
Base URL
#Todas as requisições devem ser feitas para a seguinte URL base:
https://mescwrzkwjwtyjouueqq.supabase.co/functions/v1A chave fica apenas no seu browser e é usada pelos botões Try it out abaixo.
Ambiente Live
https://mescwrzkwjwtyjouueqq.supabase.co/functions/v1Ambiente Sandbox
https://mescwrzkwjwtyjouueqq.supabase.co/functions/v1Use sk_sandbox_ para testes
/payment-orchestrator
#Endpoint principal para criar cobranças em qualquer método suportado. O orquestrador detecta automaticamente o melhor roteamento.
Requisitos C2B: Para validar qualquer transação Consumer-to-Business (C2B), os campos merchant_id, wallet_id e api_key são estritamente obrigatórios no corpo da requisição.
/payment-orchestratorSchema da Requisição
{
"type": "object",
"required": ["merchant_id", "wallet_id", "api_key", "amount", "currency", "payment_method", "customer"],
"properties": {
"merchant_id": { "type": "string", "description": "ID único do comerciante" },
"wallet_id": { "type": "string", "description": "ID da carteira de destino" },
"api_key": { "type": "string", "description": "Chave de API para validação C2B" },
"amount": { "type": "integer", "minimum": 100, "description": "Valor em centavos" },
"currency": { "type": "string", "enum": ["MZN", "ZAR", "USD"] },
"payment_method": { "type": "string", "enum": ["mpesa", "emola", "mkesh", "card", "payfast"] },
"description": { "type": "string", "maxLength": 255 },
"external_reference": { "type": "string", "maxLength": 64 },
"callback_url": { "type": "string", "format": "uri" },
"customer": {
"type": "object",
"required": ["name"],
"properties": {
"name": { "type": "string", "maxLength": 100 },
"email": { "type": "string", "format": "email" },
"phone": { "type": "string", "pattern": "^258[0-9]{9}$|^27[0-9]{9}$" }
}
},
"card": {
"type": "object",
"description": "Obrigatório quando payment_method = card",
"properties": {
"number": { "type": "string" },
"exp_month": { "type": "integer", "minimum": 1, "maximum": 12 },
"exp_year": { "type": "integer" },
"cvv": { "type": "string", "minLength": 3, "maxLength": 4 },
"holder_name": { "type": "string" }
}
}
}
}Schema da Resposta
{
"type": "object",
"properties": {
"id": { "type": "string", "example": "pay_987654321" },
"status": { "type": "string", "enum": ["pending", "processing", "completed", "failed", "expired"] },
"amount": { "type": "integer" },
"currency": { "type": "string" },
"payment_method": { "type": "string" },
"provider": { "type": "string", "description": "Ex: vodacom, movitel, mkesh, payfast, visa" },
"provider_reference": { "type": "string", "nullable": true },
"external_reference": { "type": "string", "nullable": true },
"checkout_url": { "type": "string", "format": "uri", "nullable": true },
"expires_at": { "type": "string", "format": "date-time" },
"created_at": { "type": "string", "format": "date-time" }
}
}Parâmetros
| Campo | Tipo | Descrição |
|---|---|---|
| merchant_id | String | Obrigatório. Seu identificador único de comerciante. |
| wallet_id | String | Obrigatório. Identificador da carteira onde o fundo será depositado. |
| api_key | String | Obrigatório. Chave de autenticação para validação de transações C2B. |
| amount | Integer | Valor em centavos (ex: 1500 = 15.00 MZN) |
| currency | String | MZN, ZAR ou USD |
| payment_method | String | mpesa, emola, mkesh, card, payfast |
| customer.phone | String | Obrigatório para mpesa, emola e mkesh (formato E.164 sem +) |
| callback_url | String | Opcional. URL chamada após mudança de estado. |
| external_reference | String | Seu identificador interno (idempotência). |
Exemplos por payment_method
Cada método tem requisitos específicos. Veja request e response reais para cada um:
M-Pesa (Vodacom)
POST /payment-orchestrator
{
"merchant_id": "mrc_887766",
"wallet_id": "wlt_554433",
"api_key": "sk_live_xxxxxx",
"amount": 1500,
"currency": "MZN",
"payment_method": "mpesa",
"description": "Fatura #12345",
"external_reference": "INV-12345",
"customer": {
"name": "João Silva",
"phone": "258840000000"
}
}{
"id": "pay_01HXMP9A8K2N",
"status": "pending",
"amount": 1500,
"currency": "MZN",
"payment_method": "mpesa",
"provider": "vodacom",
"provider_reference": "MP240520.1010.A12345",
"external_reference": "INV-12345",
"checkout_url": null,
"expires_at": "2024-05-20T10:05:00Z",
"created_at": "2024-05-20T10:00:00Z"
}e-Mola (Movitel)
POST /payment-orchestrator
{
"merchant_id": "mrc_887766",
"wallet_id": "wlt_554433",
"api_key": "sk_live_xxxxxx",
"amount": 2500,
"currency": "MZN",
"payment_method": "emola",
"description": "Recarga conta",
"customer": {
"name": "Maria Santos",
"phone": "258860000000"
}
}{
"id": "pay_01HXMQ5C1L9P",
"status": "pending",
"amount": 2500,
"currency": "MZN",
"payment_method": "emola",
"provider": "movitel",
"provider_reference": "EM240520-7788",
"checkout_url": null,
"expires_at": "2024-05-20T10:05:00Z",
"created_at": "2024-05-20T10:00:00Z"
}mKesh (TMcel)
POST /payment-orchestrator
{
"merchant_id": "mrc_887766",
"wallet_id": "wlt_554433",
"api_key": "sk_live_xxxxxx",
"amount": 5000,
"currency": "MZN",
"payment_method": "mkesh",
"description": "Assinatura mensal",
"customer": {
"name": "Carlos Mucavele",
"phone": "258820000000"
}
}{
"id": "pay_01HXMR2F4M6Q",
"status": "processing",
"amount": 5000,
"currency": "MZN",
"payment_method": "mkesh",
"provider": "mkesh",
"provider_reference": "MK20240520-991122",
"checkout_url": null,
"expires_at": "2024-05-20T10:05:00Z",
"created_at": "2024-05-20T10:00:00Z"
}Cartão Visa / Mastercard (MZN)
POST /payment-orchestrator
{
"merchant_id": "mrc_887766",
"wallet_id": "wlt_554433",
"api_key": "sk_live_xxxxxx",
"amount": 12000,
"currency": "MZN",
"payment_method": "card",
"description": "Compra Loja Online",
"callback_url": "https://sualoja.co.mz/retorno",
"customer": {
"name": "Ana Macuácua",
"email": "ana@exemplo.co.mz"
}
}{
"id": "pay_01HXMS8H7N2R",
"status": "pending",
"amount": 12000,
"currency": "MZN",
"payment_method": "card",
"provider": "visa",
"checkout_url": "https://checkout.easyhost.co.mz/c/pay_01HXMS8H7N2R",
"expires_at": "2024-05-20T10:30:00Z",
"created_at": "2024-05-20T10:00:00Z"
}PayFast (ZAR — África do Sul)
POST /payment-orchestrator
{
"merchant_id": "mrc_887766",
"wallet_id": "wlt_554433",
"api_key": "sk_live_xxxxxx",
"amount": 25000,
"currency": "ZAR",
"payment_method": "payfast",
"description": "Order #98765",
"callback_url": "https://yourshop.co.za/return",
"customer": {
"name": "Thabo Nkosi",
"email": "thabo@example.co.za"
}
}{
"id": "pay_01HXMT1J3P8S",
"status": "pending",
"amount": 25000,
"currency": "ZAR",
"payment_method": "payfast",
"provider": "payfast",
"checkout_url": "https://www.payfast.co.za/eng/process?uuid=...",
"expires_at": "2024-05-20T10:30:00Z",
"created_at": "2024-05-20T10:00:00Z"
}Respostas de Erro
{
"type": "object",
"properties": {
"error": {
"type": "object",
"properties": {
"code": { "type": "string", "example": "insufficient_funds" },
"message": { "type": "string" },
"param": { "type": "string", "nullable": true },
"request_id": { "type": "string" }
}
}
}
}{
"error": {
"code": "invalid_phone",
"message": "O número informado não pertence à rede Vodacom.",
"param": "customer.phone",
"request_id": "req_01HXMU9K2Q7T"
}
}POST /payment-orchestrator/payment-session
#Gera um token de sessão seguro de curta duração para uso em checkout hospedado ou integrações front-end. Nunca exponha sk_live_ no browser.
/payment-sessionSchema da Requisição
{
"type": "object",
"required": ["merchant_id", "wallet_id", "api_key", "amount", "currency"],
"properties": {
"merchant_id": { "type": "string", "description": "ID único do comerciante" },
"wallet_id": { "type": "string", "description": "ID da carteira de destino" },
"api_key": { "type": "string", "description": "Chave de API para validação C2B" },
"amount": { "type": "integer", "minimum": 100 },
"currency": { "type": "string", "enum": ["MZN", "ZAR", "USD"] },
"allowed_methods": { "type": "array", "items": { "type": "string", "enum": ["mpesa","emola","mkesh","card","payfast"] } },
"domain": { "type": "string", "description": "Domínio que carregará o widget" },
"success_url": { "type": "string", "format": "uri" },
"cancel_url": { "type": "string", "format": "uri" },
"expires_in": { "type": "integer", "default": 900, "description": "Segundos até expirar (máx 3600)" },
"metadata": { "type": "object", "additionalProperties": { "type": "string" } }
}
}Schema da Resposta
{
"type": "object",
"properties": {
"session_token": { "type": "string", "description": "JWT de curta duração, usar no front-end" },
"session_id": { "type": "string" },
"checkout_url": { "type": "string", "format": "uri" },
"expires_at": { "type": "string", "format": "date-time" }
}
}POST /payment-session
{
"merchant_id": "mrc_887766",
"wallet_id": "wlt_554433",
"api_key": "sk_live_xxxxxx",
"amount": 1500,
"currency": "MZN",
"allowed_methods": ["mpesa", "emola", "card"],
"domain": "sualoja.co.mz",
"success_url": "https://sualoja.co.mz/sucesso",
"cancel_url": "https://sualoja.co.mz/cancelado",
"expires_in": 900,
"metadata": { "order_id": "ORD-998" }
}{
"session_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"session_id": "ses_01HXMV3L5R9U",
"checkout_url": "https://checkout.easyhost.co.mz/s/ses_01HXMV3L5R9U",
"expires_at": "2024-05-20T10:15:00Z"
}POST /payment-session/wallet-balance
#Consulta o saldo disponível em tempo real para cada carteira integrada (M-Pesa, e-Mola, mKesh, cartão e PayFast).
/wallet-balanceQuery Parameters (opcionais)
{
"type": "object",
"properties": {
"currency": { "type": "string", "enum": ["MZN", "ZAR", "USD"] },
"method": { "type": "string", "enum": ["mpesa","emola","mkesh","card","payfast"] }
}
}Schema da Resposta
{
"type": "object",
"properties": {
"wallets": {
"type": "array",
"items": {
"type": "object",
"properties": {
"payment_method": { "type": "string", "enum": ["mpesa","emola","mkesh","card","payfast"] },
"provider": { "type": "string" },
"currency": { "type": "string" },
"available": { "type": "integer", "description": "Disponível em centavos" },
"pending": { "type": "integer" },
"updated_at": { "type": "string", "format": "date-time" }
}
}
}
}
}{
"wallets": [
{ "payment_method": "mpesa", "provider": "vodacom", "currency": "MZN", "available": 1250000, "pending": 35000, "updated_at": "2024-05-20T10:00:00Z" },
{ "payment_method": "emola", "provider": "movitel", "currency": "MZN", "available": 430000, "pending": 0, "updated_at": "2024-05-20T10:00:00Z" },
{ "payment_method": "mkesh", "provider": "mkesh", "currency": "MZN", "available": 180000, "pending": 5000, "updated_at": "2024-05-20T10:00:00Z" },
{ "payment_method": "card", "provider": "visa", "currency": "MZN", "available": 920000, "pending": 12000, "updated_at": "2024-05-20T10:00:00Z" },
{ "payment_method": "payfast", "provider": "payfast", "currency": "ZAR", "available": 560000, "pending": 20000, "updated_at": "2024-05-20T10:00:00Z" }
]
}GET /wallet-balanceWebhooks
#Receba notificações em tempo real sempre que uma transação mudar de estado. Todos os webhooks são assinados com um segredo HMAC-SHA256.
Exemplo de Payload
{
"id": "evt_123456789",
"type": "payment.succeeded",
"created_at": "2024-05-20T10:00:00Z",
"data": {
"id": "pay_987654321",
"amount": 1500,
"status": "completed",
"payment_method": "mpesa",
"external_reference": "258841234567"
}
}payment.succeeded
Enviado quando o pagamento é confirmado pelo provedor.
payment.failed
Enviado quando a transação expira ou é rejeitada.
Cabeçalhos enviados
Cada requisição POST inclui os seguintes cabeçalhos para que você possa validar a origem e prevenir replay attacks:
| Header | Descrição |
|---|---|
| X-Webhook-Signature | Assinatura HMAC-SHA256 (hex) do corpo bruto. |
| X-Webhook-Timestamp | Unix timestamp do envio. Rejeite se > 5 min. |
| X-Webhook-Id | ID único do evento (use para idempotência). |
Verificação da assinatura
Calcule um HMAC-SHA256 de timestamp + "." + raw_body usando seu webhook_secret e compare em tempo constante com o header recebido.
import express from "express";
import crypto from "crypto";
const app = express();
const WEBHOOK_SECRET = process.env.WEBHOOK_SECRET;
const MAX_AGE = 5 * 60; // 5 minutos
// IMPORTANTE: use o corpo BRUTO (raw) para calcular a assinatura
app.post("/webhooks/easyhost", express.raw({ type: "application/json" }), (req, res) => {
const signature = req.header("X-Webhook-Signature");
const timestamp = req.header("X-Webhook-Timestamp");
const rawBody = req.body.toString("utf8");
if (!signature || !timestamp) return res.status(400).send("missing headers");
// 1. Proteção contra replay
const age = Math.floor(Date.now() / 1000) - Number(timestamp);
if (age > MAX_AGE) return res.status(401).send("timestamp too old");
// 2. Calcular assinatura esperada
const expected = crypto
.createHmac("sha256", WEBHOOK_SECRET)
.update(`${timestamp}.${rawBody}`)
.digest("hex");
// 3. Comparação em tempo constante
const valid = crypto.timingSafeEqual(
Buffer.from(signature, "hex"),
Buffer.from(expected, "hex")
);
if (!valid) return res.status(401).send("invalid signature");
// 4. Processar evento
const event = JSON.parse(rawBody);
switch (event.type) {
case "payment.succeeded":
console.log("Pagamento confirmado:", event.data.id);
break;
case "payment.failed":
console.log("Pagamento falhou:", event.data.id);
break;
}
// Responda 2xx rápido — trabalho pesado deve ir para uma fila
res.status(200).send("ok");
});
app.listen(3000);import os, hmac, hashlib, time, json
from flask import Flask, request, abort
app = Flask(__name__)
WEBHOOK_SECRET = os.environ["WEBHOOK_SECRET"].encode()
MAX_AGE = 5 * 60 # 5 minutos
@app.post("/webhooks/easyhost")
def handle_webhook():
signature = request.headers.get("X-Webhook-Signature", "")
timestamp = request.headers.get("X-Webhook-Timestamp", "")
raw_body = request.get_data() # bytes brutos
if not signature or not timestamp:
abort(400, "missing headers")
# 1. Proteção contra replay
if abs(int(time.time()) - int(timestamp)) > MAX_AGE:
abort(401, "timestamp too old")
# 2. Calcular assinatura esperada
signed_payload = f"{timestamp}.".encode() + raw_body
expected = hmac.new(WEBHOOK_SECRET, signed_payload, hashlib.sha256).hexdigest()
# 3. Comparação em tempo constante
if not hmac.compare_digest(signature, expected):
abort(401, "invalid signature")
# 4. Processar evento
event = json.loads(raw_body)
if event["type"] == "payment.succeeded":
print("Pagamento confirmado:", event["data"]["id"])
elif event["type"] == "payment.failed":
print("Pagamento falhou:", event["data"]["id"])
return "ok", 200✓ Boas práticas
Use o corpo bruto, comparação em tempo constante e responda 2xx em menos de 5s.
↻ Idempotência
Use X-Webhook-Id como chave para evitar processar o mesmo evento duas vezes.
⟳ Retries
Reenviamos até 5x com backoff exponencial caso a resposta não seja 2xx.
Códigos de Erro
#A API usa códigos de status HTTP padrão e retorna payloads de erro estruturados em JSON. Cada resposta de erro inclui um código legível por máquina, uma mensagem legível por humanos, o parâmetro relacionado (quando aplicável) e um ID único da requisição para rastreamento.
| Status | Descrição | Cenário típico |
|---|---|---|
| 400 | Bad Request | Payload malformado, campos obrigatórios ausentes ou tipos incorretos. |
| 401 | Unauthorized | API key ausente, inválida ou expirada. |
| 403 | Forbidden | API key válida, mas sem permissão para o recurso solicitado. |
| 404 | Not Found | Recurso inexistente (ex: pagamento, sessão ou cliente não encontrado). |
| 422 | Unprocessable Entity | Sintaxe válida, mas regra de negócio violada (ex: saldo insuficiente). |
| 429 | Too Many Requests | Limite de requisições excedido (rate limit). Aguarde e tente novamente. |
| 500 | Internal Server Error | Erro inesperado no servidor. Entre em contato com o suporte. |
| 502 | Bad Gateway | Provedor de pagamento externo indisponível ou resposta inválida. |
| 503 | Service Unavailable | Manutenção programada ou sobrecarga temporária da API. |
Estrutura padrão do erro
{
"error": {
"code": "invalid_request",
"message": "Descrição legível do erro",
"param": "amount",
"request_id": "req_7f8a9b2c3d4e"
}
}400 — Bad Request
{
"error": {
"code": "missing_parameter",
"message": "O campo 'amount' é obrigatório.",
"param": "amount",
"request_id": "req_9a8b7c6d5e4f"
}
}{
"error": {
"code": "invalid_parameter",
"message": "'currency' deve ser uma das opções suportadas: MZN, ZAR, USD.",
"param": "currency",
"request_id": "req_1a2b3c4d5e6f"
}
}401 — Unauthorized
{
"error": {
"code": "unauthorized",
"message": "API key ausente. Inclua o header Authorization: Bearer <token>.",
"param": "authorization",
"request_id": "req_2b3c4d5e6f7g"
}
}{
"error": {
"code": "invalid_api_key",
"message": "A API key fornecida não é válida ou foi revogada.",
"param": "authorization",
"request_id": "req_3c4d5e6f7g8h"
}
}403 — Forbidden
{
"error": {
"code": "insufficient_permissions",
"message": "Sua chave não tem permissão para acessar este recurso.",
"param": null,
"request_id": "req_4d5e6f7g8h9i"
}
}{
"error": {
"code": "ip_not_allowed",
"message": "Requisição bloqueada. O IP 102.130.61.x não está na whitelist.",
"param": null,
"request_id": "req_5e6f7g8h9i0j"
}
}404 — Not Found
{
"error": {
"code": "resource_not_found",
"message": "Pagamento 'pay_123456789' não encontrado.",
"param": "id",
"request_id": "req_6f7g8h9i0j1k"
}
}{
"error": {
"code": "endpoint_not_found",
"message": "O endpoint '/v1/unknown' não existe. Consulte a documentação.",
"param": null,
"request_id": "req_7g8h9i0j1k2l"
}
}422 — Unprocessable Entity
{
"error": {
"code": "amount_below_minimum",
"message": "O valor mínimo para M-Pesa é 10 MZN.",
"param": "amount",
"request_id": "req_8h9i0j1k2l3m"
}
}{
"error": {
"code": "provider_rejected",
"message": "A operadora M-Pesa recusou a transação (saldo insuficiente do cliente).",
"param": null,
"request_id": "req_9i0j1k2l3m4n"
}
}429 — Too Many Requests
{
"error": {
"code": "rate_limit_exceeded",
"message": "Limite de 100 requisições/min excedido. Tente novamente em 45s.",
"param": null,
"request_id": "req_0j1k2l3m4n5o",
"retry_after": 45
}
}500 — Internal Server Error
{
"error": {
"code": "internal_error",
"message": "Ocorreu um erro interno. Nossa equipe foi notificada automaticamente.",
"param": null,
"request_id": "req_1k2l3m4n5o6p"
}
}502 / 503 — Gateway / Unavailable
{
"error": {
"code": "provider_timeout",
"message": "Provedor M-Pesa não respondeu em tempo hábil. Tente novamente.",
"param": null,
"request_id": "req_2l3m4n5o6p7q"
}
}{
"error": {
"code": "service_unavailable",
"message": "API em manutenção programada. Previsão de retorno: 14h00 UTC.",
"param": null,
"request_id": "req_3m4n5o6p7q8r"
}
}💡 Dica de debugging
Sempre guarde o request_id retornado em erros 5xx. Ao abrir um ticket de suporte, inclua esse ID — ele permite que nossa equipe rastreie a requisição completa nos logs em segundos.
SDKs
#Exemplos prontos de integração em Node.js e Python. Todos usam automaticamente a Base URL do Supabase e o header Authorization com a API Key configurada acima.
Node.js (fetch nativo)
const BASE_URL = "https://mescwrzkwjwtyjouueqq.supabase.co/functions/v1";
const API_KEY = process.env.EASYHOST_API_KEY || "sk_live_your_key";
async function createPayment(body) {
const res = await fetch(`${BASE_URL}/payment-orchestrator`, {
method: "POST",
headers: {
"Authorization": `Bearer ${API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify(body),
});
if (!res.ok) throw new Error(`HTTP ${res.status}`);
return res.json();
}
async function createSession(body) {
const res = await fetch(`${BASE_URL}/payment-session`, {
method: "POST",
headers: {
"Authorization": `Bearer ${API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify(body),
});
if (!res.ok) throw new Error(`HTTP ${res.status}`);
return res.json();
}
async function getWalletBalance(currency = "MZN") {
const res = await fetch(`${BASE_URL}/wallet-balance?currency=${currency}`, {
method: "GET",
headers: {
"Authorization": `Bearer ${API_KEY}`,
"Accept": "application/json",
},
});
if (!res.ok) throw new Error(`HTTP ${res.status}`);
return res.json();
}
// Uso
(async () => {
const payment = await createPayment({
merchant_id: "mrc_887766",
wallet_id: "wlt_554433",
api_key: "sk_live_xxxxxx",
amount: 1500,
currency: "MZN",
payment_method: "mpesa",
customer: { name: "João Silva", phone: "258840000000" },
external_reference: "ORD-001",
});
console.log(payment.id, payment.status);
const balance = await getWalletBalance("MZN");
console.log(balance.wallets);
})();Python (requests)
import os
import requests
BASE_URL = "https://mescwrzkwjwtyjouueqq.supabase.co/functions/v1"
API_KEY = os.getenv("EASYHOST_API_KEY", "sk_live_your_key")
HEADERS = {
"Authorization": f"Bearer {API_KEY}",
"Content-Type": "application/json",
"Accept": "application/json",
}
def create_payment(body: dict) -> dict:
url = f"{BASE_URL}/payment-orchestrator"
r = requests.post(url, json=body, headers=HEADERS, timeout=30)
r.raise_for_status()
return r.json()
def create_session(body: dict) -> dict:
url = f"{BASE_URL}/payment-session"
r = requests.post(url, json=body, headers=HEADERS, timeout=30)
r.raise_for_status()
return r.json()
def get_wallet_balance(currency: str = "MZN") -> dict:
url = f"{BASE_URL}/wallet-balance"
params = {"currency": currency}
r = requests.get(url, headers=HEADERS, params=params, timeout=30)
r.raise_for_status()
return r.json()
# Uso
if __name__ == "__main__":
payment = create_payment({
"merchant_id": "mrc_887766",
"wallet_id": "wlt_554433",
"api_key": "sk_live_xxxxxx",
"amount": 1500,
"currency": "MZN",
"payment_method": "mpesa",
"customer": {"name": "João Silva", "phone": "258840000000"},
"external_reference": "ORD-001",
})
print(payment["id"], payment["status"])
balance = get_wallet_balance("MZN")
print(balance["wallets"])⚡ Instalação rápida
Node: nativo (fetch). Python: pip install requests.
✓ Variáveis de ambiente
Use EASYHOST_API_KEY para não hardcodear a chave. O fallback usa o valor do Console de Testes.
Clientes
#Gerencie o cadastro de clientes para automatizar cobranças recorrentes e manter um histórico detalhado.
curl -X POST https://mescwrzkwjwtyjouueqq.supabase.co/functions/v1/customers \
-H "Authorization: Bearer sk_live_your_key" \
-d '{
"merchant_id": "mrc_887766",
"wallet_id": "wlt_554433",
"api_key": "sk_live_xxxxxx",
"full_name": "Maria Santos",
"email": "maria@exemplo.com",
"phone": "258820000000"
}'Precisa de ajuda com a integração?
Nossa equipe de engenharia está pronta para ajudar você a colocar sua solução no ar em menos de 30 minutos.

