docs
集成指南

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 presente

FyPay 生成的交易内部 ID。

示例: "7845"

correlationIdstringsempre presente

用于追踪和关联交易的 UUID。

示例: "550e8400-e29b-41d4-a716-446655440000"

externalIdstringsempre presente

请求中提供的外部 ID(与输入值相同)。

示例: "ORDER-12345-20240119"

statusstringsempre presente

交易的当前状态。

可能的值:

  • PENDING:等待付款
  • CONFIRMED:付款已确认
  • ERROR:处理出错

示例: "PENDING"

pixCodestringsempre presente

EMV 格式的 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"

qrCodeImagestring

Base64 编码、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无效 TokenToken 未提供、已过期或无效
500内部错误生成收款时出现意外错误。重试前请先通过 externalId 查询

请参阅 API 参考 获取响应字段的完整详情。

最佳实践

重要说明

已过期的收款无法重新激活。如有需要,请生成新的收款。

  • 最低金额: R$ 0,01 | 小数位: 最多 2 位
  • 最短过期时间: 30 秒(30),如果账户清算机构的最小值更大则以其为准
  • 最长过期时间: 7 天(604800),如果账户清算机构的最大值更小则以其为准
  • externalId: 最多 50 个字符,每个账户内唯一
  • description: 最多 100 个字符
  • payer.fullName: 最多 100 个字符

后续步骤

本页目录