Pular para o conteúdo
MOONIPdocs
IntegraçãoManual
PTEN
Ir para o painel

SDKs oficiais

A Moonip publica clientes oficiais para Node.js, Python, PHP e .NET. Eles envolvem a mesma API REST /v1 descrita na Referência da API — tudo que dá para fazer com curl, dá para fazer sem SDK. O que os SDKs acrescentam é justamente a parte fácil de errar sem perceber: idempotência, política de retry e verificação de assinatura de webhook.

Os quatro compartilham uma versão só: 0.8.0.

LinguagemPacoteInstalaçãoRuntime
Node.js / TypeScript@moonip/nodenpm i @moonip/nodeNode 18+
Pythonmoonippip install moonipPython 3.8+
PHPmoonip/sdk-phpcomposer require moonip/sdk-phpPHP 8.1+
.NET / C#Moonipdotnet add package Moonipnetstandard2.0, net8.0

#O que os quatro garantem

Os quatro clientes são idênticos em comportamento, não só parecidos. A verificação de assinatura de webhook, em particular, roda contra um conjunto compartilhado de vetores de teste no CI — se o Node aceita uma assinatura, Python, PHP e .NET aceitam a mesma, byte a byte.

#Famílias de recursos

Todo cliente expõe as mesmas seis famílias de recursos — as mesmas rotas, os mesmos formatos de fio da Referência da API:

FamíliaNodePythonPHP.NET
Cobranças (/v1/charges)client.chargesclient.charges$client->chargesclient.Charges
Operações de pagamento (/v1/payments)client.paymentsclient.payments$client->paymentsclient.Payments
Saques (/v1/withdrawals)client.payoutsclient.payouts$client->payoutsclient.Payouts
Saldo (/v1/wallets)client.balanceclient.balance$client->balanceclient.Balance
Webhooks (/v1/webhooks)client.webhooks (incl. client.webhooks.endpoints)client.webhooks (incl. client.webhooks.endpoints)$client->webhooks (incl. $client->webhooks->endpoints)client.Webhooks (incl. client.Webhooks.Endpoints)
Casos MEDclient.medCasesclient.med_cases$client->medCasesclient.MedCases

Os nomes dos métodos seguem a convenção de cada linguagem (client.payments.create(input, { idempotencyKey }) em Node, client.payments.create(input, idempotency_key) em Python, $client->payments->create($input, $idempotencyKey) em PHP, client.Payments.CreateAsync(input, idempotencyKey) em .NET). payments.refund está ausente de propósito: a API responde 403 para toda requisição com chave de API — o error.code é "forbidden" e a mensagem começa com o marcador REFUND_ADMIN_ONLY (prefixo de mensagem, não um valor de code) — porque reembolsos vêm do painel administrativo.

#Autenticação

text
Authorization: Bearer ak_live_…

Os SDKs enviam o cabeçalho canônico Authorization: Bearer; o cabeçalho legado apikey: continua aceito pela API por compatibilidade. O ambiente (teste ou produção) vem da própria chave. Você nunca configura ambiente, e nenhum identificador de conta ou de lojista é passado ou devolvido.

#Idempotência é obrigatória na escrita financeira

Criar cobrança ou saque exige chave de idempotência. Os SDKs recusam a chamada sem ela, em vez de mandar torcendo.

Derive a chave do seu pedido (pedido-1234), nunca de um valor aleatório. Aleatório destrói o mecanismo inteiro: se a sua requisição chegou mas a resposta se perdeu, repetir com chave nova cria uma segunda cobrança; repetir com a mesma chave devolve a original.

#Política de retry

SituaçãoRepete?
GET / HEAD em 5xx ou erro de redesim
POST com chave de idempotênciasim — a mesma chave em toda tentativa
POST sem chave de idempotêncianunca
Qualquer 4xxnunca — o pedido está errado, repetir não conserta

O backoff é exponencial com jitter total, com teto de 8s.

A terceira linha é a que importa. Uma falha de rede não te diz se o servidor processou a requisição — só que resposta nenhuma voltou. Repetir uma escrita financeira sem chave em cima dessa ambiguidade é como um cliente é cobrado duas vezes.

#Início rápido

#Node.js

js
import { MoonipClient } from '@moonip/node';

const moonip = new MoonipClient({ apiKey: process.env.MOONIP_API_KEY });

const cobranca = await moonip.charges.create(
  {
    amount: 15000,                 // R$ 150,00 em centavos — sempre inteiro
    currency: 'BRL',
    payment_method: 'pix',
    customer: { name: 'Maria Silva', document: '12345678901' },
  },
  { idempotencyKey: `pedido-${pedidoId}` },
);

cobranca.pix.br_code;              // Pix Copia e Cola

#Python

python
import os
from moonip import MoonipClient

moonip = MoonipClient(api_key=os.environ["MOONIP_API_KEY"])

cobranca = moonip.charges.create(
    {
        "amount": 15000,
        "currency": "BRL",
        "payment_method": "pix",
        "customer": {"name": "Maria Silva", "document": "12345678901"},
    },
    idempotency_key=f"pedido-{pedido_id}",
)

cobranca["pix"]["br_code"]

O SDK Python não tem dependência de runtime — só a biblioteca padrão. Um SDK de pagamentos roda dentro do seu processo; cada pacote transitivo que ele trouxesse viraria superfície de supply chain que você herda de nós.

#PHP

php
<?php
require __DIR__ . '/vendor/autoload.php';

use Moonip\MoonipClient;

$cliente = new MoonipClient(['apiKey' => getenv('MOONIP_API_KEY')]);

$cobranca = $cliente->charges->create([
    'amount' => 15000,
    'currency' => 'BRL',
    'payment_method' => 'pix',
    'customer' => ['name' => 'Maria Silva', 'document' => '12345678901'],
], 'pedido-' . $pedidoId);

$cobranca['pix']['br_code'];

#C#

csharp
using Moonip;

// Registre como SINGLETON — é thread-safe e reaproveita o HttpClient.
// Um cliente por requisição esgota portas TCP, a armadilha clássica em .NET.
var moonip = new MoonipClient(Environment.GetEnvironmentVariable("MOONIP_API_KEY")!);

var cobranca = await moonip.Charges.CreateAsync(new
{
    amount = 15000,
    currency = "BRL",
    payment_method = "pix",
    customer = new { name = "Maria Silva", document = "12345678901" },
}, idempotencyKey: $"pedido-{pedidoId}");

var brCode = cobranca!.RootElement.GetProperty("pix").GetProperty("br_code").GetString();

#Verificando webhooks

A verificação não precisa de chave de API — instancie o utilitário sozinho.

js
// Node — Express com parser de corpo bruto
app.post('/webhooks/moonip', express.raw({ type: 'application/json' }), (req, res) => {
  if (!moonip.webhooks.verify(req.body, req.headers['x-moonip-signature'], segredo)) {
    return res.status(401).end();
  }
  const evento = JSON.parse(req.body.toString('utf8'));
  res.status(200).end();          // qualquer 2xx confirma a entrega
});
python
# Python — Flask
if not webhooks.verify(request.get_data(), request.headers.get("X-Moonip-Signature"), segredo):
    return "", 401
csharp
// C# — minimal API
if (!webhooks.Verify(corpo, req.Headers["X-Moonip-Signature"], segredo))
    return Results.Unauthorized();

Passe os bytes brutos. Não desserialize e re-serialize o corpo antes de verificar: qualquer diferença de espaço ou de ordem de chave muda o HMAC e a assinatura falha. É o bug de integração de webhook mais comum, em qualquer linguagem.

Assinaturas com mais de 5 minutos são recusadas por padrão, o que impede que um POST capturado uma vez seja reenviado para sempre. Veja Webhooks para o formato da assinatura e a agenda de retentativa.

#Erros

Todos os SDKs levantam erros tipados carregando status, code, type e request_id.

Tipo de falhaNodePythonPHPC#
401 / 403MoonipAuthErrorMoonipAuthErrorMoonipAuthErrorMoonipAuthException
400 / 422MoonipValidationErrorMoonipValidationErrorMoonipValidationErrorMoonipValidationException
409MoonipConflictErrorMoonipConflictErrorMoonipConflictErrorMoonipConflictException
Nenhuma respostaMoonipNetworkErrorMoonipNetworkErrorMoonipNetworkErrorMoonipNetworkException

Ramifique pelo code, nunca pela mensagem — mensagem é escrita para gente ler e muda sem aviso. O code é contrato; veja Erros para o catálogo. O único marcador de mensagem documentado é REFUND_ADMIN_ONLY (reembolsos são apenas no painel e respondem forbidden comum); combine-o como prefixo, não como valor de code.

O erro de rede não herda do erro de API em nenhum dos quatro, de propósito. Quando resposta nenhuma voltou, você não sabe se o servidor processou. Tratar os dois no mesmo ramo esconde exatamente a distinção que decide se repetir é seguro.

Cite o request_id ao falar com o suporte — ele localiza a requisição exata no nosso log.