PIX Cash-In (Recepción)
Descripción General
El endpoint PIX Cash-In le permite generar cobros PIX dinámicos para recibir pagos. Cada cobro genera un QR Code único y un código PIX (Pix Copia e Cola) que sus clientes pueden usar para realizar el pago.
Este endpoint requiere un token Bearer válido. Consulte la documentación de autenticación para más detalles.
Características
- Generación de QR Code dinámico
- Código PIX en formato EMV (Copia e Cola)
- Configuración del plazo de expiración (30 segundos a 7 días, sujeto al rango del liquidador de la cuenta)
- Identificación única por
externalId - Información adicional personalizable
- Validación de formato del CPF/CNPJ del pagador
- Split de pago (cuando está habilitado en la cuenta): división automática entre múltiples destinatarios
Endpoint
POST /api/pix/cash-in
Genera un nuevo cobro PIX.
Encabezados Requeridos
Authorization: Bearer {token}
Content-Type: application/jsonCuerpo de la Solicitud
{
"transaction": {
"value": 150.00,
"description": "Pago del pedido #12345",
"expirationTime": 86400,
"externalId": "ORDER-12345-20240119",
"generateQrCode": true
},
"payer": {
"fullName": "Carlos Oliveira",
"document": "12345678901"
},
"additionalInfo": {
"orderId": "12345",
"storeName": "Tech Solutions",
"productCategory": "Electrónicos"
},
"splits": [
{
"pixKey": "proveedor@email.com",
"pixKeyType": "EMAIL",
"name": "Proveedor Ltda",
"document": "12345678000199",
"type": "PERCENTAGE",
"value": 10,
"immediate": false
}
]
}Solicitud
curl -X POST https://api.fypay.me/api/pix/cash-in \
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..." \
-H "Content-Type: application/json" \
-d '{
"transaction": {
"value": 150.00,
"description": "Pago del pedido #12345",
"expirationTime": 86400,
"externalId": "ORDER-12345-20240119",
"generateQrCode": true
},
"payer": {
"fullName": "Carlos Oliveira",
"document": "12345678901"
},
"additionalInfo": {
"orderId": "12345"
},
"splits": [
{
"pixKey": "proveedor@email.com",
"pixKeyType": "EMAIL",
"name": "Proveedor Ltda",
"document": "12345678000199",
"type": "PERCENTAGE",
"value": 70,
"immediate": false
}
]
}'El campo splits es opcional y solo se acepta en cuentas con split habilitado (sin eso, la API responde 400 SPLIT_NOT_CONFIGURED). Consulte la guía de Split de Pagos para detalles completos sobre tipos, formatos de valor y frecuencias.
Respuesta (201 Created)
{
"transactionId": "7845",
"correlationId": "550e8400-e29b-41d4-a716-446655440000",
"externalId": "ORDER-12345-20240119",
"status": "PENDING",
"pixCode": "00020126580014br.gov.bcb.pix0136550e8400-e29b-41d4-a716-4466554400005204000053039865802BR5916Tech Solutions Ltda6009SAO PAULO62070503***63041D3D",
"generateTime": "2024-01-19T14:30:00.000Z",
"expirationDate": "2024-01-20T14:30:00.000Z",
"qrCodeImage": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAASwAAAEsCAYAAAB5fY51..."
}El campo qrCodeImage se devuelve solo cuando se envía generateQrCode: true en la solicitud. El valor es una imagen PNG del QR Code codificada en Base64 en formato Data URL.
Parámetros de la Solicitud
Objeto Transaction
transaction.valuenumberobrigatorioValor de la transacción en reales (BRL). Debe tener como máximo 2 decimales.
Mínimo: 0.01
Ejemplo: 150.00
transaction.descriptionstringobrigatorioDescripción de la transacción que aparecerá en el extracto del pagador.
Máximo: 100 caracteres
Ejemplo: "Pago del pedido #12345"
transaction.expirationTimenumberTiempo de expiración en segundos.
Mínimo: 30 (30 segundos)
Máximo: 604800 (7 días)
Predeterminado: 86400 (24 horas)
El liquidador de la cuenta puede aceptar un rango más estrecho; en ese caso la API responde 400 con PROVIDER_EXPIRATION_BELOW_MINIMUM o PROVIDER_EXPIRATION_ABOVE_MAXIMUM. Vea Límites de expiración.
transaction.externalIdstringobrigatorioIdentificador externo único de la transacción, por cuenta. Úselo para correlacionar con su sistema. Si se repite, la API devuelve 400 con code PIX_DUPLICATE_EXTERNAL_ID. No puede empezar con MIRROR: (prefijo reservado).
Máximo: 50 caracteres
Recomendación: Use un formato que incluya fecha/hora para garantizar unicidad
Ejemplo: "ORDER-12345-20240119-1430"
transaction.generateQrCodebooleanDefine si se debe generar el QR Code en Base64.
Predeterminado: false
Recomendación: Use true para mostrar el QR Code al usuario
Objeto Payer
Los campos payer son obligatorios en la API, pero son informativos: sirven para registro (extracto, auditoría, identificación de la contraparte) y no restringen quién puede pagar el cobro.
Enfoque simplificado: Si su caso de uso no exige recopilar datos del pagador (ej.: e-commerce donde cualquier persona puede pagar), puede enviar valores fijos como el CNPJ y la razón social de la cuenta receptora. No es necesario solicitar CPF/nombre al pagador final.
payer.fullNamestringobrigatorioNombre del pagador o identificador fijo.
Máximo: 100 caracteres
Uso: Campo informativo — se almacena en los registros de la transacción para identificación. No se valida contra ningún registro.
Ejemplos:
- Datos reales del cliente:
"Carlos Oliveira" - Valor fijo (razón social de la cuenta):
"Mi Empresa Ltda"
payer.documentstringobrigatorioCPF o CNPJ del pagador (solo números). Validación solo de formato (11 o 14 dígitos).
CPF: 11 dígitos | CNPJ: 14 dígitos
Uso: Campo informativo: no restringe quién puede pagar el cobro. Puede ser el documento del propio integrador.
Ejemplos:
- CPF real del cliente:
"12345678901" - CNPJ fijo de la cuenta receptora:
"12345678000199"
Objeto Additional Info
additionalInfoobjectInformación adicional en formato clave-valor (string:string). Los valores deben ser strings. La clave mirror está reservada y no puede usarse.
Máximo: 10 claves
Ejemplo:
{
"orderId": "12345",
"customerId": "67890",
"storeName": "Tech Solutions"
}Array Splits (Opcional)
splitsarrayLista de destinatarios para la división automática del pago recibido. Cuando el PIX-IN se confirma, el valor se divide y se envía automáticamente a los destinatarios. Solo se acepta en cuentas con split habilitado.
Máximo: 10 destinatarios por transacción (o el límite de la cuenta, si es menor)
splits[].pixKeystringobrigatorioClave PIX del destinatario del split.
Máximo: 255 caracteres
Ejemplo: "proveedor@email.com"
splits[].pixKeyTypestringobrigatorioTipo de clave PIX del destinatario.
Valores posibles: EMAIL, PHONE, CPF, CNPJ, RANDOM
Ejemplo: "EMAIL"
splits[].namestringobrigatorioNombre completo del destinatario.
Máximo: 255 caracteres
Ejemplo: "Proveedor Ltda"
splits[].documentstringobrigatorioCPF o CNPJ del destinatario (solo dígitos).
CPF: 11 dígitos | CNPJ: 14 dígitos
Ejemplo: "12345678000199"
splits[].typestringobrigatorioTipo de split: valor fijo o porcentual.
Valores posibles:
FIXED— Valor fijo en reales (ej.:10.00= R$ 10,00)PERCENTAGE— Porcentaje directo (ej.:10= 10%)
Ejemplo: "PERCENTAGE"
splits[].valuenumberobrigatorioValor del split según el tipo:
- FIXED: Valor en reales con hasta 2 decimales.
10.50= R$ 10,50 - PERCENTAGE: Porcentaje directo.
10= 10%,25.5= 25,5%
Mínimo: 0.01
Ejemplo: 10 (10% para PERCENTAGE) o 10.00 (R$ 10,00 para FIXED)
splits[].immediatebooleanSi es true, el split se ejecuta inmediatamente después de la confirmación del PIX-IN, ignorando la frecuencia configurada en la cuenta.
Predeterminado: false
La suma de los splits (valores fijos + porcentajes sobre el valor bruto) más las tarifas no puede exceder el valor de la transacción, y la suma de los porcentajes no puede superar el 100%. De lo contrario, la API devuelve 400 (SPLIT_EXCEEDS_AMOUNT o SPLIT_PERCENTAGE_EXCEEDS_100).
Estructura de la Respuesta
transactionIdstringsempre presenteID interno de la transacción generado por FyPay.
Ejemplo: "7845"
correlationIdstringsempre presenteUUID para el rastreo y la correlación de la transacción.
Ejemplo: "550e8400-e29b-41d4-a716-446655440000"
externalIdstringsempre presenteID externo proporcionado en la solicitud (mismo valor que la entrada).
Ejemplo: "ORDER-12345-20240119"
statusstringsempre presenteEstado actual de la transacción.
Valores posibles:
PENDING: Esperando el pagoCONFIRMED: Pago confirmadoERROR: Error en el procesamiento
Ejemplo: "PENDING"
pixCodestringsempre presenteCódigo PIX en formato EMV (Pix Copia e Cola).
Ejemplo: "00020126580014br.gov.bcb.pix..."
generateTimestringsempre presenteFecha y hora de generación del cobro (ISO 8601 UTC).
Ejemplo: "2024-01-19T14:30:00.000Z"
expirationDatestringsempre presenteFecha y hora de expiración del cobro (ISO 8601 UTC).
Ejemplo: "2024-01-20T14:30:00.000Z"
qrCodeImagestringQR Code en Base64 en formato Data URL. Se devuelve solo cuando generateQrCode: true en la solicitud.
Formato: data:image/png;base64,{base64_encoded_image}
Ejemplo: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAASwAAAEsCAYAAAB5fY51..."
Uso: Puede mostrarse directamente en una etiqueta <img> en HTML o decodificarse para guardarse como archivo.
Ejemplos de Implementación
Node.js / TypeScript
import axios from 'axios';
interface CashInRequest {
transaction: {
value: number;
description: string;
expirationTime?: number;
externalId: string;
generateQrCode?: boolean;
};
payer: {
fullName: string;
document: string;
};
additionalInfo?: Record<string, string>;
}
interface CashInResponse {
transactionId: string;
correlationId: string;
externalId: string;
status: 'PENDING' | 'CONFIRMED' | 'ERROR';
pixCode: string;
generateTime: string;
expirationDate: string;
qrCodeImage?: string; // Presente solo cuando generateQrCode: true
}
async function createPixCharge(
token: string,
orderId: string,
amount: number,
customerName: string,
customerDocument: string
): Promise<CashInResponse> {
const payload: CashInRequest = {
transaction: {
value: amount,
description: `Pago del pedido ${orderId}`,
expirationTime: 3600, // 1 hora
externalId: `ORDER-${orderId}-${Date.now()}`,
generateQrCode: true
},
payer: {
fullName: customerName,
document: customerDocument
},
additionalInfo: {
orderId: orderId,
timestamp: new Date().toISOString()
}
};
try {
const response = await axios.post<CashInResponse>(
'https://api.fypay.me/api/pix/cash-in',
payload,
{
headers: {
'Authorization': `Bearer ${token}`,
'Content-Type': 'application/json'
}
}
);
console.log('¡Cobro PIX generado con éxito!');
console.log(`ID de la Transacción: ${response.data.transactionId}`);
console.log(`Código PIX: ${response.data.pixCode}`);
console.log(`Expira el: ${new Date(response.data.expirationDate).toLocaleString('es')}`);
if (response.data.qrCodeImage) {
console.log('Imagen del QR Code disponible para mostrar');
}
return response.data;
} catch (error) {
if (axios.isAxiosError(error)) {
console.error('Error al generar el cobro:', error.response?.data);
throw new Error(error.response?.data?.message || 'Error al generar el cobro PIX');
}
throw error;
}
}
// Uso
const token = 'su_token_aqui';
createPixCharge(token, '12345', 150.00, 'Carlos Oliveira', '12345678901');Python
import requests
from datetime import datetime, timedelta
from typing import Dict, Optional
def create_pix_charge(
token: str,
order_id: str,
amount: float,
customer_name: str,
customer_document: str,
expiration_hours: float = 1,
additional_info: Optional[Dict[str, str]] = None
) -> Dict:
"""
Genera un cobro PIX
Args:
token: Token Bearer válido
order_id: ID del pedido
amount: Valor en reales
customer_name: Nombre del cliente
customer_document: CPF o CNPJ (solo números)
expiration_hours: Horas hasta la expiración (predeterminado: 1)
additional_info: Información adicional
Returns:
Datos del cobro generado
"""
url = 'https://api.fypay.me/api/pix/cash-in'
payload = {
'transaction': {
'value': round(amount, 2),
'description': f'Pago del pedido {order_id}',
'expirationTime': int(expiration_hours * 3600),
'externalId': f'ORDER-{order_id}-{int(datetime.now().timestamp())}',
'generateQrCode': True
},
'payer': {
'fullName': customer_name,
'document': customer_document
},
'additionalInfo': additional_info or {}
}
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('¡Cobro PIX generado con éxito!')
print(f"ID de la Transacción: {data['transactionId']}")
print(f"Código PIX: {data['pixCode']}")
print(f"Estado: {data['status']}")
expiration = datetime.fromisoformat(data['expirationDate'].replace('Z', '+00:00'))
print(f"Expira el: {expiration.strftime('%d/%m/%Y %H:%M:%S')}")
if 'qrCodeImage' in data:
print('Imagen del QR Code disponible para mostrar')
return data
except requests.exceptions.RequestException as e:
print(f'Error al generar el cobro: {e}')
if hasattr(e.response, 'json'):
print(f'Detalles: {e.response.json()}')
raise
# Uso
token = 'su_token_aqui'
charge = create_pix_charge(
token=token,
order_id='12345',
amount=150.00,
customer_name='Carlos Oliveira',
customer_document='12345678901',
expiration_hours=24,
additional_info={
'storeName': 'Tech Solutions',
'productCategory': 'Electrónicos'
}
)PHP
<?php
function createPixCharge(
string $token,
string $orderId,
float $amount,
string $customerName,
string $customerDocument,
int $expirationHours = 1
): array {
$url = 'https://api.fypay.me/api/pix/cash-in';
$payload = [
'transaction' => [
'value' => round($amount, 2),
'description' => "Pago del pedido $orderId",
'expirationTime' => $expirationHours * 3600,
'externalId' => "ORDER-$orderId-" . time(),
'generateQrCode' => true
],
'payer' => [
'fullName' => $customerName,
'document' => $customerDocument
],
'additionalInfo' => [
'orderId' => $orderId
]
];
$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) {
throw new Exception("Error al generar el cobro: HTTP $httpCode - $response");
}
$data = json_decode($response, true);
echo "¡Cobro PIX generado con éxito!" . PHP_EOL;
echo "ID de la Transacción: {$data['transactionId']}" . PHP_EOL;
echo "Código PIX: {$data['pixCode']}" . PHP_EOL;
echo "Estado: {$data['status']}" . PHP_EOL;
if (isset($data['qrCodeImage'])) {
echo "Imagen del QR Code disponible para mostrar" . PHP_EOL;
}
return $data;
}
// Uso
$token = 'su_token_aqui';
$charge = createPixCharge(
$token,
'12345',
150.00,
'Carlos Oliveira',
'12345678901',
24
);Casos de Uso
1. E-commerce - Checkout con PIX
// Integración en el checkout de e-commerce
class PixCheckout {
constructor(token) {
this.token = token;
}
async generatePayment(order) {
const charge = await createPixCharge(
this.token,
order.id,
order.total,
order.customer.name,
order.customer.document
);
// Mostrar el QR Code en la página (usando la imagen de la API o generándolo localmente)
this.displayQrCode(charge);
// Iniciar polling para verificar el pago
this.startPaymentPolling(charge.transactionId);
return charge;
}
displayQrCode(charge) {
const qrCanvas = document.getElementById('qr-canvas');
const qrImage = document.getElementById('qr-image');
// Usar la imagen Base64 de la API (preferible - evita procesamiento en el cliente)
if (charge.qrCodeImage) {
qrImage.src = charge.qrCodeImage;
qrImage.style.display = 'block';
qrCanvas.style.display = 'none';
} else {
// Alternativa: generar el QR Code localmente usando una biblioteca (ej.: qrcode.js)
QRCode.toCanvas(qrCanvas, charge.pixCode, {
width: 300,
margin: 2
});
qrCanvas.style.display = 'block';
qrImage.style.display = 'none';
}
// Mostrar también el código Pix Copia e Cola
document.getElementById('pix-code').textContent = charge.pixCode;
}
startPaymentPolling(transactionId) {
// Verificar el estado cada 3 segundos
const interval = setInterval(async () => {
const status = await this.checkPaymentStatus(transactionId);
if (status === 'CONFIRMED') {
clearInterval(interval);
this.onPaymentConfirmed();
}
}, 3000);
// Detener después de 10 minutos
setTimeout(() => clearInterval(interval), 10 * 60 * 1000);
}
onPaymentConfirmed() {
// Redirigir a la página de éxito
window.location.href = '/payment/success';
}
}2. PDV (Punto de Venta)
class PixPDV:
"""Sistema de PDV con cobro PIX"""
def __init__(self, token: str):
self.token = token
def process_sale(self, items: list, customer: dict) -> dict:
"""Procesar la venta y generar el cobro PIX"""
# Calcular el total
total = sum(item['price'] * item['quantity'] for item in items)
# Generar la descripción
description = self.generate_sale_description(items)
# Crear el cobro PIX (expira en 15 minutos)
charge = create_pix_charge(
token=self.token,
order_id=self.generate_sale_id(),
amount=total,
customer_name=customer['name'],
customer_document=customer['document'],
expiration_hours=0.25, # 15 minutos
additional_info={
'items_count': str(len(items)),
'cashier_id': self.get_cashier_id()
}
)
# Imprimir el comprobante con QR Code
self.print_receipt(charge, items, total)
return charge
def generate_sale_description(self, items: list) -> str:
"""Generar una descripción resumida de la venta"""
if len(items) == 1:
return f"{items[0]['name']}"
else:
return f"{len(items)} ítems - {items[0]['name']} y más"
def print_receipt(self, charge: dict, items: list, total: float):
"""Imprimir el comprobante con QR Code"""
# Implementar impresión térmica o generar PDF
print("\n" + "="*50)
print("COMPROBANTE DE COBRO PIX")
print("="*50)
for item in items:
print(f"{item['name']}: R$ {item['price']:.2f}")
print("-"*50)
print(f"TOTAL: R$ {total:.2f}")
print(f"\nID de la Transacción: {charge['transactionId']}")
print(f"Código PIX:\n{charge['pixCode']}")
print("="*50 + "\n")3. SaaS - Cobro de Suscripción
class SubscriptionBilling {
constructor(private token: string) {}
async chargeMonthlySubscription(
subscriptionId: string,
userId: string,
planValue: number
) {
// Buscar datos del usuario
const user = await this.getUserData(userId);
// Generar cobro con expiración de 3 días
const charge = await createPixCharge(
this.token,
`SUB-${subscriptionId}-${new Date().getMonth() + 1}`,
planValue,
user.name,
user.document
);
// Enviar email con el enlace de pago
await this.sendPaymentEmail(user.email, charge, planValue);
// Programar recordatorio 1 día antes de expirar
await this.scheduleReminder(user, charge, 24);
return charge;
}
async sendPaymentEmail(email: string, charge: CashInResponse, planValue: number) {
// Implementar el envío de email
const paymentLink = `https://app.exemplo.com/payment/${charge.transactionId}`;
await sendEmail({
to: email,
subject: 'Factura disponible - Pague con PIX',
html: `
<h2>Su factura está disponible</h2>
<p>Valor: R$ ${planValue.toFixed(2)}</p>
<p>Vencimiento: ${new Date(charge.expirationDate).toLocaleDateString('es')}</p>
<p><a href="${paymentLink}">Haga clic aquí para pagar con PIX</a></p>
`
});
}
}Monitoreo de Pagos
Para ser notificado cuando se confirme un pago, puede:
Configure un webhook del evento cash_in para recibir el evento CashIn cuando se confirme el pago. Vea Webhooks.
// Endpoint de webhook en su servidor
app.post('/webhooks/pix', (req, res) => {
const { event, transactionId, status, externalId } = req.body;
if (event === 'CashIn' && status === 'CONFIRMED') {
// Procesar el pago confirmado
processPaymentConfirmation(externalId);
}
res.sendStatus(200);
});Consulte periódicamente el estado con GET /api/pix/transaction/\{id\} (acepta el transactionId numérico o su externalId).
async function monitorPayment(transactionId, maxAttempts = 200) {
for (let i = 0; i < maxAttempts; i++) {
const status = await checkTransactionStatus(transactionId);
if (status === 'CONFIRMED') {
return true;
}
// Esperar 3 segundos antes de intentar de nuevo
await new Promise(resolve => setTimeout(resolve, 3000));
}
return false; // Timeout
}Códigos de Respuesta
| Código | Descripción | Significado |
|---|---|---|
201 | Cobro Creado | Cobro PIX generado con éxito |
400 | Datos Inválidos | Campos obligatorios ausentes o en formato inválido (PUB_REQUEST_BODY_INVALID o error de validación con detalles por campo), externalId repetido (PIX_DUPLICATE_EXTERNAL_ID), límite de la cuenta excedido (PIX_TRANSACTION_LIMIT_EXCEEDED, PIX_DAILY_LIMIT_EXCEEDED, PIX_NIGHT_LIMIT_EXCEEDED, PIX_LIMIT_EXCEEDED), expiración fuera del rango del liquidador (PROVIDER_EXPIRATION_BELOW_MINIMUM, PROVIDER_EXPIRATION_ABOVE_MAXIMUM) o error de split (SPLIT_*) |
401 | Token Inválido | Token no proporcionado, expirado o inválido |
500 | Error Interno | Error inesperado al generar el cobro. Consulte por el externalId antes de intentar de nuevo |
Consulte la Referencia de la API para detalles completos de los campos de respuesta.
Mejores Prácticas
Notas Importantes
Los cobros expirados no pueden reactivarse. Genere un nuevo cobro si es necesario.
- Valor mínimo: R$ 0,01 | Decimales: Máximo 2
- Expiración mínima: 30 segundos (
30), o el mínimo del liquidador de la cuenta, si es mayor - Expiración máxima: 7 días (
604800), o el máximo del liquidador de la cuenta, si es menor externalId: Máximo 50 caracteres, único por cuentadescription: Máximo 100 caracterespayer.fullName: Máximo 100 caracteres