PIX Cash-Out (Pago)
Descripción General
El endpoint de PIX Cash-Out le permite realizar pagos PIX instantáneos a cualquier clave PIX válida (CPF, CNPJ, teléfono, email o clave aleatoria). El pago se procesa en tiempo real y el monto se debita de su cuenta inmediatamente.
Para pagos vía QR Code PIX (escaneo o copiar y pegar), use el endpoint dedicado Cash-Out vía QR Code. Este endpoint es exclusivamente para pagos por clave PIX.
Este endpoint requiere un Bearer token válido. Consulte la documentación de autenticación para más detalles.
Características
- Pagos instantáneos 24/7
- Soporte para todos los tipos de clave PIX
- Validación automática de datos del destinatario
- Identificación única vía
externalId - Descripción personalizable para el destinatario
- Verificación automática de saldo
Endpoint
POST /api/pix/cash-out
Realiza un pago PIX.
Encabezados Requeridos
Authorization: Bearer {token}
Content-Type: application/jsonCuerpo de la Solicitud
{
"value": 250.50,
"details": {
"key": "12345678901",
"keyType": "DOCUMENT",
"name": "Ana Costa",
"document": "12345678901"
},
"externalId": "PAYMENT-987654-20240119",
"description": "Pagamento de fornecedor"
}Solicitud
curl -X POST https://api.ntxpay.com/api/pix/cash-out \
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..." \
-H "Content-Type: application/json" \
-d '{
"value": 250.50,
"details": {
"key": "12345678901",
"keyType": "DOCUMENT",
"name": "Ana Costa",
"document": "12345678901"
},
"externalId": "PAYMENT-987654-20240119",
"description": "Pagamento de fornecedor"
}'Respuesta (201 Created)
{
"transactionId": "9876",
"externalId": "PAYMENT-987654-20240119",
"status": "PENDING",
"generateTime": "2024-01-19T15:45:00.000Z"
}Parámetros de la Solicitud
valuenumberobrigatorioMonto del pago en BRL (Reales brasileños). Debe tener como máximo 2 decimales.
Mínimo: 0.01
Ejemplo: 250.50
detailsobjectobrigatorioInformación de la clave PIX de destino.
details.keystringobrigatorioClave PIX de destino.
Formatos aceptados:
- CPF:
12345678901(11 dígitos) - CNPJ:
12345678000199(14 dígitos) - Email:
usuario@exemplo.com - Teléfono:
5511999999999(con código de país y área) - Clave aleatoria: formato UUID
xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
details.keyTypestringobrigatorioTipo de clave PIX.
Valores aceptados:
DOCUMENT- CPF o CNPJEMAIL- Dirección de emailPHONE- Número de teléfonoRANDOM- Clave aleatoria (UUID)
Ejemplo: "DOCUMENT"
details.namestringobrigatorioNombre completo del titular de la clave PIX de destino.
Validación: El nombre debe coincidir con el registrado en la clave PIX
Ejemplo: "Ana Costa"
details.documentstringobrigatorioCPF o CNPJ del titular (solo números).
CPF: 11 dígitos
CNPJ: 14 dígitos
Validación: El documento debe coincidir con el registrado en la clave PIX
Ejemplo: "12345678901"
externalIdstringobrigatorioIdentificador externo único de la transacción.
Máximo: 255 caracteres
Recomendación: Use un formato que garantice unicidad
Ejemplo: "PAYMENT-987654-20240119-154500"
descriptionstringDescripción del pago que aparecerá en el extracto del destinatario.
Máximo: 140 caracteres
Predeterminado: Vacío
Ejemplo: "Pagamento de fornecedor - Nota Fiscal 12345"
Estructura de la Respuesta
transactionIdstringsempre presenteID interno de la transacción generado por Avista.
Ejemplo: "9876"
externalIdstringsempre presenteID externo proporcionado en la solicitud (mismo valor que la entrada).
Ejemplo: "PAYMENT-987654-20240119"
statusstringsempre presenteEstado actual de la transacción.
Valores posibles:
PENDING: Pago en procesoCONFIRMED: Pago confirmado y completadoERROR: Error de procesamiento
Ejemplo: "PENDING"
Nota: La mayoría de los pagos PIX se confirman en pocos segundos
generateTimestringsempre presenteFecha y hora de creación del pago (ISO 8601 UTC).
Ejemplo: "2024-01-19T15:45:00.000Z"
Ejemplos de Implementación
Node.js / TypeScript
import axios from 'axios';
interface CashOutRequest {
value: number;
details: {
key: string;
keyType: 'DOCUMENT' | 'EMAIL' | 'PHONE' | 'RANDOM';
name: string;
document: string;
};
externalId: string;
description?: string;
}
interface CashOutResponse {
transactionId: string;
externalId: string;
status: 'PENDING' | 'CONFIRMED' | 'ERROR';
generateTime: string;
}
async function sendPixPayment(
token: string,
recipientKey: string,
recipientKeyType: 'DOCUMENT' | 'EMAIL' | 'PHONE' | 'RANDOM',
recipientName: string,
recipientDocument: string,
amount: number,
description?: string
): Promise<CashOutResponse> {
const payload: CashOutRequest = {
value: amount,
details: {
key: recipientKey,
keyType: recipientKeyType,
name: recipientName,
document: recipientDocument
},
externalId: `PAY-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`,
description: description || `Pagamento PIX de R$ ${amount.toFixed(2)}`
};
try {
const response = await axios.post<CashOutResponse>(
'https://api.ntxpay.com/api/pix/cash-out',
payload,
{
headers: {
'Authorization': `Bearer ${token}`,
'Content-Type': 'application/json'
}
}
);
console.log('PIX payment initiated successfully!');
console.log(`Transaction ID: ${response.data.transactionId}`);
console.log(`Status: ${response.data.status}`);
console.log(`Amount: R$ ${amount.toFixed(2)}`);
console.log(`Recipient: ${recipientName}`);
return response.data;
} catch (error) {
if (axios.isAxiosError(error)) {
const errorData = error.response?.data;
console.error('Error making payment:', errorData);
// Handle specific errors
if (error.response?.status === 400) {
if (errorData?.message?.includes('saldo insuficiente')) {
throw new Error('Insufficient balance to make the payment');
}
throw new Error('Invalid data: ' + errorData?.message);
}
throw new Error(errorData?.message || 'Error making PIX payment');
}
throw error;
}
}
// Usage - Payment by CPF
sendPixPayment(
'your_token_here',
'12345678901',
'DOCUMENT',
'Ana Costa',
'12345678901',
250.50,
'Pagamento de fornecedor'
);
// Usage - Payment by Email
sendPixPayment(
'your_token_here',
'ana.costa@email.com',
'EMAIL',
'Ana Costa',
'12345678901',
100.00,
'Reembolso'
);
// Usage - Payment by Phone
sendPixPayment(
'your_token_here',
'5511999999999',
'PHONE',
'Ana Costa',
'12345678901',
50.00
);Python
import requests
from datetime import datetime
from typing import Dict, Optional
import uuid
def send_pix_payment(
token: str,
recipient_key: str,
recipient_key_type: str,
recipient_name: str,
recipient_document: str,
amount: float,
description: Optional[str] = None
) -> Dict:
"""
Send a PIX payment
Args:
token: Valid Bearer token
recipient_key: Recipient's PIX key
recipient_key_type: Key type (DOCUMENT, EMAIL, PHONE, RANDOM)
recipient_name: Recipient's name
recipient_document: Recipient's CPF or CNPJ
amount: Amount in BRL
description: Payment description (optional)
Returns:
Initiated payment data
"""
url = 'https://api.ntxpay.com/api/pix/cash-out'
payload = {
'value': round(amount, 2),
'details': {
'key': recipient_key,
'keyType': recipient_key_type,
'name': recipient_name,
'document': recipient_document
},
'externalId': f'PAY-{int(datetime.now().timestamp())}-{uuid.uuid4().hex[:8]}',
'description': description or f'Pagamento PIX de R$ {amount:.2f}'
}
headers = {
'Authorization': f'Bearer {token}',
'Content-Type': 'application/json'
}
try:
response = requests.post(url, json=payload, headers=headers)
response.raise_for_status()
data = response.json()
print('PIX payment initiated successfully!')
print(f"Transaction ID: {data['transactionId']}")
print(f"Status: {data['status']}")
print(f"Amount: R$ {amount:.2f}")
print(f"Recipient: {recipient_name}")
return data
except requests.exceptions.HTTPError as e:
error_data = e.response.json() if e.response else {}
# Handle specific errors
if e.response.status_code == 400:
if 'saldo insuficiente' in error_data.get('message', '').lower():
raise Exception('Insufficient balance to make the payment')
raise Exception(f"Invalid data: {error_data.get('message')}")
raise Exception(f"Error making payment: {error_data.get('message', str(e))}")
# Usage
token = 'your_token_here'
# Payment by CPF
payment = send_pix_payment(
token=token,
recipient_key='12345678901',
recipient_key_type='DOCUMENT',
recipient_name='Ana Costa',
recipient_document='12345678901',
amount=250.50,
description='Pagamento de fornecedor'
)PHP
<?php
function sendPixPayment(
string $token,
string $recipientKey,
string $recipientKeyType,
string $recipientName,
string $recipientDocument,
float $amount,
?string $description = null
): array {
$url = 'https://api.ntxpay.com/api/pix/cash-out';
$payload = [
'value' => round($amount, 2),
'details' => [
'key' => $recipientKey,
'keyType' => $recipientKeyType,
'name' => $recipientName,
'document' => $recipientDocument
],
'externalId' => 'PAY-' . time() . '-' . bin2hex(random_bytes(4)),
'description' => $description ?? "Pagamento PIX de R$ " . number_format($amount, 2, ',', '.')
];
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($payload));
curl_setopt($ch, CURLOPT_HTTPHEADER, [
'Authorization: Bearer ' . $token,
'Content-Type: application/json'
]);
$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
if ($httpCode !== 201) {
$errorData = json_decode($response, true);
$errorMessage = $errorData['message'] ?? "HTTP $httpCode";
if ($httpCode === 400 && stripos($errorMessage, 'saldo insuficiente') !== false) {
throw new Exception('Insufficient balance to make the payment');
}
throw new Exception("Error making payment: $errorMessage");
}
$data = json_decode($response, true);
echo "PIX payment initiated successfully!" . PHP_EOL;
echo "Transaction ID: {$data['transactionId']}" . PHP_EOL;
echo "Status: {$data['status']}" . PHP_EOL;
echo "Amount: R$ " . number_format($amount, 2, ',', '.') . PHP_EOL;
echo "Recipient: $recipientName" . PHP_EOL;
return $data;
}
// Usage
$token = 'your_token_here';
$payment = sendPixPayment(
$token,
'12345678901',
'DOCUMENT',
'Ana Costa',
'12345678901',
250.50,
'Pagamento de fornecedor'
);Validación de Clave PIX
Antes de enviar un pago, valide el formato de la clave PIX:
function validatePixKey(key: string, keyType: string): boolean {
switch (keyType) {
case 'DOCUMENT':
// CPF: 11 digits or CNPJ: 14 digits
return /^\d{11}$|^\d{14}$/.test(key);
case 'EMAIL':
return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(key);
case 'PHONE':
// Format: +5511999999999 (country code + area code + number)
return /^55\d{10,11}$/.test(key);
case 'RANDOM':
// UUID format: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
return /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(key);
default:
return false;
}
}Verificación de Saldo
Siempre verifique el saldo antes de realizar pagos para evitar errores 400.
async function safePayment(
token: string,
amount: number,
recipient: RecipientData
) {
// Query balance
const balance = await getBalance(token);
// Check if there is sufficient balance
if (balance.netBalance < amount) {
throw new Error(
`Insufficient balance. Available: R$ ${balance.netBalance.toFixed(2)} | ` +
`Required: R$ ${amount.toFixed(2)}`
);
}
// Proceed with payment
return await sendPixPayment(token, ...recipient, amount);
}Monitoreo de Estado
Para rastrear la confirmación del pago:
async function monitorPaymentStatus(transactionId, timeout = 60000) {
const startTime = Date.now();
while (Date.now() - startTime < timeout) {
const status = await checkTransactionStatus(transactionId);
if (status === 'CONFIRMED') {
console.log('Payment confirmed!');
return true;
}
if (status === 'ERROR') {
throw new Error('Payment failed');
}
// Wait 2 seconds before checking again
await new Promise(resolve => setTimeout(resolve, 2000));
}
throw new Error('Timeout: Payment not confirmed within expected time');
}Códigos de Respuesta
| Código | Descripción | Significado |
|---|---|---|
201 | Pago Iniciado | Transferencia PIX iniciada exitosamente |
400 | Saldo Insuficiente | Saldo insuficiente para completar la transacción |
400 | Datos Inválidos | Verifique los campos requeridos y formatos |
401 | Token Inválido | Token no proporcionado, expirado o inválido |
Consulte la Referencia de la API para detalles completos de los campos de respuesta.
Mejores Prácticas
Notas Importantes
- Monto mínimo: R$ 0.01