Transfers between accounts
Move balance to another PayZu account by its Pix key, with the result already in the response.
The money does not go through Pix: the destination is always another PayZu account, identified by its Pix key. For any other destination, use a withdrawal.
Request the transfer
POST /transactions/internal-transfer, scope INTERNAL_TRANSFER. WITHDRAW does not give access to this route: the credential needs INTERNAL_TRANSFER. Required: amount, in cents, and toPixKey, the Pix key of the other PayZu account.
Generate an Idempotency-Key for each transfer and, if you repeat the call, send the same one.
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 appears on the receipt. callbackUrl receives the webhooks for your side and requires the callback secret. All fields are in Transfer to another PayZu account.
Read the result
The response (201) carries the result. With CONFIRMED, the amount is already in the other account: you do not need to wait for the INTERNAL_TRANSFER_SENT webhook.
{
"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
}The fee is added on top: the other account receives the full amount, and totalDebited leaves yours. With FAILED, nothing left the account, and providerRejectedReason carries a fixed message for display.
Download the receipt
Optional. GET /transactions/internal-transfer/{transferId}/receipt returns the PDF in base64, for a CONFIRMED transfer. It is not a Pix receipt and has no end-to-end ID: the transfer is identified by its id.
Repeated request
The Idempotency-Key follows the withdrawal rules, and the comparison uses amount and destination. The same key with another amount or destination is refused with 409 TRANSFER_IDEMPOTENCY_KEY_REUSED.
On a 502 where the bank did not respond (PROVIDER_UNAVAILABLE) or refused temporarily (PROVIDER_REFUSED with details.status 408 or 429), the transfer may have gone out. It stays REQUESTED, with no result, and the amount stays out of the available balance:
- The API does not resolve it on its own: no webhook or lookup gives the result earlier. PayZu checks with the bank, and the transfer moves to
CONFIRMEDorFAILED. - Repeating with the same
Idempotency-Keyreturns the original, stillREQUESTED, without sending another one. A new key creates another transfer. - Until the result is checked, it counts toward that day's daily cap.
A final refusal from the bank leaves the transfer FAILED and returns the amount.
Both sides
The same transfer appears in both accounts, and side says which side:
| Field | side: "SENT" | side: "RECEIVED" |
|---|---|---|
amount | What went out to the destination | What came in |
serviceFee and totalDebited | Fee and total debited | 0 |
counterparty | Who received | Who sent |
counterparty.pixKey | Full in the POST response; masked in the lookup and in the list | Masked |
callbackUrl | The URL sent | null |
| Webhook | INTERNAL_TRANSFER_SENT | INTERNAL_TRANSFER_RECEIVED |
Only a confirmed transfer generates a webhook.
Look up
GET /transactions/internal-transfer/{transferId}andGET /transactions/internal-transfer, scopeINTERNAL_TRANSFER_READ. The list includes both sides;?side=SENTor?side=RECEIVEDfilters one. It also filters bystatus,dateFromanddateTo.- A transfer from another account, or one that does not exist, responds
404TRANSFER_NOT_FOUND.
Limits
- Insufficient balance refuses the whole transfer, and the check uses
totalDebited.TRANSFER_INSUFFICIENT_BALANCEcarriesdetails.availableanddetails.required. - The amount must be between the account's minimum and maximum transfer, in
internalTransferin the limits. - The daily cap is its own, separate from withdrawals:
dailyInternalTransfer.0blocks every transfer andlimit: nullmeans no cap. Going over it responds422TRANSFER_DAILY_LIMIT. - Up to 5 requests per minute per credential and 10 per account. Above that, the API responds
429withRetry-After.
Rejections
The ones that call for another destination or a change on the account:
| Status | code | When |
|---|---|---|
| 404 | TRANSFER_DESTINATION | No PayZu account has this key active. Use a withdrawal. |
| 422 | TRANSFER_DIFFERENT_PROVIDER | The destination account operates at another bank. Use a withdrawal. |
| 422 | TRANSFER_SAME_ACCOUNT | The key belongs to your own account. |
| 422 | TRANSFER_AMBIGUOUS_DESTINATION | The key is active in more than one account. |
| 422 | TRANSFER_DESTINATION_NOT_ACTIVE | The destination account is not active. |
| 422 | TRANSFER_MAIN_ACCOUNT_DESTINATION | The key belongs to an account that does not receive transfers. |
| 422 | TRANSFER_NO_ORIGIN_KEY | Your account has no active Pix key. See Pix keys. |
| 422 | ACCOUNT_BLOCKED_BY_PROVIDER | The bank blocked outflows on your account or inflows on the destination account. details.operation says which. |
| 422 | ACCOUNT_HELD_BY_STAFF | Your account or the destination account is held by support. |
All rejections, with the code, are in Transfer to another PayZu account, and credential and scope rejections are in Authentication.