Documentação da API

Receba e envie Pix pelo seu sistema: cobranças, consultas, saldo, transferências, saque cripto e webhooks.

Primeiros passos

Introdução #

A API da SafiPay é HTTP com JSON. Com ela o seu sistema gera cobranças Pix com QR Code, acompanha pagamentos, consulta o saldo, envia transferências Pix e saca em cripto para uma carteira.

Base URL https://www.safipaybr.com

Convenções

  • Envie o corpo em JSON com o header Content-Type: application/json.
  • Valores são em reais, como número com ponto decimal: 150.00 é R$ 150,00. Nas respostas os números vêm sem zeros à direita (150, 2.5).
  • Datas seguem ISO 8601 em UTC, como 2026-09-12T17:03:21.000Z.
  • Sucesso responde { "success": true, "data": { … } }. Erro responde { "error": "mensagem" } com o status HTTP correspondente. Alguns erros trazem também code, como IP_NOT_ALLOWED ou AMOUNT_BELOW_MINIMUM, para você tratar no código sem depender do texto.
  • IDs de transação começam com sfp_ (cobranças) ou sfp_out_ (transferências).

Mudanças recentes

Estas regras passaram a valer para todas as integrações. Confira se o seu sistema já atende a cada uma:

  • Credenciais só em header. ci e cs na URL são recusados com 400 e CREDENTIALS_IN_QUERY. Veja Autenticação.
  • Só chave de API em /api/gateway/*. A sessão do painel não vale nessas rotas: sem ci e cs, a resposta é 401 com API_KEY_REQUIRED.
  • Idempotency-Key recomendada em pix-create e pix-out: repetir a mesma chave devolve a resposta original, sem criar nada de novo. Com caractere fora do formato, 400 com IDEMPOTENCY_KEY_INVALID. Veja Idempotência.
  • Valores com até 2 casas decimais. amount precisa ser número com ponto decimal. "100abc", vírgula e 3 casas são recusados com INVALID_AMOUNT.
  • Copia e cola precisa ter valor. Em pix-out, código sem valor definido é recusado (BRCODE_DYNAMIC_NOT_ALLOWED), e o valor do código precisa ser igual a amount (BRCODE_AMOUNT_MISMATCH). Veja Transferência Pix.
  • Códigos de erro estáveis. Trate os erros pelo campo code. A lista completa está em Códigos de erro.
  • Taxa conforme a verificação da conta, com valor mínimo de cobrança por conta (AMOUNT_BELOW_MINIMUM). Veja Taxas.
  • Saque cripto pela API. crypto-withdraw envia USDT (rede BEP20) para uma carteira a partir do saldo em reais, com cotação e taxas em crypto-quote. Veja Saque cripto.
Primeiros passos

Autenticação #

Toda requisição leva as credenciais de uma chave de API em dois headers:

ciheaderobrigatório
Client ID da chave. Começa com ck_.
csheaderobrigatório
Client Secret da chave. Começa com cs_.

Os nomes X-Client-Id e X-Client-Secret também são aceitos. Crie e revogue chaves em API Keys. O Client Secret aparece uma única vez, na criação, porque a SafiPay guarda só um hash dele. Uma chave revogada para de funcionar na hora.

  • Só em header. Credenciais na URL, como ?ci=…&cs=…, são recusadas com 400 e "code": "CREDENTIALS_IN_QUERY", sem executar a operação. Endereços ficam gravados em logs e proxies: se o Client Secret já apareceu numa URL, troque a chave.
  • Só chave de API. Os endpoints /api/gateway/* não aceitam a sessão do painel. Sem ci e cs, a resposta é 401 com "code": "API_KEY_REQUIRED", mesmo com login ativo no navegador.
Chame a API só do seu servidor. Com o Client Secret dá para gerar cobranças e enviar transferências da sua conta. Nunca coloque as credenciais no site, no app ou no repositório.

Os exemplos desta página leem as credenciais das variáveis de ambiente SAFIPAY_CLIENT_ID e SAFIPAY_CLIENT_SECRET. Para testar a sua chave, consulte o saldo:

IPs permitidos

Cada chave pode ter uma lista de IPs permitidos, em API Keys (Configurar › IPs permitidos). Com a lista vazia, que é o padrão, a chave aceita chamadas de qualquer IP. Com pelo menos um item, só os IPs da lista conseguem usá-la.

  • Aceita IPv4 (177.71.200.14), IPv6 (2804:14c:5b73::1) e faixas CIDR (189.40.88.0/24, 2804:14c:5b73:8a10::/64), até 50 itens por chave.
  • Vale o IP público de onde a chamada chega à SafiPay. Se o seu servidor sai para a internet por proxy, NAT ou balanceador, libere o IP de saída, não o IP interno.
  • A regra vale para todos os endpoints chamados com a chave. O painel e o checkout não passam por ela.

Uma chamada de IP fora da lista é recusada com 403 e o código IP_NOT_ALLOWED, sem gerar cobrança nem mexer no saldo. As credenciais são conferidas antes do IP: com ci ou cs errados, a resposta continua 401. A mensagem traz o IP que a SafiPay recebeu (IPv4 aparece como IPv4, mesmo vindo por IPv6), o que ajuda a descobrir qual liberar:

Erros de autenticação

StatusMensagemQuando acontece
400Credenciais não são aceitas na URL. Envie ci e cs só nos headers e troque o client secret se ele já apareceu em alguma URL.ci ou cs enviados na query string. O corpo traz "code": "CREDENTIALS_IN_QUERY".
401Credenciais inválidas.O par ci/cs não confere, a chave foi revogada ou a conta não está ativa.
401Esta rota exige chave de API: envie os headers ci e cs. A sessão do painel não é aceita aqui.Faltou enviar ci ou cs. O corpo traz "code": "API_KEY_REQUIRED".
403IP não autorizado (203.0.113.50).A chave tem lista de IPs permitidos e a chamada veio de outro IP. O corpo traz "code": "IP_NOT_ALLOWED".
Primeiros passos

Idempotência #

Conexões caem. Para você repetir uma requisição sem gerar cobrança ou transferência em dobro, pix-create, pix-out e crypto-withdraw são idempotentes quando recebem uma chave por operação.

Idempotency-Keyheaderrecomendado
Identificador único da operação, de 1 a 128 caracteres. Só letras, números, :, _ e -: qualquer outro caractere, inclusive espaço e ponto, devolve 400 com IDEMPOTENCY_KEY_INVALID. Também aceito como X-Idempotency-Key. Opcional, mas recomendado em pix-create e principalmente em pix-out: protege contra cobrança ou transferência em dobro quando a sua requisição é repetida depois de um timeout.

Como funciona

SituaçãoResultado
Sem o headerA operação roda normalmente, mas sem proteção contra repetição: nada fica guardado e, se você reenviar a mesma requisição, mesmo com o corpo idêntico, uma nova cobrança ou transferência é criada.
Chave fora do formato400 "code": "IDEMPOTENCY_KEY_INVALID". Nada é criado nem debitado.
Primeira requisição com a chaveExecuta e guarda o status e o corpo da resposta. Erros em que nada foi criado nem debitado, como dados inválidos, não ficam guardados.
Mesma chave e mesmo corpoDevolve a resposta guardada, sem executar de novo.
Mesma chave, corpo diferente409 Idempotency-Key reutilizada com body diferente.
Mesma chave enquanto a primeira ainda roda409 Requisição idêntica em processamento. Tente novamente em instantes.
Chave de uma transferência usada em outra409 "code": "IDEMPOTENCY_KEY_ALREADY_USED". Consulte a transferência original antes de repetir.
Registro de idempotência indisponível503 "code": "IDEMPOTENCY_UNAVAILABLE". Nada foi executado: repita em instantes com a mesma chave.

As chaves valem por conta e por endpoint durante 48 horas, contadas da primeira requisição. Depois disso a chave é ignorada e repetir cria uma operação nova; em pix-out e crypto-withdraw, a chave de uma transferência já feita continua recusada com 409 e IDEMPOTENCY_KEY_ALREADY_USED. O corpo é comparado como JSON serializado: mesmos campos, mesmos valores e na mesma ordem.

Uma chave por operação. Use o ID do pedido ou do repasse, ou gere um UUID na hora de criar a operação e guarde junto dela. Duas cobranças diferentes nunca devem usar a mesma chave: a segunda receberia a resposta da primeira.

Repetir com segurança

  • Não recebeu resposta (timeout, queda de rede): repita com a mesma chave e o mesmo corpo. Se a primeira chegou a ser processada, você recebe a resposta original.
  • Recebeu um erro e corrigiu os dados: o corpo mudou, então use uma chave nova.
  • Quer tentar de novo o mesmo pedido depois de um erro (por exemplo, 502): use uma chave nova, porque a resposta de erro também fica guardada.
Primeiros passos

Taxas #

A taxa depende da verificação da conta. Enquanto a conta não é verificada, vale a taxa padrão de conta não verificada. Depois da aprovação em Verificação, passam a valer as taxas da sua conta. A regra é a mesma para cobranças pela API, checkout hospedado, cobranças do painel e transferências.

ContaPix recebidoTransferência
Não verificada10% + R$ 1,00R$ 2,00
VerificadaTaxa da sua contaTaxa da sua conta
Cobrança acima de R$ 1.000,00 (qualquer conta)10% + R$ 1,00—

O saque cripto tem taxa própria, igual para qualquer conta: veja Saque cripto › Taxas.

O que usar no seu sistema

  • fee e netAmount da resposta são a fonte da verdade. Grave os valores devolvidos por pix-create, pix-status, pix-out e pelo webhook. Não recalcule a taxa: ela muda quando a conta é verificada.
  • A taxa de cada operação é definida quando ela é criada. Uma cobrança gerada antes da aprovação mantém a taxa com que foi criada, mesmo que seja paga depois.
  • Cobranças acima de R$ 1.000,00 (até R$ 5.000,00) pagam 10% + R$ 1,00, com a conta verificada ou não. Até R$ 1.000,00 vale a taxa da conta.
  • Cada conta tem um valor mínimo de cobrança: o menor valor que deixa pelo menos R$ 0,01 depois da taxa, nunca abaixo de R$ 1,00. Com a taxa de conta não verificada, o mínimo é R$ 1,13.

Valor abaixo do mínimo

Uma cobrança abaixo do mínimo da conta é recusada com 400 e "code": "AMOUNT_BELOW_MINIMUM". O campo minAmount traz o mínimo atual, em reais. Nada é criado.

Endpoints

Criar cobrança Pix #

POST/api/gateway/pix-create

Gera uma cobrança Pix com QR Code e código copia e cola. A cobrança nasce com status pending e expira em 30 minutos (veja expiresAt).

Corpo

amountnumberobrigatório
Valor em reais, até 5000.00, como número com ponto decimal e no máximo 2 casas (150.00). "100abc", vírgula (150,00) e 3 casas são recusados com INVALID_AMOUNT. O mínimo é o da conta, a partir de 1.00, e depende da taxa: veja Taxas.
descriptionstringopcional
Descrição da cobrança, até 180 caracteres.
payerNamestringopcional
Nome do pagador, até 120 caracteres.
payerDocumentstringopcional
CPF ou CNPJ do pagador, com ou sem pontuação. Os dígitos verificadores são conferidos.
externalReferencestringopcional
Seu identificador, como o número do pedido. Até 120 caracteres. Fica gravado na transação e aparece no painel.

Campos de texto passam por limpeza antes de gravar: tags HTML são removidas e o que passar do limite é cortado.

Taxa

A taxa sai do valor recebido e depende da verificação da conta (veja Taxas). A conta é fee = amount × percentual ÷ 100, arredondado ao centavo, + valor fixo, e netAmount = amount − fee. Use sempre fee e netAmount da resposta: são os valores que valem para a cobrança.

A sua taxa aparece em Configurações.
201Cobrança criada
transactionIdstring
ID da cobrança. Guarde junto do seu pedido.
amount · fee · netAmountnumber
Valor cobrado, taxa e valor líquido que entra no saldo quando for pago.
statusstring
Sempre pending na criação.
qrCodeBase64string
Imagem PNG do QR Code em base64, com ou sem o prefixo data:image/png;base64,. Pode vir null: nesse caso, gere o QR Code a partir de copyPaste.
copyPastestring
Código Pix copia e cola.
expiresAtstring
Quando a cobrança expira.
paymentLinkstring | null
Página de pagamento desta cobrança, para enviar ao cliente. Veja Link de pagamento. Pode vir null; nesse caso, mostre o QR Code e o copia e cola.

Erros

StatusMensagemQuando acontece
400Valor inválido. Envie amount em reais, com até 2 casas decimais (ex.: 150.00).amount ausente, com texto, vírgula ou mais de 2 casas. "code": "INVALID_AMOUNT".
400Valor mínimo para esta conta: R$ 1,13.amount abaixo do mínimo da conta. O corpo traz "code": "AMOUNT_BELOW_MINIMUM" e minAmount. Veja Taxas.
400Valor máximo R$ 5000,00 por cobrança.amount acima de 5000.
400CPF/CNPJ do pagador inválido.payerDocument sem 11 ou 14 dígitos ou com dígito verificador errado.
400Mensagem de idempotênciaA Idempotency-Key tem caracteres fora do formato (IDEMPOTENCY_KEY_INVALID).
429Mensagem de limite de requisiçõesMuitas cobranças seguidas. "code": "RATE_LIMITED"; espere os segundos do header Retry-After.
409Mensagens de idempotênciaChave reutilizada com outro corpo ou requisição idêntica em andamento.
502Não foi possível gerar a cobrança agora. Tente novamente em instantes.O Pix não foi gerado. Tente de novo com uma nova Idempotency-Key.
503Serviço de pagamento temporariamente indisponível. Tente novamente em instantes."code": "ACQUIRER_UNAVAILABLE". Nada foi criado; tente de novo em instantes.
500Erro ao registrar transação.Falha ao gravar a cobrança. Tente de novo com uma nova chave.
Endpoints

Consultar cobrança #

GET/api/gateway/pix-status?transactionId={id}

Devolve o status atual da cobrança. Se ela ainda estiver pending, a SafiPay confere o pagamento antes de responder. Se o pagamento já tiver entrado, o saldo é creditado e o webhook pix.paid é disparado nesse momento. A conferência tem um limite por conta (algumas por minuto, no máximo uma a cada 5 segundos por cobrança): acima dele a resposta traz o último status conhecido, sem erro. Até 120 consultas por minuto por conta; acima disso, 429 com RATE_LIMITED e Retry-After. Para acompanhar pagamentos, prefira o webhook.

Parâmetros de consulta

transactionIdstringobrigatório
ID recebido na criação (sfp_…).
200Status da cobrança
statusstring
pending, paid, expired, failed ou refunded. Veja Status das transações.
payerNamestring | null
Nome informado na criação ou, depois do pagamento, o nome de quem pagou o Pix.
qrCodeBase64string | null
Pode vir null, inclusive em cobranças que tinham a imagem na criação. Nesse caso, gere o QR Code a partir de copyPaste, que sempre vem enquanto a cobrança está pendente.
paidAtstring | null
Momento do pagamento. Pode vir null na mesma resposta em que o status acabou de mudar para paid; aparece nas consultas seguintes e no webhook.
createdAtstring
Criação da cobrança.
paymentLinkstring | null
O mesmo link devolvido na criação. Os demais campos também são os mesmos da criação.

O endpoint também aceita o ID de uma transferência (sfp_out_…). Nesse caso o status vem do registro da transferência na SafiPay. Num saque cripto, a resposta traz também "type": "pix_out", "method": "crypto" e o objeto crypto (moeda, rede, endereço mascarado e estimativa).

Erros

StatusMensagemQuando acontece
400transactionId obrigatório.Faltou o parâmetro transactionId.
404Transação não encontrada.O ID não existe ou é de outra conta.
Endpoints

Saldo #

GET/api/gateway/balance

Saldo da conta e totais de movimentação, em reais. balance é o que está disponível agora: já desconta as taxas e o que está reservado por transferências em andamento, porque valor e taxa da transferência saem do saldo no momento do pedido.

Parâmetros de consulta

fromstringopcional
Início do período, incluído. Data AAAA-MM-DD (meia-noite no horário de Brasília) ou data e hora em ISO 8601.
tostringopcional
Fim do período, não incluído. Mesmo formato de from.

Sem from e to, os totais cobrem todo o histórico da conta; com eles, só o período. Para setembro inteiro, use from=2026-09-01 e to=2026-10-01. balance e blockedBalance não dependem do período: são sempre o valor do momento. Data em formato inválido responde 400.

200Saldo e totais
balancenumber
Saldo disponível para transferir.
blockedBalancenumber
Reservado por transferências ainda pendentes (valor + taxa). Já está fora de balance e ignora from/to.
currencystring
Sempre BRL.
totalReceivednumber
Soma do valor das cobranças pagas.
totalReceivedNetnumber
O mesmo, descontada a taxa de cada cobrança. É o que entrou no saldo.
totalWithdrawnnumber
Soma do valor das transferências concluídas, sem a taxa.
totalFeesnumber
Taxas de cobranças pagas e de transferências concluídas.
transactionsCountnumber
Quantidade de transações, entre cobranças e transferências, em qualquer status.
pendingPixInCountnumber
Cobranças aguardando pagamento que ainda não venceram.
updatedAtstring
Hora em que os números foram calculados. Ficam em cache por até 10 segundos por conta: consultas seguidas nesse intervalo recebem o mesmo resultado, com o mesmo updatedAt.

balance e currency continuam iguais aos de antes. Integrações que só leem esses dois campos não precisam mudar nada.

Endpoints

Transferência Pix #

POST/api/gateway/pix-out

Envia um Pix a partir do seu saldo, para uma chave Pix ou pagando um código copia e cola.

Chave Pix "mode": "key"

Informe pixKey e pixKeyType.

Copia e cola "mode": "brcode"

Informe o código completo em brCode, com o valor preenchido.

Sem mode, a SafiPay usa brcode quando o corpo tem brCode e key nos outros casos.

Corpo

amountnumberobrigatório
Valor em reais, a partir de 1.00. Obrigatório também no modo copia e cola.
modestringopcional
key ou brcode.
pixKeystringmodo key
Chave Pix de destino, no formato da tabela abaixo.
pixKeyTypestringmodo key
CPF, CNPJ, EMAIL, TELEFONE ou CHAVE_ALEATORIA. Maiúsculas ou minúsculas.
brCodestringmodo brcode
Código Pix copia e cola completo, com valor definido e igual a amount. Também aceito como copyPaste ou pixCopyPaste, desde que mode seja brcode.
descriptionstringopcional
Descrição, até 180 caracteres.
externalReferencestringopcional
Seu identificador, até 120 caracteres.

Tipos de chave

pixKeyTypeO que aceitaEnviada como
CPF11 dígitos, com ou sem pontuação. Dígitos verificadores conferidos.123.456.789-09
CNPJ14 dígitos, com ou sem pontuação. Dígitos verificadores conferidos.12.345.678/0001-95
EMAILEndereço de e-mail válido.Em minúsculas
TELEFONEDDD + número (10 ou 11 dígitos), com ou sem +55.+5511987654321
CHAVE_ALEATORIAUUID: 32 caracteres hexadecimais, com ou sem hífens.6f1b2c3d-4e5f-4a6b-8c7d-9e0f1a2b3c4d

No modo copia e cola, o código precisa começar com 0002 e terminar com o CRC (6304 + 4 caracteres), que é conferido. Quebras de linha e caracteres invisíveis colados junto são removidos.

O código precisa trazer o valor. A SafiPay lê o valor gravado no código (campo 54) e confere com amount, centavo a centavo. Código sem valor definido, como o de cobranças em que quem paga digita o valor, é recusado com 400 e BRCODE_DYNAMIC_NOT_ALLOWED. Valor diferente de amount é recusado com BRCODE_AMOUNT_MISMATCH, que traz o valor do código em brCodeAmount. Nos dois casos nada é debitado.

Taxa, saldo e limites

  • Cada transferência tem uma taxa fixa, que depende da verificação da conta (veja Taxas). O saldo precisa cobrir valor + taxa, e os dois saem do saldo no momento do pedido. fee e totalDebited da resposta são os valores debitados.
  • A sua conta pode ter limite por transferência e limite diário (veja em Configurações). O limite diário soma o valor das transferências pendentes e concluídas desde 00:00, no horário de Brasília. A taxa e as transferências que falharam não entram na conta.
  • Até 10 transferências por minuto e 60 por hora pela API, e no máximo 20 pedidos de transferência por hora por conta, somando painel, API e saque cripto. Acima disso, 429 com RATE_LIMITED e o header Retry-After.

Respostas

201Transferência enviada

O pedido foi aceito para envio. O status fica pending e o resultado final chega pelo webhook pixout.paid ou pixout.failed. Se falhar depois, valor e taxa voltam ao saldo.

202Envio ambíguo

O envio não teve confirmação conclusiva (instabilidade ou tempo esgotado), então ainda não dá para saber se o Pix saiu. O valor continua debitado e a transferência fica pending até a confirmação. Não repita com outra Idempotency-Key: isso pode pagar duas vezes.

400Transferência recusada

O envio foi recusado (por exemplo, chave Pix inexistente). O corpo traz "code": "PIX_OUT_REFUSED" e a mensagem em error. A transferência é marcada como failed e valor + taxa voltam ao saldo na hora.

Erros

StatusMensagemQuando acontece
400Valor mínimo R$ 1,00.amount menor que 1.
400Valor inválido. Envie amount em reais, com até 2 casas decimais (ex.: 150.00).amount ausente, com texto, vírgula ou mais de 2 casas. "code": "INVALID_AMOUNT".
400Chave PIX obrigatória.Modo key sem pixKey.
400Tipo de chave PIX inválido.pixKeyType ausente ou fora da lista.
400CPF inválido. CNPJ inválido. Email inválido. Telefone inválido. Use DDD + número. Chave aleatória inválida (UUID).A chave não bate com o tipo informado.
400Código PIX copia-e-cola inválido (CRC ou formato).Modo brcode com código incompleto ou CRC errado. "code": "BRCODE_INVALID".
400Este código Pix não tem valor definido. Peça ao recebedor um código com valor ou use a chave Pix."code": "BRCODE_DYNAMIC_NOT_ALLOWED".
400O valor informado (R$ 50,00) é diferente do valor do código Pix (R$ 89,90)."code": "BRCODE_AMOUNT_MISMATCH", com brCodeAmount.
400Valor acima do limite por saque (R$ 1000.00).Passou do limite por transferência da conta.
400Limite diário de saques atingido (usado R$ 1350.40 de R$ 20000.00).A soma do dia passaria do limite diário.
400Saldo insuficiente. Disponível: R$ 80.00O saldo não cobre valor + taxa.
400Limite diário de transferências para conta não verificada atingido (usado R$ 500,00 de R$ 500,00). Conclua a verificação em /verificacao.Limite diário da conta não verificada. "code": "UNVERIFIED_DAILY_LIMIT", com used, limit e verificationUrl.
400Não foi possível reservar saldo.A reserva foi recusada por outro motivo.
403Transferências bloqueadas para revisão de segurança da conta. Fale com o suporte."code": "WITHDRAWALS_BLOCKED".
403Saldo negativo por devolução de Pix recebido. Transferências ficam bloqueadas até a revisão da conta. Fale com o suporte."code": "NEGATIVE_BALANCE".
400Não foi possível concluir a transferência. Confira os dados do Pix e tente novamente. Valor e taxa já voltaram ao saldo.Envio recusado. "code": "PIX_OUT_REFUSED". Valor e taxa já voltaram ao saldo.
400Mensagem de idempotênciaA Idempotency-Key tem caracteres fora do formato (IDEMPOTENCY_KEY_INVALID). Nada é debitado.
409Esta Idempotency-Key já foi usada em outra transferência. Consulte o status dela antes de repetir."code": "IDEMPOTENCY_KEY_ALREADY_USED".
429Mensagem de limite de requisiçõesMuitas transferências seguidas, ou o limite de 20 por hora da conta (painel, API e cripto somados). "code": "RATE_LIMITED"; espere os segundos do header Retry-After.
503Serviço de pagamento temporariamente indisponível. Nada foi debitado; tente novamente em instantes."code": "ACQUIRER_UNAVAILABLE". Consulte o Extrato antes de repetir.
409Mensagens de idempotênciaChave reutilizada com outro corpo ou requisição idêntica em andamento.
500Falha ao reservar saldo.Erro ao reservar. Nada foi debitado; tente de novo com uma nova chave.

Os valores nas mensagens de limite e saldo são exemplos: a mensagem real traz os números da sua conta.

Endpoints

Saque cripto #

POST/api/gateway/crypto-withdraw
GET/api/gateway/crypto-quote?amount={valor}&network=BEP20

Saca do seu saldo em cripto, direto para uma carteira. Você informa o valor em reais: o saldo é debitado em reais, o valor é convertido para USDT e enviado na rede escolhida. As mesmas regras valem para o saque cripto feito no painel, em Transferir.

Transferências cripto não podem ser desfeitas. Confira a rede e o endereço antes de enviar. Um envio para um endereço errado, ou para uma carteira de outra rede, não pode ser recuperado pela SafiPay.

Moedas e redes

coinnetworkEndereço
USDTBEP20 (BNB Smart Chain)0x seguido de 40 caracteres hexadecimais (42 no total), como 0x5aAeb6053F3E94C9b9A09f33669435E7Ef1BeAed.
  • Hoje a única opção é USDT na rede BEP20. Outra rede (TRC20, ERC20, Polygon) ou outra moeda é recusada com 400 e CRYPTO_NETWORK_INVALID.
  • Endereço com letras maiúsculas e minúsculas misturadas precisa conferir com o checksum do endereço (EIP-55); um caractere trocado é recusado com CRYPTO_ADDRESS_INVALID. Endereço todo em minúsculas também é aceito.
  • Espaços, quebras de linha e caracteres invisíveis colados junto com o endereço são removidos. O endereço 0x000…000 é recusado.

Corpo

amountnumberobrigatório
Valor em reais, de 24.00 a 3000.00, dentro do limite por transferência da sua conta. É o valor convertido; a taxa SafiPay é debitada à parte.
networkstringobrigatório
BEP20.
coinstringopcional
USDT. Se enviado, precisa ser a moeda da rede.
addressstringobrigatório
Endereço da carteira que vai receber, no formato da rede.
descriptionstringopcional
Descrição, até 180 caracteres. Fica só na SafiPay.
externalReferencestringopcional
Seu identificador, até 120 caracteres.

Envie Idempotency-Key como em pix-out (veja Idempotência): repetir a mesma chave e o mesmo corpo devolve a resposta original sem enviar de novo.

Taxas

  • Taxa SafiPay: R$ 2,00 por saque cripto, debitada do saldo junto com o valor. Vem em fee. A taxa de transferência Pix não é cobrada no saque cripto.
  • Taxa de conversão: 5% sobre o valor convertido, paga de dentro do valor da transferência.
  • Taxa da rede: R$ 3,00, paga de dentro do valor da transferência.
  • Convertido = valor − taxa de conversão − taxa da rede. Como os 5% incidem sobre o convertido, e não sobre o valor inteiro, a taxa de conversão de uma transferência de R$ 100,00 é R$ 4,62, não R$ 5,00. Vem em convertedAmount.
  • Total debitado = valor + taxa SafiPay. Vem em totalDebited.
  • Valor estimado recebido = convertido ÷ cotação, arredondado para baixo, em USDT. É uma estimativa: o valor final usa a cotação do momento do processamento.
Exemplo com R$ 100,00 e cotação de R$ 5,25 por USDTValor
Valor da transferênciaR$ 100,00
Taxa SafiPay+ R$ 2,00
Total debitado do saldoR$ 102,00
Taxa de conversão (5% de R$ 92,38)− R$ 4,62
Taxa da rede− R$ 3,00
ConvertidoR$ 92,38
Valor estimado recebido≈ 17,59 USDT

As taxas da conversão e da rede podem mudar. Consulte crypto-quote antes de enviar e grave fee, totalDebited e crypto da resposta em vez de recalcular.

Saldo e limites

  • O saldo precisa cobrir valor + taxa SafiPay; os dois saem do saldo no momento do pedido.
  • Valor de R$ 24,00 a R$ 3.000,00 por saque, e até o limite por transferência da sua conta (padrão R$ 1.000,00, veja em Configurações).
  • O limite diário da conta vale para Pix e cripto juntos: soma o valor das transferências pendentes e concluídas desde 00:00, no horário de Brasília.
  • Até 3 saques cripto por minuto e 20 por hora por conta, somando todas as chaves, dentro do limite de 20 pedidos de transferência por hora da conta (Pix e cripto, painel e API). Acima disso, 429 com RATE_LIMITED e o header Retry-After.
  • Com as transferências pausadas pela SafiPay, o pedido é recusado com 503 e WITHDRAWALS_PAUSED, sem debitar.

Respostas

201Saque cripto enviado

O pedido foi aceito. O status fica pending enquanto a conversão e o envio na rede acontecem, o que costuma levar alguns minutos. O resultado final chega pelo webhook pixout.paid ou pixout.failed. Se falhar, valor e taxa voltam ao saldo.

202Envio ambíguo

O envio não teve confirmação conclusiva, então ainda não dá para saber se saiu. O valor continua debitado e o saque fica pending até a confirmação. Não repita com outra Idempotency-Key: um saque cripto enviado duas vezes não pode ser desfeito.

400Saque recusado

O envio foi recusado antes de sair. O corpo traz "code": "CRYPTO_OUT_REFUSED", o saque é marcado como failed e valor + taxa voltam ao saldo na hora.

crypto.address vem sempre mascarado nas respostas, na consulta e no webhook. crypto.estimatedAmount e crypto.rate podem vir null quando não há cotação disponível no momento do pedido.

Cotação e taxas

GET /api/gateway/crypto-quote devolve as redes aceitas, os limites, as taxas e a estimativa para um valor, calculada pela SafiPay. Não debita nada. Até 30 consultas por minuto por conta.

amountnumberopcional
Valor em reais para a estimativa. Sem ele, estimate vem null.
networkstringopcional
BEP20 (padrão).

maxAmount já considera o limite por transferência da sua conta. Sem cotação no momento, rate, quotedAt e estimate.estimatedAmount vêm null: a conversão usa a cotação do momento do processamento.

Status e webhook

O saque cripto é uma transferência ("type": "pix_out", ID sfp_out_…): segue os status de transferência, aparece no Extrato e é consultado em pix-status. Os webhooks são os mesmos da transferência Pix, pixout.paid e pixout.failed, com data.method igual a crypto e o objeto data.crypto.

Erros

StatusMensagemQuando acontece
400Valor inválido. Envie amount em reais, com até 2 casas decimais (ex.: 150.00).amount ausente, com texto, vírgula ou mais de 2 casas. "code": "INVALID_AMOUNT".
400Valor mínimo para transferência cripto: R$ 24,00."code": "CRYPTO_AMOUNT_BELOW_MINIMUM", com minAmount.
400Valor máximo por transferência cripto: R$ 3.000,00."code": "CRYPTO_AMOUNT_ABOVE_MAXIMUM", com maxAmount.
400Moeda ou rede inválida. Hoje a transferência cripto aceita USDT na rede BEP20.network ausente ou fora da lista, ou coin diferente da moeda da rede. "code": "CRYPTO_NETWORK_INVALID".
400Endereço inválido para a rede BEP20. Ele começa com 0x e tem 42 caracteres. Endereço com letras maiúsculas e minúsculas trocadas. Copie o endereço de novo direto da carteira. Informe o endereço da carteira que vai receber.Endereço fora do formato da rede, com checksum errado ou ausente. "code": "CRYPTO_ADDRESS_INVALID".
400Valor acima do limite por saque (R$ 1000.00).Passou do limite por transferência da conta.
400Limite diário de saques atingido (usado R$ 1350.40 de R$ 20000.00).A soma do dia (Pix e cripto) passaria do limite diário.
400Saldo insuficiente. Disponível: R$ 80.00O saldo não cobre valor + taxa SafiPay.
400Limite diário de transferências para conta não verificada atingido (usado R$ 500,00 de R$ 500,00). Conclua a verificação em /verificacao."code": "UNVERIFIED_DAILY_LIMIT".
400Não foi possível concluir a transferência agora. Nada foi enviado e o valor com a taxa já voltou ao saldo.Envio recusado. "code": "CRYPTO_OUT_REFUSED". Valor e taxa já voltaram ao saldo.
400Mensagem de idempotênciaIdempotency-Key fora do formato (IDEMPOTENCY_KEY_INVALID) ou obrigatória e ausente (IDEMPOTENCY_KEY_REQUIRED). Nada é debitado.
401 403Mensagens de autenticaçãoCredenciais ausentes ou inválidas, ou IP fora da lista da chave.
403Transferências bloqueadas para revisão de segurança da conta. Fale com o suporte."code": "WITHDRAWALS_BLOCKED" (ou NEGATIVE_BALANCE).
409Esta Idempotency-Key já foi usada em outra transferência. Consulte o status dela antes de repetir."code": "IDEMPOTENCY_KEY_ALREADY_USED".
409Mensagens de idempotênciaChave reutilizada com outro corpo ou requisição idêntica em andamento.
429Muitas transferências cripto seguidas nesta conta. Tente novamente em 42s. Limite de transferências cripto por hora atingido. Tente novamente em 1800s.Mais de 3 saques cripto por minuto, 20 por hora, ou o limite de 20 transferências por hora da conta. "code": "RATE_LIMITED"; espere os segundos do header Retry-After.
500Falha ao reservar saldo.Erro ao reservar. Confira o Extrato antes de repetir com uma nova chave.
503Saque cripto indisponível no momento. Nada foi debitado; tente novamente mais tarde."code": "CRYPTO_WITHDRAWAL_UNAVAILABLE". Vale também para crypto-quote.
503Transferências temporariamente indisponíveis. Nada foi debitado; tente novamente em instantes."code": "WITHDRAWALS_PAUSED".
503Serviço de pagamento temporariamente indisponível. Nada foi debitado; tente novamente em instantes."code": "ACQUIRER_UNAVAILABLE". Consulte o Extrato antes de repetir.

Os valores nas mensagens de limite e saldo são exemplos: a mensagem real traz os números da sua conta.

Notificações

Webhooks #

Com uma URL cadastrada, a SafiPay faz um POST no seu servidor quando uma transação muda de status. A URL da conta fica em Webhooks. Cada chave de API pode ter URL e segredo próprios, em API Keys.

Configuração

  • A URL precisa ser HTTPS, num domínio público e sem usuário e senha. URLs que apontam ou resolvem para localhost, rede privada ou endereços reservados são recusadas ao salvar e conferidas de novo a cada entrega. A regra vale para a URL da conta e para a de cada chave.
  • Trocar ou remover uma URL, da conta ou de uma chave, exige a senha da conta.
  • O segredo da conta, com 64 caracteres hexadecimais, fica em Webhooks. O segredo de uma chave começa com whsec_ e é gerado quando você cadastra a primeira URL da chave; você vê e troca em API Keys, confirmando com a senha.

Conta ou chave: para onde vai o aviso

TransaçãoURLSegredo
Criada pela API com uma chave que tem URL própriaDa chaveDa chave
Criada com uma chave sem URL própria, pelo painel ou pelo checkoutDa contaDa conta
  • Vale para cobranças e transferências, no envio automático, nos reenvios automático e manual e na rotina de conciliação.
  • Com uma URL por chave, cada sistema recebe só os avisos das transações criadas com a chave dele. Valide a assinatura com o segredo da mesma chave.
  • Transações criadas com uma chave que depois foi revogada continuam avisando a URL dessa chave, com o segredo dela.
  • O teste de uma chave, em API Keys, usa a URL e o segredo da chave. Sem URL própria, vai para o webhook da conta.

Eventos

EventoQuandoEnvio
pix.paidCobrança paga. O valor líquido já entrou no saldo.Sempre
pixout.paidTransferência concluída (Pix ou saque cripto).Sempre
pixout.failedTransferência falhou depois de aceita. Valor e taxa voltaram ao saldo.Sempre
pix.expiredCobrança expirou sem pagamento.Opcional
pix.failedA cobrança falhou ou foi cancelada.Opcional
test.pingBotão de teste em Webhooks ou em API Keys.Teste

pix.expired e pix.failed são enviados quando a opção Enviar cobranças expiradas e falhas está ligada em Webhooks. Contas criadas antes dessa opção começam com ela desligada, para não surpreender integrações que tratam qualquer aviso como pagamento; contas novas começam com ela ligada. Desligada, esses eventos só chegam quando você reenvia manualmente o webhook de uma cobrança nesse status.

Uma cobrança expirada ainda pode ser paga, se o pagamento for confirmado depois. Nesse caso chegam os dois avisos, primeiro pix.expired e depois pix.paid: não cancele um pedido de forma definitiva só pelo pix.expired.

Confira o evento antes de liberar um pedido. Libere só com event igual a pix.paid. Os eventos opcionais chegam no mesmo formato, com o status real e paidAt: null.

Corpo

eventstring
Nome do evento.
data.transactionIdstring
ID da transação (sfp_… ou sfp_out_…).
data.typestring
pix_in (cobrança) ou pix_out (transferência).
data.amount · data.fee · data.netAmountnumber
Valor, taxa e líquido. Em transferências, netAmount é igual a amount.
data.statusstring
Status da transação no envio.
data.payerName · data.payerDocumentstring | null
Dados do pagador, quando existem. null em transferências.
data.paidAtstring | null
Momento do pagamento ou da conclusão. null em pix.expired e pix.failed.
data.resendboolean
Só aparece, com true, em reenvios manuais.
data.method · data.cryptostring · object
Só em saque cripto: method igual a crypto e crypto com coin, network, address (mascarado), estimatedAmount, rate, conversionFee e networkFee.

No test.ping, data.clientId indica a chave testada, quando o teste é feito por uma chave em API Keys. O corpo chega compacto, sem quebras de linha; os exemplos estão formatados só para leitura.

Headers

HeaderValor
X-SafiPay-Signature-V2t=<unix>,v1=<hex>. v1 é o HMAC-SHA256 de t, um ponto e o corpo bruto, em hexadecimal minúsculo. É a assinatura recomendada.
X-SafiPay-TimestampO mesmo t da V2: momento do envio, em segundos Unix.
X-SafiPay-SignatureLegado: HMAC-SHA256 só do corpo bruto, em hexadecimal minúsculo. Continua sendo enviado.
X-SafiPay-EventNome do evento, igual a event.
X-SafiPay-DeliveryID único (UUID) desta tentativa. Muda a cada reenvio.
Content-Typeapplication/json
User-AgentSafiPay/1.0

As duas assinaturas usam o mesmo segredo: o da chave, quando o aviso vai para a URL da chave, ou o da conta. Cada tentativa, inclusive os reenvios, tem um t novo e por isso uma assinatura V2 nova; o corpo é sempre o mesmo.

Resposta esperada e reenvio

  • Responda com qualquer status 2xx em até 10 segundos. O corpo da sua resposta é ignorado.
  • Redirecionamentos (3xx) não são seguidos e contam como falha. Cadastre a URL final.
  • Outros status, erro de conexão, certificado inválido ou tempo esgotado contam como falha.
  • Eventos automáticos que falham entram na fila de reenvio: até 6 tentativas no total, com intervalos mínimos de 1 min, 5 min, 30 min, 2 h e 12 h. A fila é processada por uma rotina agendada, então o reenvio pode demorar mais que o intervalo.
  • O reenvio usa o mesmo corpo da primeira tentativa, com assinatura e t novos. Se a transação mudou de status desde a falha, o evento antigo não é reenviado. Quando uma tentativa é entregue, as pendentes do mesmo evento são canceladas.
  • O teste e o reenvio manual fazem uma tentativa só.

Todas as tentativas, com status HTTP, duração e próxima tentativa, aparecem no histórico da página Webhooks.

Validar a assinatura

Valide a V2 em todo aviso, antes de converter o corpo para objeto:

  1. Leia X-SafiPay-Signature-V2 e separe t e v1.
  2. Recuse se t estiver a mais de 300 segundos do seu relógio, para mais ou para menos. Assim um aviso copiado não pode ser reenviado depois.
  3. Calcule o HMAC-SHA256 de t, um ponto e os bytes do corpo exatamente como chegaram, com o segredo certo: o da chave ou o da conta.
  4. Compare o resultado em hexadecimal com v1 numa comparação de tempo constante. Recuse o que não bater.
Já valida o header antigo? X-SafiPay-Signature continua sendo enviado, com o HMAC só do corpo, e quem usa esse header não precisa mudar nada. Para migrar, valide a V2 junto com a antiga e, quando estiver funcionando, remova a validação antiga.
O mesmo evento pode chegar mais de uma vez. Por exemplo, um reenvio depois de um timeout do seu lado ou um reenvio manual. Processe de forma idempotente usando transactionId + event. Não use X-SafiPay-Delivery para isso: ele muda a cada tentativa.
Vendas sem código

Checkout hospedado #

Para vender sem integrar a API, crie um produto em Produtos. Cada produto ganha um link público de pagamento:

Link https://checkout.seguro.safipaybr.com/payment/{código}
  • O comprador abre o link, informa nome, e-mail e, conforme a configuração do produto, CPF/CNPJ e telefone. Paga com Pix e vê a confirmação na mesma página.
  • O preço vai do mínimo da conta até R$ 5.000,00, com a mesma taxa de uma cobrança pela API (veja Taxas).
  • Cada pedido gera uma cobrança Pix comum: aparece no Extrato com o nome do produto na descrição e dispara pix.paid no seu webhook quando é pago, no mesmo formato da API.
  • Você escolhe o tema da página, a mensagem de confirmação e, se quiser, um link HTTPS para onde levar o comprador depois do pagamento.
Ir para Produtos
Referência

Status das transações #

StatusCobrança (pix_in)Transferência (pix_out)
pendingAguardando pagamento. O QR Code vale até expiresAt.Pedido feito, aguardando confirmação. Valor e taxa já saíram do saldo.
paidPagamento confirmado e líquido creditado. Dispara pix.paid.Transferência concluída. Dispara pixout.paid.
expiredNão foi paga no prazo. Dispara pix.expired se a opção estiver ligada. Se o pagamento for confirmado depois, ainda muda para paid e credita normalmente.—
failedA cobrança falhou ou foi cancelada. Dispara pix.failed se a opção estiver ligada.Recusada ou falhou. Valor e taxa voltam ao saldo. Dispara pixout.failed quando a falha chega depois do pedido.
refundedPix devolvido ao pagador (estorno ou MED).—

Cobranças sem pagamento confirmado 1 hora depois de criadas, com expiresAt já vencido, passam a expired automaticamente, sem esperar a rotina de conciliação: uma consulta a pix-status nesse ponto já responde expired. Se o pagamento for confirmado depois, a cobrança muda para paid e credita normalmente. Por isso, trate pix.paid mesmo para pedidos que você já deu como vencidos.

Referência

Erros #

Erros vêm com o status HTTP e o corpo { "error": "mensagem" }. As mensagens são em português e podem ser mostradas ao seu time. Para decidir no código, use o status HTTP. As mensagens de cada endpoint estão na seção dele.

StatusSignificadoO que fazer
200 · 201Sucesso.—
202Transferência com envio ambíguo (pix-out ou crypto-withdraw).Aguarde o webhook. Não repita com outra chave.
400Dados inválidos, limite, saldo insuficiente, transferência recusada (PIX_OUT_REFUSED), credenciais na URL ou valor abaixo do mínimo da conta (AMOUNT_BELOW_MINIMUM).Corrija e envie de novo com uma nova Idempotency-Key.
401Credenciais ausentes (API_KEY_REQUIRED) ou inválidas, chave revogada ou conta inativa.Envie ci e cs em header. Confira os valores em API Keys.
403IP fora da lista de IPs permitidos da chave. "code": "IP_NOT_ALLOWED".Libere o IP que aparece na mensagem em API Keys, ou chame de um IP da lista.
404Transação não encontrada. ou Endpoint não encontrado.Confira o ID e a URL.
405Método não permitido.Use o método indicado no endpoint.
409Conflito de idempotência.Espere e repita; se o corpo mudou, use outra chave.
429Muitas requisições (RATE_LIMITED).Espere os segundos do header Retry-After.
500Erro interno. ou falha ao gravar.Tente de novo em instantes com uma nova chave. Em transferências, confira antes no Extrato se ela não foi criada.
502A cobrança não foi gerada.Tente de novo com uma nova chave.
503Serviço de pagamento ou registro de idempotência indisponível.Tente de novo em instantes. Veja o code.

Códigos de erro

Quando existe, o campo code identifica o erro sem depender do texto da mensagem. Trate por ele.

StatuscodeQuando aconteceO que fazer
400INVALID_AMOUNTamount não é número com ponto decimal e até 2 casas: "100abc", vírgula ou 3 casas.Envie 150.00. Corrija e repita com uma nova Idempotency-Key.
400AMOUNT_BELOW_MINIMUMCobrança abaixo do mínimo da conta. Traz minAmount.Cobre pelo menos minAmount. Veja Taxas.
400IDEMPOTENCY_KEY_INVALIDA chave tem caractere fora de letras, números, :, _ e -, ou passa de 128.Gere a chave só com esses caracteres (um UUID serve).
409IDEMPOTENCY_KEY_ALREADY_USEDA chave já foi usada em outra transferência.Consulte a transferência original. Para uma operação nova, use outra chave.
503IDEMPOTENCY_UNAVAILABLENão deu para garantir execução única agora. Nada foi executado.Tente de novo em instantes com a mesma chave e o mesmo corpo.
400CREDENTIALS_IN_QUERYci ou cs na URL.Envie só em header e troque a chave se o secret já apareceu numa URL.
401API_KEY_REQUIREDRota de API chamada sem ci e cs (a sessão do painel não vale).Envie as credenciais da chave em header.
403IP_NOT_ALLOWEDIP fora da lista de IPs permitidos da chave.Libere o IP da mensagem em API Keys.
429RATE_LIMITEDMuitas requisições seguidas. Vem com o header Retry-After (segundos).Espere o Retry-After e repita. Não repita em laço.
400BRCODE_INVALIDCopia e cola incompleto ou com CRC errado.Copie o código inteiro de novo.
400BRCODE_AMOUNT_MISMATCHamount diferente do valor do código. Traz brCodeAmount.Envie amount igual a brCodeAmount.
400BRCODE_DYNAMIC_NOT_ALLOWEDCódigo sem valor definido.Peça um código com valor ou transfira pela chave Pix.
403WITHDRAWALS_BLOCKEDTransferências bloqueadas para revisão de segurança da conta.Fale com o suporte. Não repita.
403NEGATIVE_BALANCESaldo negativo por devolução de Pix recebido; transferências bloqueadas.Fale com o suporte para regularizar.
400UNVERIFIED_DAILY_LIMITLimite diário de transferências da conta não verificada. Traz used, limit e verificationUrl.Espere o próximo dia ou conclua a verificação.
400PIX_OUT_REFUSEDTransferência recusada no envio (ex.: chave Pix inexistente). Valor e taxa já voltaram ao saldo.Confira a chave ou o código copia e cola e envie de novo com uma nova Idempotency-Key.
503ACQUIRER_UNAVAILABLEServiço de pagamento indisponível no momento.Tente de novo em instantes. Em transferências, confira antes o Extrato.
503WITHDRAWALS_PAUSEDTransferências (Pix e cripto) pausadas pela SafiPay. Nada foi debitado.Tente de novo mais tarde.
400CRYPTO_NETWORK_INVALIDSaque cripto com rede ou moeda fora da lista.Envie network BEP20 (USDT).
400CRYPTO_ADDRESS_INVALIDEndereço da carteira fora do formato da rede ou com checksum errado.Copie o endereço de novo direto da carteira. Nada foi debitado.
400CRYPTO_AMOUNT_BELOW_MINIMUM CRYPTO_AMOUNT_ABOVE_MAXIMUMSaque cripto fora da faixa de R$ 24,00 a R$ 3.000,00. Traz minAmount ou maxAmount.Ajuste amount.
400CRYPTO_OUT_REFUSEDSaque cripto recusado no envio. Valor e taxa já voltaram ao saldo.Confira rede e endereço e envie de novo com uma nova Idempotency-Key.
503CRYPTO_WITHDRAWAL_UNAVAILABLESaque cripto indisponível no momento. Nada foi debitado.Tente de novo mais tarde ou use pix-out.
Referência

Boas práticas #

Guarde o transactionId

Salve junto do pedido assim que a cobrança for criada. É com ele que você consulta o status e reconhece o webhook.

Use Idempotency-Key

Recomendada em pix-create, pix-out e crypto-withdraw. Use o ID do seu pedido ou um UUID guardado com ele. Em timeout, repita com a mesma chave e o mesmo corpo para não duplicar.

Confie no webhook e confirme

Valide a assinatura V2 e o horário de todo aviso. Antes de liberar algo valioso, confirme com pix-status.

Não dependa só do webhook

Se o aviso não chegou alguns minutos depois do pagamento, consulte pix-status. A consulta confere o pagamento (dentro do limite de conferências da conta) e dispara o webhook se ele tiver entrado.

Responda rápido, processe uma vez

Devolva 2xx em até 10 s e faça o trabalho pesado depois. Ignore eventos repetidos pelo par transactionId + event.

Reenvie quando precisar

Perdeu um aviso? No painel, reenvie o webhook de uma transação paga ou com falha pelo Extrato e acompanhe em Webhooks.

Proteja as credenciais

Guarde em variáveis de ambiente do servidor e limite cada chave aos IPs dele. Para trocar uma chave, crie a nova, publique e só então revogue a antiga.

Some dinheiro sem erro

No seu sistema, guarde valores em centavos inteiros ou tipo decimal, nunca em ponto flutuante. Grave fee e netAmount da resposta em vez de recalcular a taxa.

Pronto para integrar? Crie uma chave e faça a primeira cobrança.