PayZuDocs

Transferências entre contas

Mova saldo para outra conta PayZu pela chave Pix dela, com o resultado já na resposta.

O dinheiro não passa pelo Pix: o destino é sempre outra conta PayZu, identificada pela chave Pix dela. Para qualquer outro destino, use um saque.

Pedir a transferência

POST /transactions/internal-transfer, escopo INTERNAL_TRANSFER. WITHDRAW não dá acesso a esta rota: a credencial precisa de INTERNAL_TRANSFER. Obrigatórios: amount, em centavos, e toPixKey, a chave Pix da outra conta PayZu.

Gere uma Idempotency-Key para cada transferência e, se repetir a chamada, mande a mesma.

IDEMPOTENCY_KEY=$(uuidgen)

curl -X POST https://api.hub.payzu.com.br/api/v1/transactions/internal-transfer \
  -H "Authorization: Bearer $PAYZU_TOKEN" \
  -H "Idempotency-Key: $IDEMPOTENCY_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "amount": 10000,
    "toPixKey": "financeiro@lojaparceira.com.br",
    "comment": "Repasse do mês"
  }'
import crypto from 'node:crypto';

const idempotencyKey = crypto.randomUUID();

const res = await fetch('https://api.hub.payzu.com.br/api/v1/transactions/internal-transfer', {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${process.env.PAYZU_TOKEN}`,
    'Idempotency-Key': idempotencyKey,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    amount: 10000,
    toPixKey: 'financeiro@lojaparceira.com.br',
    comment: 'Repasse do mês',
  }),
});
const transferencia = await res.json();

comment aparece no comprovante. callbackUrl recebe os webhooks do seu lado e exige o segredo de callback. Todos os campos estão em Transferir para outra conta PayZu.

Ler o resultado

A resposta (201) traz o resultado. Com CONFIRMED, o valor já está na outra conta: não precisa esperar o webhook INTERNAL_TRANSFER_SENT.

{
  "id": "hubp-20261005L9C3VH6KMA127431",
  "status": "CONFIRMED",
  "side": "SENT",
  "amount": 10000,
  "serviceFee": 100,
  "totalDebited": 10100,
  "counterparty": {
    "name": "Loja Parceira Ltda",
    "document": "12.345.678/0001-95",
    "pixKey": "financeiro@lojaparceira.com.br"
  },
  "comment": "Repasse do mês",
  "providerRejectedReason": null,
  "callbackUrl": null,
  "createdAt": "2026-10-05T15:02:44.010Z",
  "confirmedAt": "2026-10-05T15:02:44.418Z",
  "failedAt": null
}

A tarifa é somada por cima: a outra conta recebe o amount inteiro, e da sua sai o totalDebited. Com FAILED, nada saiu, e providerRejectedReason traz uma mensagem fixa, para exibir.

Baixar o comprovante

Opcional. GET /transactions/internal-transfer/{transferId}/receipt devolve o PDF em base64, para transferência CONFIRMED. Não é comprovante de Pix e não tem end-to-end: a transferência é identificada pelo id.

Pedido repetido

A Idempotency-Key segue as regras do saque, e a comparação usa valor e destino. A mesma chave com outro valor ou destino é recusada com 409 TRANSFER_IDEMPOTENCY_KEY_REUSED.

Num 502 em que o banco não respondeu (PROVIDER_UNAVAILABLE) ou recusou de forma temporária (PROVIDER_REFUSED com details.status 408 ou 429), a transferência pode ter saído. Ela fica REQUESTED, sem resultado, e o valor fica fora do saldo disponível:

  • A API não resolve sozinha: não há webhook nem consulta que antecipe o resultado. A PayZu confere com o banco, e a transferência passa a CONFIRMED ou FAILED.
  • Repetir com a mesma Idempotency-Key devolve a original, ainda REQUESTED, sem enviar outra. Uma chave nova cria outra transferência.
  • Até o resultado ser conferido, ela conta no teto diário daquele dia.

Recusa definitiva do banco deixa a transferência FAILED e devolve o valor.

As duas pontas

A mesma transferência aparece nas duas contas, e side diz o lado:

Camposide: "SENT"side: "RECEIVED"
amountO que saiu para o destinoO que entrou
serviceFee e totalDebitedTarifa e total debitado0
counterpartyQuem recebeuQuem enviou
counterparty.pixKeyInteira na resposta do POST; mascarada na consulta e na listagemMascarada
callbackUrlA URL enviadanull
WebhookINTERNAL_TRANSFER_SENTINTERNAL_TRANSFER_RECEIVED

Só a transferência confirmada gera webhook.

Consultar

Limites

  • Saldo insuficiente recusa a transferência inteira, e a conta é feita sobre o totalDebited. TRANSFER_INSUFFICIENT_BALANCE traz details.available e details.required.
  • O valor fica entre o mínimo e o máximo de transferência da conta, em internalTransfer nos limites.
  • O teto diário é próprio, separado do saque: dailyInternalTransfer. 0 bloqueia toda transferência e limit: null é sem teto. Estourar responde 422 TRANSFER_DAILY_LIMIT.
  • Até 5 pedidos por minuto por credencial e 10 por conta. Acima disso, a API responde 429 com Retry-After.

Recusas

As que pedem outro destino ou um ajuste na conta:

StatuscodeQuando
404TRANSFER_DESTINATIONNenhuma conta PayZu tem esta chave ativa. Use um saque.
422TRANSFER_DIFFERENT_PROVIDERA conta de destino opera em outro banco. Use um saque.
422TRANSFER_SAME_ACCOUNTA chave é da sua própria conta.
422TRANSFER_AMBIGUOUS_DESTINATIONA chave está ativa em mais de uma conta.
422TRANSFER_DESTINATION_NOT_ACTIVEA conta de destino não está ativa.
422TRANSFER_MAIN_ACCOUNT_DESTINATIONA chave é de uma conta que não recebe transferência.
422TRANSFER_NO_ORIGIN_KEYA sua conta não tem chave Pix ativa. Veja Chaves Pix.
422ACCOUNT_BLOCKED_BY_PROVIDERO banco bloqueou a saída na sua conta ou a entrada na de destino. details.operation diz qual.
422ACCOUNT_HELD_BY_STAFFA sua conta ou a de destino está retida pelo suporte.

Todas as recusas, com o code, estão em Transferir para outra conta PayZu, e as de credencial e escopo, em Autenticação.

Nesta página