Pular para o conteúdo principal

Guia de Transferências Internas

Este guia explica como realizar transferências internas entre contas do mesmo banco, cobrindo os três métodos disponíveis e seus casos de uso.

Visão Geral

Transferências internas movem valores entre contas dentro do mesmo banco, sem passar pela rede PIX. São processadas instantaneamente.

Existem três formas de identificar a conta de destino:

MétodoEndpointRequisito da conta destinoCaso de uso
Por Account ID/transfers/internalDeve ter API habilitadaTransferências entre suas próprias contas
Por Documento/transfers/internal/by-documentQualquer conta do bancoTransferências para qualquer correntista
Por Agência/Conta/transfers/internal/by-bank-accountDeve ter API habilitadaQuando você tem agência e número da conta

1. Transferência por Account ID

O método mais performático. Use quando ambas as contas (origem e destino) estão registradas na API.

Endpoint: POST /v1/accounts/{accountId}/transfers/internal

curl -X POST "https://tenant.api.corpx.com/v1/accounts/{accountId}/transfers/internal" \
-H "Authorization: Bearer {token}" \
-H "X-Tenant-Id: tenant-suaempresa" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: int-001" \
-d '{
"destinationAccountId": "773107de-139e-48d1-9462-f4e88f251891",
"value": 1500.00,
"description": "Transferência entre filiais",
"identifier": "transf-filial-001"
}'

Campos:

CampoTipoObrigatórioDescrição
destinationAccountIdstring (UUID)SimAccount ID de destino (UUID interno da API)
valuenumberSimValor em reais (máx. 2 casas decimais)
descriptionstringNãoDescrição da transferência (máx. 140 caracteres)
identifierstringNãoIdentificador único para rastreamento. Gerado automaticamente se omitido

Resposta (200):

{
"paymentId": "pay_2f4a0f88-2147-49f2-a4e2-4f7b9f6c0f7a",
"workflowId": "internal-out-{accountId}-transf-filial-001-int-001",
"runId": "b7c1f0e2-...",
"transactionId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"endToEndId": "E50871921202603181530000000001",
"destinationAccountId": "773107de-139e-48d1-9462-f4e88f251891",
"status": "COMPLETED",
"value": 1500.00,
"description": "Transferência entre filiais",
"identifier": "transf-filial-001",
"idempotencyKey": "int-001",
"completedAt": "2026-03-18T15:30:00Z"
}

Quando a transferência é recusada, o mesmo corpo volta com 422, status: "FAILED" e os campos errorCode/errorReason preenchidos.

2. Transferência por Documento (CPF/CNPJ)

Use quando a conta de destino não está registrada na API. Funciona para qualquer conta do ecossistema bancário.

Endpoint: POST /v1/accounts/{accountId}/transfers/internal/by-document

curl -X POST "https://tenant.api.corpx.com/v1/accounts/{accountId}/transfers/internal/by-document" \
-H "Authorization: Bearer {token}" \
-H "X-Tenant-Id: tenant-suaempresa" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: int-002" \
-d '{
"document": "12345678000190",
"value": 500.00,
"description": "Pagamento fornecedor",
"identifier": "pgto-fornecedor-002"
}'

Campos:

CampoTipoObrigatórioDescrição
documentstringSimCPF ou CNPJ do titular da conta destino (somente números)
valuenumberSimValor em reais
descriptionstringNãoDescrição da transferência (máx. 140 caracteres)
identifierstringNãoIdentificador único para rastreamento. Gerado automaticamente se omitido
Documento com múltiplas contas

Quando o documento de destino possui mais de uma conta ativa, endereçar por documento é ambíguo e a requisição é rejeitada com 409 multiple_destination_accounts. Nesse caso, use /transfers/internal/by-bank-account (agência + conta) ou /transfers/internal (destinationAccountId).

3. Transferência por Agência e Conta

Use quando você tem agência e número da conta. Ambas as contas devem estar registradas na API.

Endpoint: POST /v1/accounts/{accountId}/transfers/internal/by-bank-account

curl -X POST "https://tenant.api.corpx.com/v1/accounts/{accountId}/transfers/internal/by-bank-account" \
-H "Authorization: Bearer {token}" \
-H "X-Tenant-Id: tenant-suaempresa" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: int-003" \
-d '{
"branch": "0001",
"accountNumber": "200038274",
"holderDocument": "12345678000190",
"holderName": "EMPRESA DESTINO LTDA",
"value": 250.00,
"description": "Reembolso",
"identifier": "reembolso-003"
}'

Campos:

CampoTipoObrigatórioDescrição
branchstringSimAgência da conta destino
accountNumberstringSimNúmero da conta destino
holderDocumentstringSimCPF/CNPJ do titular da conta destino — o liquidante exige o documento para rotear
holderNamestringNãoNome do titular destino
valuenumberSimValor em reais
descriptionstringNãoDescrição da transferência (máx. 140 caracteres)
identifierstringNãoIdentificador único para rastreamento. Gerado automaticamente se omitido

Qual método escolher?

Conta destino tem API habilitada?
├── SIM → Você tem o Account ID (UUID)?
│ ├── SIM → Use /transfers/internal (mais rápido)
│ └── NÃO → Use /transfers/internal/by-bank-account
└── NÃO → Use /transfers/internal/by-document

Exemplos práticos:

  • Movimentação entre filiais da sua empresa/transfers/internal (por Account ID)
  • Pagamento a fornecedor do banco/transfers/internal/by-document (por CPF/CNPJ)
  • Transferência para conta conhecida por agência/transfers/internal/by-bank-account

Webhooks

Após uma transferência interna, ambas as partes recebem um webhook:

  • Quem enviou: transfer.internal.out
  • Quem recebeu: transfer.internal.in
{
"id": "transfer-internal-out-pay_2f4a0f88-2147-49f2-a4e2-4f7b9f6c0f7a",
"type": "transfer.internal.out",
"occurredAt": "2026-03-18T15:30:00.000000000Z",
"schemaVersion": "1.0",
"environment": "production",
"tenantId": "tenant-suaempresa",
"accountId": "a1b2c3d4-aaaa-bbbb-cccc-111122223333",
"data": {
"paymentId": "pay_2f4a0f88-2147-49f2-a4e2-4f7b9f6c0f7a",
"transactionId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"endToEnd": "E50871921202603181530000000001",
"accountId": "a1b2c3d4-aaaa-bbbb-cccc-111122223333",
"direction": "OUT",
"sourceAccountId": "a1b2c3d4-aaaa-bbbb-cccc-111122223333",
"sourceTenantId": "tenant-suaempresa",
"destinationAccountId": "773107de-139e-48d1-9462-f4e88f251891",
"destinationTenantId": "tenant-suaempresa",
"amount": 1500.00,
"description": "Repasse para filial SP",
"identifier": "transf-filial-001",
"status": "SUCCESS"
}
}

O data é plano: não existem objetos aninhados source/destination com nome e documento — as contraparte aparecem como sourceAccountId / destinationAccountId. A perna transfer.internal.in traz o mesmo payload com accountId do destino e direction: "IN".

Status em transferência interna

Como a liquidação é atômica e síncrona, o webhook sempre chega com data.status: "SUCCESS" — é o único valor possível para transfer.internal.*. Falhas (saldo insuficiente, conta destino inexistente, conta bloqueada, etc.) são sinalizadas na própria resposta HTTP da chamada POST /transfers/internal* e nunca geram webhook.

Campos garantidos para reconciliação

O webhook enviado ao pagador (transfer.internal.out) carrega identifier e description idênticos aos que você enviou no corpo da requisição (POST /transfers/internal*), junto com paymentId e transactionId, que também estão na resposta síncrona. Isso dispensa consultas adicionais ao extrato para fechar a transferência no seu sistema.

A perna transfer.internal.in só é emitida quando a conta de destino também é gerenciada na CorpX; ela repete os mesmos campos (inclusive o identifier definido pelo pagador), mudando apenas accountId e direction.

Para receber estes webhooks, inclua transfer.internal.in e/ou transfer.internal.out nos event types da sua subscrição.

Erros Comuns

HTTPerrorCodeCausa
400missing_fieldsCampo obrigatório ausente (value, description, destino)
400invalid_fieldValor com mais de 2 casas decimais, agência inválida, descrição fora do formato
400invalid_identifieridentifier fora do charset [A-Za-z0-9._-] ou acima de 38 caracteres
404beneficiary_not_foundConta destino não existe (destinationAccountId desconhecido na CorpX ou documento sem conta no liquidante)
422beneficiary_not_active_at_partnerConta existe na CorpX, mas o liquidante ainda não tem o titular (credenciamento pendente)
422beneficiary_incompleteLiquidante devolveu o titular sem agência/conta
422recipient_account_not_foundLiquidante não encontrou a conta destino informada
409multiple_destination_accountsDocumento com mais de uma conta ativa (use by-bank-account)
409identifier_conflictJá existe transferência com esse identifier nesta conta de origem
422insufficient_fundsSaldo disponível não cobre o valor
422balance_reservation_failedSaldo existe mas não pôde ser reservado (bloqueio, concorrência)
422partner_account_disabledConta de origem desabilitada no banco
422limit_exceeded_transaction / limit_exceeded_dailyLimite de transferência excedido
422partner_rejectedRecusa por política interna do banco. O bloco partner traz o motivo informado
502partner_error / partner_unavailableErro ou indisponibilidade no banco
422 é desfecho, 202 é dúvida

Uma transferência recusada responde 422 com status: "FAILED", errorCode e errorReason — o dinheiro não saiu e não virá webhook algum. O 202 com status: "PENDING" significa outra coisa: a chamada foi enviada e a confirmação não chegou dentro da janela síncrona. Nesse caso consulte o extrato antes de reemitir — repetir o POST com a mesma Idempotency-Key reaproveita a operação em curso, mas com chave nova você pode transferir duas vezes.