Este guia mostra como enviar transferências PIX de forma detalhada, com exemplos práticos e todas as opções disponíveis para transferências instantâneas.
Endpoint
POST /api/v1/pix/out/pixkey
Realiza transferência PIX instantânea para uma chave PIX específica.
URL Completa:
Produção : https://api.vexybank.com/api/v1/pix/out/pixkey
Content-Type : application/json
Authorization : Bearer <seu_token_bearer>
x-idempotency-key : <chave_unica_para_evitar_duplicacao>
Crítico : Sempre use o header x-idempotency-key com um identificador único para evitar transferências duplicadas.
Parâmetros do corpo
Campos Obrigatórios
Tipo : string
Descrição : Chave PIX de destino
Formatos aceitos : CPF, CNPJ, email, telefone ou chave aleatória// Exemplos válidos
{
"pixKey" : "11122233344" // CPF
"pixKey" : "11222333000144" // CNPJ
"pixKey" : "[email protected] " // Email
"pixKey" : "+5511912345678" // Telefone
"pixKey" : "abc12345-de67-89fg-hijk-lmnopqrstuv0" // Chave aleatória
}
Tipo : number
Descrição : Valor em centavos
Mínimo : 1 centavo (R0 , 01 ) ∗ ∗ M a ˊ x i m o ∗ ∗ : 1.000.000.000 c e n t a v o s ( R 0,01) **Máximo**: 1.000.000.000 centavos (R 0 , 01 ) ∗ ∗ M a ˊ x im o ∗ ∗ : 1.000.000.000 ce n t a v os ( R 10.000.000,00){
"amount" : 150000 // R$ 1.500,00
}
Campos opcionais
Tipo : string
Descrição : Moeda da transferência
Padrão : "BRL"
Valores aceitos : Apenas "BRL"
Tipo : string
Descrição : Descrição da transferência
Limite : 140 caracteres
Padrão : Vazio{
"description" : "Pagamento de fornecedor - NF 12345"
}
Tipo : string
Descrição : URL para receber notificações de status da transferência
Formato : URL válida com protocolo HTTPS
Padrão : Vazio{
"postbackUrl" : "https://exemplo.com.br/webhook/pix-out"
}
Exemplos práticos
Exemplo Básico - CPF
curl --location 'https://api.vexybank.com/api/v1/pix/out/pixkey' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer SEU_TOKEN_AQUI' \
--header 'x-idempotency-key: idempotency_exemplo_001' \
--data '{
"pixKey": "11122233344",
"amount": 10000,
"currency": "BRL",
"description": "Transfer PIX Exemplo",
"postbackUrl": "https://exemplo.com.br/webhook/pix-out"
}'
Exemplo Email - Fornecedor
curl --location 'https://api.vexybank.com/api/v1/pix/out/pixkey' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer SEU_TOKEN_AQUI' \
--header 'x-idempotency-key: idempotency_exemplo_002' \
--data '{
"pixKey": "[email protected] ",
"amount": 20000,
"currency": "BRL",
"description": "Pagamento fornecedor - NF Exemplo",
"postbackUrl": "https://exemplo.com.br/webhook/pix-out"
}'
Exemplo CNPJ - B2B
curl --location 'https://api.vexybank.com/api/v1/pix/out/pixkey' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer SEU_TOKEN_AQUI' \
--header 'x-idempotency-key: idempotency_exemplo_003' \
--data '{
"pixKey": "11222333000144",
"amount": 50000,
"currency": "BRL",
"description": "Pagamento parcela contrato Exemplo",
"postbackUrl": "https://exemplo.com.br/webhook/pix-out"
}'
Exemplo Telefone - Afiliado
curl --location 'https://api.vexybank.com/api/v1/pix/out/pixkey' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer SEU_TOKEN_AQUI' \
--header 'x-idempotency-key: idempotency_exemplo_004' \
--data '{
"pixKey": "+5511912345678",
"amount": 15000,
"currency": "BRL",
"description": "Comissão Exemplo - Afiliado",
"postbackUrl": "https://exemplo.com.br/webhook/pix-out"
}'
Resposta de sucesso (200)
{
"success" : true ,
"message" : "Transferência criada com sucesso" ,
"data" : {
"id" : "transfer_abc123def456" ,
"status" : "queued" ,
"amount" : 10000 ,
"netAmount" : 10000 ,
"fees" : 0 ,
"pixKey" : "11122233344"
}
}
Campos da Resposta
Campo Descrição idID único da transferência statusStatus atual da transferência (queued, processing, completed, canceled) amountValor total da transferência netAmountValor líquido após dedução de taxas feesTaxa cobrada na transferência pixKeyChave PIX de destino
Acompanhamento de status
Via Webhook (Recomendado)
Configure um webhook via postbackUrl para receber atualizações automáticas:
{
"id" : "transfer_abc123def456" ,
"type" : "transfer" ,
"event" : "transfer_completed" ,
"scope" : "postback" ,
"transfer" : {
"id" : "transfer_abc123def456" ,
"amount" : 10000 ,
"status" : "completed" ,
"pix" : {
"endToEndId" : "E00000000202401011200000000000000" ,
"creditorAccount" : null
}
}
}
Eventos Webhook Disponíveis
Os seguintes eventos serão enviados para o postbackUrl configurado:
Evento Descrição transfer_createdTransferência criada e validada transfer_updatedStatus da transferência foi atualizado transfer_completedTransferência concluída com sucesso transfer_canceledTransferência foi cancelada
Possíveis Status da Transferência
Status Descrição queuedTransferência em fila para processamento processingTransferência sendo processada completedTransferência concluída com sucesso canceledTransferência foi cancelada
Via Polling (Alternativo)
# Consultar status da transferência
curl -X GET 'https://api.vexybank.com/api/v1/transfers/transfer_abc123def456' \
-H 'Authorization: Bearer SEU_TOKEN_AQUI'
Implementações por linguagem
JavaScript/Node.js
class PixTransfer {
constructor ( auth ) {
this . auth = auth
}
async sendToPixKey ( pixKey , amount , description = '' , postbackUrl = '' , idempotencyKey = null ) {
if ( ! idempotencyKey ) {
idempotencyKey = this . generateIdempotencyKey ( pixKey , amount )
}
const transferData = {
pixKey ,
amount ,
currency: 'BRL' ,
description ,
postbackUrl
}
try {
const response = await this . auth . makeAuthenticatedRequest (
'POST' ,
'/api/v1/pix/out/pixkey' ,
transferData ,
{ 'x-idempotency-key' : idempotencyKey }
)
return response . data . data
} catch ( error ) {
throw new Error ( `Erro na transferência: ${ error . message } ` )
}
}
generateIdempotencyKey ( pixKey , amount ) {
const timestamp = Date . now ()
const hash = require ( 'crypto' )
. createHash ( 'md5' )
. update ( ` ${ pixKey } _ ${ amount } _ ${ timestamp } ` )
. digest ( 'hex' )
return `transfer_ ${ hash . substring ( 0 , 16 ) } `
}
async waitForCompletion ( transferId , timeoutMs = 60000 ) {
const startTime = Date . now ()
const checkInterval = 3000 // 3 segundos
while ( Date . now () - startTime < timeoutMs ) {
const transfer = await this . getTransfer ( transferId )
if ( transfer . status === 'completed' ) {
return transfer
} else if ( transfer . status === 'refused' || transfer . status === 'canceled' ) {
throw new Error ( `Transferência ${ transfer . status } : ${ transfer . reason } ` )
}
await new Promise ( resolve => setTimeout ( resolve , checkInterval ))
}
throw new Error ( 'Timeout: transferência não foi concluída no tempo esperado' )
}
async getTransfer ( transferId ) {
const response = await this . auth . makeAuthenticatedRequest (
'GET' ,
`/api/v1/transfers/ ${ transferId } `
)
return response . data . data
}
}
// Uso
const pixTransfer = new PixTransfer ( authInstance )
try {
const transfer = await pixTransfer . sendToPixKey (
'[email protected] ' ,
20000 ,
'Pagamento NF Exemplo' ,
'https://exemplo.com.br/webhook/pix-out'
)
console . log ( 'Transferência iniciada:' , transfer . id )
// Aguardar conclusão via webhook ou polling
const completedTransfer = await pixTransfer . waitForCompletion ( transfer . id )
console . log ( 'Transferência concluída:' , completedTransfer . status )
} catch ( error ) {
console . error ( 'Erro:' , error . message )
}
Python
import time
import hashlib
from datetime import datetime
class PixTransfer :
def __init__ ( self , auth_instance ):
self .auth = auth_instance
def send_to_pix_key ( self , pix_key , amount , description = '' , postback_url = '' , idempotency_key = None ):
if not idempotency_key:
idempotency_key = self .generate_idempotency_key(pix_key, amount)
transfer_data = {
'pixKey' : pix_key,
'amount' : amount,
'currency' : 'BRL' ,
'description' : description,
'postbackUrl' : postback_url
}
headers = { 'x-idempotency-key' : idempotency_key}
response = self .auth.make_authenticated_request(
'POST' ,
'/api/v1/pix/out/pixkey' ,
transfer_data,
additional_headers = headers
)
if response.status_code == 200 :
return response.json()[ 'data' ]
else :
raise Exception ( f "Erro na transferência: { response.text } " )
def generate_idempotency_key ( self , pix_key , amount ):
timestamp = str ( int (time.time() * 1000 ))
data = f " { pix_key } _ { amount } _ { timestamp } "
hash_obj = hashlib.md5(data.encode())
return f "transfer_ { hash_obj.hexdigest()[: 16 ] } "
def wait_for_completion ( self , transfer_id , timeout_seconds = 60 ):
start_time = time.time()
check_interval = 3 # 3 segundos
while time.time() - start_time < timeout_seconds:
transfer = self .get_transfer(transfer_id)
if transfer[ 'status' ] == 'completed' :
return transfer
elif transfer[ 'status' ] in [ 'refused' , 'canceled' ]:
raise Exception ( f "Transferência { transfer[ 'status' ] } : { transfer.get( 'reason' , 'Motivo não informado' ) } " )
time.sleep(check_interval)
raise Exception ( 'Timeout: transferência não foi concluída no tempo esperado' )
def get_transfer ( self , transfer_id ):
response = self .auth.make_authenticated_request(
'GET' ,
f '/api/v1/transfers/ { transfer_id } '
)
return response.json()[ 'data' ]
# Uso
pix_transfer = PixTransfer(auth_instance)
try :
transfer = pix_transfer.send_to_pix_key(
'[email protected] ' ,
20000 ,
'Pagamento NF Exemplo' ,
'https://exemplo.com.br/webhook/pix-out'
)
print ( f 'Transferência iniciada: { transfer[ "id" ] } ' )
# Aguardar conclusão via webhook ou polling
completed_transfer = pix_transfer.wait_for_completion(transfer[ 'id' ])
print ( f 'Transferência concluída: { completed_transfer[ "status" ] } ' )
except Exception as error:
print ( f 'Erro: { error } ' )
PHP
<? php
class PixTransfer {
private $auth ;
public function __construct ( $authInstance ) {
$this -> auth = $authInstance ;
}
public function sendToPixKey ( $pixKey , $amount , $description = '' , $postbackUrl = '' , $idempotencyKey = null ) {
if ( ! $idempotencyKey ) {
$idempotencyKey = $this -> generateIdempotencyKey ( $pixKey , $amount );
}
$transferData = [
'pixKey' => $pixKey ,
'amount' => $amount ,
'currency' => 'BRL' ,
'description' => $description ,
'postbackUrl' => $postbackUrl
];
$headers = [ 'x-idempotency-key' => $idempotencyKey ];
$response = $this -> auth -> makeAuthenticatedRequest (
'POST' ,
'/api/v1/pix/out/pixkey' ,
$transferData ,
$headers
);
$data = json_decode ( $response , true );
if ( $data [ 'success' ]) {
return $data [ 'data' ];
} else {
throw new Exception ( "Erro na transferência: " . $response );
}
}
private function generateIdempotencyKey ( $pixKey , $amount ) {
$timestamp = round ( microtime ( true ) * 1000 );
$data = "{ $pixKey }_{ $amount }_{ $timestamp }" ;
$hash = md5 ( $data );
return "transfer_" . substr ( $hash , 0 , 16 );
}
public function waitForCompletion ( $transferId , $timeoutSeconds = 60 ) {
$startTime = time ();
$checkInterval = 3 ; // 3 segundos
while ( time () - $startTime < $timeoutSeconds ) {
$transfer = $this -> getTransfer ( $transferId );
if ( $transfer [ 'status' ] === 'completed' ) {
return $transfer ;
} elseif ( in_array ( $transfer [ 'status' ], [ 'refused' , 'canceled' ])) {
$reason = $transfer [ 'reason' ] ?? 'Motivo não informado' ;
throw new Exception ( "Transferência { $transfer ['status']}: { $reason }" );
}
sleep ( $checkInterval );
}
throw new Exception ( 'Timeout: transferência não foi concluída no tempo esperado' );
}
public function getTransfer ( $transferId ) {
$response = $this -> auth -> makeAuthenticatedRequest (
'GET' ,
"/api/v1/transfers/{ $transferId }"
);
$data = json_decode ( $response , true );
return $data [ 'data' ];
}
}
// Uso
$pixTransfer = new PixTransfer ( $authInstance );
try {
$transfer = $pixTransfer -> sendToPixKey (
'[email protected] ' ,
20000 ,
'Pagamento NF Exemplo' ,
'https://exemplo.com.br/webhook/pix-out'
);
echo "Transferência iniciada: " . $transfer [ 'id' ] . " \n " ;
// Aguardar conclusão via webhook ou polling
$completedTransfer = $pixTransfer -> waitForCompletion ( $transfer [ 'id' ]);
echo "Transferência concluída: " . $completedTransfer [ 'status' ] . " \n " ;
} catch ( Exception $error ) {
echo "Erro: " . $error -> getMessage () . " \n " ;
}
?>
Chaves de idempotência
Estratégias Recomendadas
Ideal para pagamentos programados ou recorrentes: function gerarPorReferencia ( referencia , data = null ) {
const dataFormatada = data || new Date (). toISOString (). split ( 'T' )[ 0 ]
return `transfer_ ${ referencia } _ ${ dataFormatada } `
}
// Exemplo: transfer_supplier_123_2024-01-20
Para transferências únicas sem referência específica: const { v4 : uuidv4 } = require ( 'uuid' )
function gerarUUID () {
return `transfer_ ${ uuidv4 () } `
}
// Exemplo: transfer_123e4567-e89b-12d3-a456-426614174000
Baseado nos dados da transferência: const crypto = require ( 'crypto' )
function gerarPorDados ( pixKey , amount , description ) {
const data = ` ${ pixKey } _ ${ amount } _ ${ description } _ ${ Date . now () } `
const hash = crypto . createHash ( 'sha256' ). update ( data ). digest ( 'hex' )
return `transfer_ ${ hash . substring ( 0 , 16 ) } `
}
❌ Tratamento de Erros
Códigos de Erro Específicos
Código Erro Descrição Solução 400INVALID_PIX_KEYChave PIX inválida Validar formato da chave 400INVALID_AMOUNTValor inválido Verificar limites min/max 402INSUFFICIENT_BALANCESaldo insuficiente Verificar saldo disponível 409DUPLICATE_IDEMPOTENCY_KEYChave duplicada Usar nova chave única 422DAILY_LIMIT_EXCEEDEDLimite diário excedido Aguardar próximo dia 422RECIPIENT_UNAVAILABLEDestinatário indisponível Verificar chave PIX
Exemplo de Tratamento Completo
async function enviarComTratamentoCompleto ( dados ) {
const maxRetries = 3
let attempt = 0
while ( attempt < maxRetries ) {
try {
return await pixTransfer . sendToPixKey (
dados . pixKey ,
dados . amount ,
dados . description
)
} catch ( error ) {
attempt ++
switch ( error . code ) {
case 'INSUFFICIENT_BALANCE' :
throw new Error ( 'Saldo insuficiente. Verifique seu saldo e tente novamente.' )
case 'INVALID_PIX_KEY' :
throw new Error ( 'Chave PIX inválida. Verifique o formato da chave.' )
case 'DAILY_LIMIT_EXCEEDED' :
throw new Error ( 'Limite diário de transferências excedido.' )
case 'RECIPIENT_UNAVAILABLE' :
throw new Error ( 'Destinatário temporariamente indisponível. Tente novamente mais tarde.' )
case 'RATE_LIMIT' :
if ( attempt < maxRetries ) {
// Aguardar antes de tentar novamente
await new Promise ( resolve => setTimeout ( resolve , 1000 * attempt ))
continue
}
throw new Error ( 'Muitas tentativas. Aguarde alguns minutos e tente novamente.' )
default :
if ( attempt < maxRetries ) {
await new Promise ( resolve => setTimeout ( resolve , 1000 * attempt ))
continue
}
throw new Error ( 'Erro interno. Entre em contato com o suporte.' )
}
}
}
}
Validações recomendadas
Validação Completa Antes do Envio
function validarDadosTransferencia ( dadosTransferencia ) {
const { pixKey , amount , description } = dadosTransferencia
const erros = []
// Validar chave PIX
if ( ! pixKey || ! validarChavePIX ( pixKey )) {
erros . push ( 'Chave PIX inválida' )
}
// Validar valor
if ( ! amount || amount < 1 ) {
erros . push ( 'Valor deve ser maior que R$ 0,01' )
}
if ( amount > 1000000000 ) {
erros . push ( 'Valor máximo é R$ 10.000.000,00' )
}
// Validar descrição
if ( description && description . length > 140 ) {
erros . push ( 'Descrição deve ter no máximo 140 caracteres' )
}
if ( erros . length > 0 ) {
throw new Error ( 'Dados inválidos: ' + erros . join ( ', ' ))
}
return true
}
Simulação Antes do Envio
async function simularTransferencia ( dados ) {
// Verificar se seria bem-sucedida sem executar
return {
pixKey: dados . pixKey ,
amount: dados . amount ,
fees: 300 , // R$ 3,00
netAmount: dados . amount - 300 ,
estimatedTime: '10 segundos' ,
valid: true
}
}
Próximos passos