PIX Cash-In(收款)
概述
PIX Cash-In 端点允许您生成动态 PIX 收款以接收付款。每笔收款都会生成唯一的二维码和 PIX 代码(Pix 复制粘贴码),您的客户可以用它完成付款。
此端点需要有效的 Bearer token。详情请参阅认证文档。
功能特性
- 生成动态二维码
- EMV 格式的 PIX 代码(复制粘贴)
- 可配置过期时间(30 秒到 7 天,受账户清算机构的范围限制)
- 通过
externalId唯一标识 - 可自定义附加信息
- 校验付款人 CPF/CNPJ 的格式
- 支付分账(在账户中启用时):在多个收款方之间自动分配
端点
POST /api/pix/cash-in
生成一笔新的 PIX 收款。
必需请求头
Authorization: Bearer {token}
Content-Type: application/json请求体
{
"transaction": {
"value": 150.00,
"description": "订单 #12345 付款",
"expirationTime": 86400,
"externalId": "ORDER-12345-20240119",
"generateQrCode": true
},
"payer": {
"fullName": "Carlos Oliveira",
"document": "12345678901"
},
"additionalInfo": {
"orderId": "12345",
"storeName": "Tech Solutions",
"productCategory": "电子产品"
},
"splits": [
{
"pixKey": "fornecedor@email.com",
"pixKeyType": "EMAIL",
"name": "Fornecedor Ltda",
"document": "12345678000199",
"type": "PERCENTAGE",
"value": 10,
"immediate": false
}
]
}请求
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": "订单 #12345 付款",
"expirationTime": 86400,
"externalId": "ORDER-12345-20240119",
"generateQrCode": true
},
"payer": {
"fullName": "Carlos Oliveira",
"document": "12345678901"
},
"additionalInfo": {
"orderId": "12345"
},
"splits": [
{
"pixKey": "fornecedor@email.com",
"pixKeyType": "EMAIL",
"name": "Fornecedor Ltda",
"document": "12345678000199",
"type": "PERCENTAGE",
"value": 70,
"immediate": false
}
]
}'splits 字段为可选,且仅在启用了分账的账户中被接受(否则 API 返回 400 SPLIT_NOT_CONFIGURED)。有关类型、金额格式和频率的完整详情,请参阅分账付款指南。
响应 (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..."
}仅当请求中发送 generateQrCode: true 时才会返回 qrCodeImage 字段。该值是以 Base64 编码、Data URL 格式表示的二维码 PNG 图片。
请求参数
Transaction 对象
transaction.valuenumberobrigatorio交易金额,单位为巴西雷亚尔(BRL)。最多 2 位小数。
最小值: 0.01
示例: 150.00
transaction.descriptionstringobrigatorio将显示在付款人对账单中的交易描述。
最大长度: 100 个字符
示例: "订单 #12345 付款"
transaction.expirationTimenumber过期时间,以秒为单位。
最小值: 30(30 秒)
最大值: 604800(7 天)
默认值: 86400(24 小时)
账户的清算机构可能只接受更窄的范围;此时 API 返回 400,附带 PROVIDER_EXPIRATION_BELOW_MINIMUM 或 PROVIDER_EXPIRATION_ABOVE_MAXIMUM。参见过期时间限制。
transaction.externalIdstringobrigatorio交易的外部唯一标识符(按账户)。用于与您的系统关联。如果重复,API 返回 400,code 为 PIX_DUPLICATE_EXTERNAL_ID。不能以 MIRROR: 开头(保留前缀)。
最大长度: 50 个字符
建议: 使用包含日期/时间的格式以确保唯一性
示例: "ORDER-12345-20240119-1430"
transaction.generateQrCodeboolean是否生成 Base64 格式的二维码。
默认值: false
建议: 需要向用户展示二维码时使用 true
Payer 对象
payer 字段在 API 中为必填,但仅具信息性:用于记录(对账单、审计、识别交易对手),不限制谁可以支付该收款。
简化做法: 如果您的使用场景不需要收集付款人数据(例如任何人都可以付款的电商),您可以发送固定值,例如收款账户的 CNPJ 和公司名称。无需向最终付款人索取 CPF/姓名。
payer.fullNamestringobrigatorio付款人姓名或固定标识。
最大长度: 100 个字符
用途: 信息性字段 — 存储在交易记录中用于识别。不会与任何登记信息进行校验。
示例:
- 客户真实数据:
"Carlos Oliveira" - 固定值(账户的公司名称):
"Minha Empresa Ltda"
payer.documentstringobrigatorio付款人的 CPF 或 CNPJ(仅数字)。仅校验格式(11 或 14 位)。
CPF: 11 位 | CNPJ: 14 位
用途: 信息性字段:不限制谁可以支付该收款。可以是集成方自己的证件号。
示例:
- 客户真实 CPF:
"12345678901" - 收款账户的固定 CNPJ:
"12345678000199"
Additional Info 对象
additionalInfoobject键值对格式(string:string)的附加信息。值必须为字符串。mirror 键为保留键,不能使用。
最大数量: 10 个键
示例:
{
"orderId": "12345",
"customerId": "67890",
"storeName": "Tech Solutions"
}Splits 数组(可选)
splitsarray用于自动分配所收付款的收款方列表。PIX-IN 确认后,金额会被分配并自动发送给各收款方。仅在启用了分账的账户中被接受。
最大数量: 每笔交易 10 个收款方(如果账户限额更低则以账户为准)
splits[].pixKeystringobrigatorio分账收款方的 PIX 密钥。
最大长度: 255 个字符
示例: "fornecedor@email.com"
splits[].pixKeyTypestringobrigatorio收款方 PIX 密钥的类型。
可能的值: EMAIL、PHONE、CPF、CNPJ、RANDOM
示例: "EMAIL"
splits[].namestringobrigatorio收款方全名。
最大长度: 255 个字符
示例: "Fornecedor Ltda"
splits[].documentstringobrigatorio收款方的 CPF 或 CNPJ(仅数字)。
CPF: 11 位 | CNPJ: 14 位
示例: "12345678000199"
splits[].typestringobrigatorio分账类型:固定金额或百分比。
可能的值:
FIXED— 以雷亚尔计的固定金额(例如10.00= R$ 10,00)PERCENTAGE— 直接填写百分比(例如10= 10%)
示例: "PERCENTAGE"
splits[].valuenumberobrigatorio按类型确定的分账值:
- FIXED: 以雷亚尔计的金额,最多 2 位小数。
10.50= R$ 10,50 - PERCENTAGE: 直接填写百分比。
10= 10%,25.5= 25.5%
最小值: 0.01
示例: 10(PERCENTAGE 表示 10%)或 10.00(FIXED 表示 R$ 10,00)
splits[].immediateboolean如果为 true,分账会在 PIX-IN 确认后立即执行,忽略账户配置的频率。
默认值: false
分账总和(固定金额 + 按毛额计算的百分比)加上手续费不能超过交易金额,且百分比总和不能超过 100%。否则 API 返回 400(SPLIT_EXCEEDS_AMOUNT 或 SPLIT_PERCENTAGE_EXCEEDS_100)。
响应结构
transactionIdstringsempre presenteFyPay 生成的交易内部 ID。
示例: "7845"
correlationIdstringsempre presente用于追踪和关联交易的 UUID。
示例: "550e8400-e29b-41d4-a716-446655440000"
externalIdstringsempre presente请求中提供的外部 ID(与输入值相同)。
示例: "ORDER-12345-20240119"
statusstringsempre presente交易的当前状态。
可能的值:
PENDING:等待付款CONFIRMED:付款已确认ERROR:处理出错
示例: "PENDING"
pixCodestringsempre presenteEMV 格式的 PIX 代码(Pix 复制粘贴码)。
示例: "00020126580014br.gov.bcb.pix..."
generateTimestringsempre presente收款生成的日期和时间(ISO 8601 UTC)。
示例: "2024-01-19T14:30:00.000Z"
expirationDatestringsempre presente收款过期的日期和时间(ISO 8601 UTC)。
示例: "2024-01-20T14:30:00.000Z"
qrCodeImagestringBase64 编码、Data URL 格式的二维码。仅当请求中 generateQrCode: true 时返回。
格式: data:image/png;base64,{base64_encoded_image}
示例: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAASwAAAEsCAYAAAB5fY51..."
用途: 可以直接在 HTML 的 <img> 标签中显示,或解码后保存为文件。
实现示例
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; // 仅当 generateQrCode: true 时存在
}
async function createPixCharge(
token: string,
orderId: string,
amount: number,
customerName: string,
customerDocument: string
): Promise<CashInResponse> {
const payload: CashInRequest = {
transaction: {
value: amount,
description: `订单 ${orderId} 付款`,
expirationTime: 3600, // 1 小时
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('PIX 收款已成功生成!');
console.log(`交易 ID:${response.data.transactionId}`);
console.log(`PIX 代码:${response.data.pixCode}`);
console.log(`过期时间:${new Date(response.data.expirationDate).toLocaleString('pt-BR')}`);
if (response.data.qrCodeImage) {
console.log('二维码图片可供显示');
}
return response.data;
} catch (error) {
if (axios.isAxiosError(error)) {
console.error('生成收款出错:', error.response?.data);
throw new Error(error.response?.data?.message || '生成 PIX 收款出错');
}
throw error;
}
}
// 用法
const token = 'your_token_here';
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:
"""
生成 PIX 收款
Args:
token: 有效的 Bearer token
order_id: 订单 ID
amount: 金额(雷亚尔)
customer_name: 客户姓名
customer_document: CPF 或 CNPJ(仅数字)
expiration_hours: 距离过期的小时数(默认:1)
additional_info: 附加信息
Returns:
已生成收款的数据
"""
url = 'https://api.fypay.me/api/pix/cash-in'
payload = {
'transaction': {
'value': round(amount, 2),
'description': f'订单 {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('PIX 收款已成功生成!')
print(f"交易 ID:{data['transactionId']}")
print(f"PIX 代码:{data['pixCode']}")
print(f"状态:{data['status']}")
expiration = datetime.fromisoformat(data['expirationDate'].replace('Z', '+00:00'))
print(f"过期时间:{expiration.strftime('%d/%m/%Y %H:%M:%S')}")
if 'qrCodeImage' in data:
print('二维码图片可供显示')
return data
except requests.exceptions.RequestException as e:
print(f'生成收款出错:{e}')
if hasattr(e.response, 'json'):
print(f'详情:{e.response.json()}')
raise
# 用法
token = 'your_token_here'
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': '电子产品'
}
)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' => "订单 $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("生成收款出错:HTTP $httpCode - $response");
}
$data = json_decode($response, true);
echo "PIX 收款已成功生成!" . PHP_EOL;
echo "交易 ID:{$data['transactionId']}" . PHP_EOL;
echo "PIX 代码:{$data['pixCode']}" . PHP_EOL;
echo "状态:{$data['status']}" . PHP_EOL;
if (isset($data['qrCodeImage'])) {
echo "二维码图片可供显示" . PHP_EOL;
}
return $data;
}
// 用法
$token = 'your_token_here';
$charge = createPixCharge(
$token,
'12345',
150.00,
'Carlos Oliveira',
'12345678901',
24
);使用场景
1. 电商 - PIX 结账
// 电商结账集成
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
);
// 在页面上显示二维码(使用 API 返回的图片或在本地生成)
this.displayQrCode(charge);
// 开始轮询以检查付款
this.startPaymentPolling(charge.transactionId);
return charge;
}
displayQrCode(charge) {
const qrCanvas = document.getElementById('qr-canvas');
const qrImage = document.getElementById('qr-image');
// 使用 API 返回的 Base64 图片(推荐 - 避免在客户端处理)
if (charge.qrCodeImage) {
qrImage.src = charge.qrCodeImage;
qrImage.style.display = 'block';
qrCanvas.style.display = 'none';
} else {
// 备用方案:使用库在本地生成二维码(例如 qrcode.js)
QRCode.toCanvas(qrCanvas, charge.pixCode, {
width: 300,
margin: 2
});
qrCanvas.style.display = 'block';
qrImage.style.display = 'none';
}
// 同时显示 Pix 复制粘贴码
document.getElementById('pix-code').textContent = charge.pixCode;
}
startPaymentPolling(transactionId) {
// 每 3 秒检查一次状态
const interval = setInterval(async () => {
const status = await this.checkPaymentStatus(transactionId);
if (status === 'CONFIRMED') {
clearInterval(interval);
this.onPaymentConfirmed();
}
}, 3000);
// 10 分钟后停止
setTimeout(() => clearInterval(interval), 10 * 60 * 1000);
}
onPaymentConfirmed() {
// 跳转到成功页面
window.location.href = '/payment/success';
}
}2. POS(销售终端)
class PixPDV:
"""带 PIX 收款的 POS 系统"""
def __init__(self, token: str):
self.token = token
def process_sale(self, items: list, customer: dict) -> dict:
"""处理销售并生成 PIX 收款"""
# 计算总额
total = sum(item['price'] * item['quantity'] for item in items)
# 生成描述
description = self.generate_sale_description(items)
# 创建 PIX 收款(15 分钟后过期)
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 分钟
additional_info={
'items_count': str(len(items)),
'cashier_id': self.get_cashier_id()
}
)
# 打印带二维码的凭条
self.print_receipt(charge, items, total)
return charge
def generate_sale_description(self, items: list) -> str:
"""生成销售的简要描述"""
if len(items) == 1:
return f"{items[0]['name']}"
else:
return f"{len(items)} 件商品 - {items[0]['name']} 等"
def print_receipt(self, charge: dict, items: list, total: float):
"""打印带二维码的凭条"""
# 实现热敏打印或生成 PDF
print("\n" + "="*50)
print("PIX 收款凭条")
print("="*50)
for item in items:
print(f"{item['name']}: R$ {item['price']:.2f}")
print("-"*50)
print(f"合计:R$ {total:.2f}")
print(f"\n交易 ID:{charge['transactionId']}")
print(f"PIX 代码:\n{charge['pixCode']}")
print("="*50 + "\n")3. SaaS - 订阅计费
class SubscriptionBilling {
constructor(private token: string) {}
async chargeMonthlySubscription(
subscriptionId: string,
userId: string,
planValue: number
) {
// 获取用户数据
const user = await this.getUserData(userId);
// 生成 3 天后过期的收款
const charge = await createPixCharge(
this.token,
`SUB-${subscriptionId}-${new Date().getMonth() + 1}`,
planValue,
user.name,
user.document
);
// 发送带付款链接的邮件
await this.sendPaymentEmail(user.email, charge, planValue);
// 安排在过期前 1 天发送提醒
await this.scheduleReminder(user, charge, 24);
return charge;
}
async sendPaymentEmail(email: string, charge: CashInResponse, planValue: number) {
// 实现邮件发送
const paymentLink = `https://app.exemplo.com/payment/${charge.transactionId}`;
await sendEmail({
to: email,
subject: '账单已生成 - 使用 PIX 支付',
html: `
<h2>您的账单已生成</h2>
<p>金额:R$ ${planValue.toFixed(2)}</p>
<p>到期日:${new Date(charge.expirationDate).toLocaleDateString('pt-BR')}</p>
<p><a href="${paymentLink}">点击此处使用 PIX 支付</a></p>
`
});
}
}付款监控
要在付款确认时收到通知,您可以:
配置 cash_in 事件的 webhook,以在付款确认时接收 CashIn 事件。参见 Webhooks。
// 您服务器上的 webhook 端点
app.post('/webhooks/pix', (req, res) => {
const { event, transactionId, status, externalId } = req.body;
if (event === 'CashIn' && status === 'CONFIRMED') {
// 处理已确认的付款
processPaymentConfirmation(externalId);
}
res.sendStatus(200);
});使用 GET /api/pix/transaction/\{id\} 定期查询状态(接受数字 transactionId 或您的 externalId)。
async function monitorPayment(transactionId, maxAttempts = 200) {
for (let i = 0; i < maxAttempts; i++) {
const status = await checkTransactionStatus(transactionId);
if (status === 'CONFIRMED') {
return true;
}
// 等待 3 秒后重试
await new Promise(resolve => setTimeout(resolve, 3000));
}
return false; // 超时
}响应状态码
| 状态码 | 描述 | 含义 |
|---|---|---|
201 | 收款已创建 | PIX 收款已成功生成 |
400 | 数据无效 | 缺少必填字段或格式无效(PUB_REQUEST_BODY_INVALID 或带有逐字段详情的验证错误)、externalId 重复(PIX_DUPLICATE_EXTERNAL_ID)、超出账户限额(PIX_TRANSACTION_LIMIT_EXCEEDED、PIX_DAILY_LIMIT_EXCEEDED、PIX_NIGHT_LIMIT_EXCEEDED、PIX_LIMIT_EXCEEDED)、过期时间超出清算机构范围(PROVIDER_EXPIRATION_BELOW_MINIMUM、PROVIDER_EXPIRATION_ABOVE_MAXIMUM)或分账错误(SPLIT_*) |
401 | 无效 Token | Token 未提供、已过期或无效 |
500 | 内部错误 | 生成收款时出现意外错误。重试前请先通过 externalId 查询 |
请参阅 API 参考 获取响应字段的完整详情。
最佳实践
重要说明
已过期的收款无法重新激活。如有需要,请生成新的收款。
- 最低金额: R$ 0,01 | 小数位: 最多 2 位
- 最短过期时间: 30 秒(
30),如果账户清算机构的最小值更大则以其为准 - 最长过期时间: 7 天(
604800),如果账户清算机构的最大值更小则以其为准 externalId: 最多 50 个字符,每个账户内唯一description: 最多 100 个字符payer.fullName: 最多 100 个字符