PIX 支付
PIX 是巴西的即时支付网络。资金在数秒内完成结算,全天候 24/7 运行。Liqfy 为您提供单一端点:在创建收款的同一响应中,返回 BR Code(Pix Copia e Cola)以及可直接在结账页面中渲染的二维码。
**按订单号查询:**创建收款时,将订单号作为 Idempotency-Key 请求头发送。之后使用同一账户的 API 密钥调用 GET /v1/charges/by-idempotency-key/{订单号}。仅设置 metadata.order_id 无法启用此查询。
确认 E2E 后,charge.paid 回调可在 data.object.settlement.end_to_end_id 中携带 Pix E2E。如果 E2E 尚不可用,该字段可能缺失;参见 Webhook。
#流程概览
1. POST /v1/charges ────────▶ Liqfy returns a Charge: ch_…, status "pending", pix.br_code + QR
2. Render QR + Pix Copia e Cola in your UI
3. Customer scans / pastes in their bank app
4. Webhook charge.paid arrives at your endpoint
5. Mark order as paid#1. 创建收款
端点 POST /v1/charges(Pix 优先快捷方式:POST /v1/pix/charges 固定 payment_method: "pix",并覆盖您发送的任何值。除此之外,其行为与 POST /v1/charges 完全相同:相同的请求头、相同的幂等性、相同的测试/正式密钥处理,响应中返回的 Charge 也完全相同)
请求头
Authorization: Bearer lq_live_…
Idempotency-Key: <unique per charge you intend to create>
Content-Type: application/jsonAuthorization: Bearer <key> 是提供 API 密钥的规范方式。Idempotency-Key 在 POST /v1/charges 上是必需的(缺少时返回 400)。它可以是任意非空字符串,按商户隔离((merchant, key))。使用相同的密钥和请求体重放时,将返回原始收款。当响应为重放时,还会携带请求头 Idempotency-Replayed: true,以便您区分重放的收款与新创建的收款。
未通过校验的请求体将被拒绝,并返回 400 及校验详情。
请求体
| 字段 | 类型 | 必需 | 说明 |
|---|---|---|---|
amount | integer | 是 | 单位为分。1000 = R$ 10,00。必须为正整数。 |
currency | string | 否 | 默认为 "BRL",这是 Pix 收款唯一接受的币种。 |
payment_method | string | 是 | "pix"(目前唯一接受的值;/v1/pix/charges 快捷方式会自动为您填写)。 |
description | string | 否 | 最多 500 个字符。在 metadata.description 中原样返回。 |
expires_in | integer | 否 | 距收款到期的秒数(即 Pix 二维码的有效期)。取值范围为 60–604800(最长 7 天)。超出范围的值将被拒绝并返回 400,绝不会被自动截断为上限。省略时使用账户的默认时长(通常为 3600 = 1 小时)。响应中的 pix.expires_at 始终是权威的到期时间。 |
customer.name | string | 否 | 在支持时显示在银行对账单上。 |
customer.document | string | 否 | CPF 或 CNPJ。 |
customer.email | string | 否 | 用于收据。 |
customer.phone | string | 否 | |
expected_payer_tax_id | string | 否 | ⚠️ 将收款锁定到该 CPF/CNPJ:当您的账户启用锁定时,只有该证件可以付款,来自其他证件的付款将被拒绝(或退回,取决于服务商)。如果付款人可能是其他人,请勿发送。如果您的账户未配置锁定,该字段将被忽略,收款正常创建。参见下文 付款人 CPF 锁定。需要 customer.name。必须为有效的 CPF/CNPJ;如果您同时发送了 customer.document,则必须与之一致。 |
metadata | object | 否 | 自由格式的键/值,按原样返回(保留键及以下划线开头的键会被移除)。 |
示例
curl -X POST https://api.liqfy.com.br/v1/charges \
-H "Authorization: Bearer $LIQFY_API_KEY" \
-H "Idempotency-Key: ORD-7821" \
-H "Content-Type: application/json" \
-d '{
"amount": 24900,
"currency": "BRL",
"payment_method": "pix",
"description": "Pedido #7821",
"expires_in": 1800,
"customer": { "name": "Maria Silva", "document": "12345678901" },
"metadata": { "order_id": "ORD-7821", "sku": "premium-monthly" }
}'响应 201 Created
{
"id": "ch_a1b2c3d4-0000-0000-0000-000000000009",
"object": "charge",
"amount": 24900,
"currency": "BRL",
"status": "pending",
"payment_method": "pix",
"customer": { "name": "Maria Silva", "document": "12345678901" },
"pix": {
"br_code": "000201BRCODEPIX",
"qr_code_url": "https://qr.example/img.png",
"expires_at": "2026-07-23T15:00:00.000Z"
},
"checkout_url": "https://checkout.liqfy.com.br/a1b2c3d4-0000-0000-0000-000000000009",
"settlement": {},
"metadata": { "order_id": "ORD-7821", "sku": "premium-monthly", "description": "Pedido #7821" },
"created_at": "2026-07-23T14:30:00.000Z"
}| 字段 | 用法 |
|---|---|
pix.br_code | EMV "Pix Copia e Cola" 载荷。请将其渲染在“复制到剪贴板”按钮中。 |
pix.qr_code_url / pix.qr_code_base64 | 二维码图像(仅当服务商返回时提供):qr_code_url 为 https:// URL(可直接放入 <img src="...">),否则为 qr_code_base64(需解码的 PNG)。仅返回 br_code 的服务商两者都不会提供,因此请始终将 br_code 作为后备进行渲染。 |
checkout_url | 该收款的 Liqfy 托管结账页,即现成的支付页面(二维码、复制粘贴、实时状态)。您可以将付款人重定向到此处,而无需自行构建页面。GET /v1/charges/{id} 也会返回该字段,因此您可以稍后通过已存储的 id 获取。您无法自行构造此 URL,因为结账页需要的是不带 ch_ 前缀的 id。 |
pix.expires_at | 该收款的到期时间。请显示倒计时;到期后,status 变为 expired。 |
pix.txid | BACEN TXID。该字段为可选,仅在服务商绑定了 TXID 时出现。切勿将其视为收款 id。 |
settlement | 始终存在。settlement.end_to_end_id 在结算前通常为空:仅在收款达到 paid 并完成结算/对账后才会出现。 |
pix 对象为 { br_code?, qr_code_url?, qr_code_base64?, expires_at?, txid? }。当没有 br_code、二维码图像或到期时间可显示时,该对象不存在。
#状态
| 状态 | 含义 |
|---|---|
pending | 已创建;等待付款人付款。 |
processing | 已检测到付款;尚未确认(例如因审核而暂扣)。 |
paid | 已付款并入账。 |
failed | 付款被拒绝。 |
expired | expires_at 已过但未付款。 |
cancelled | 在付款前已取消。 |
refunded | 已退还给付款人。 |
disputed | 拒付或争议。 |
#TXID 和 end_to_end_id
ch_… 始终是 Liqfy 收款 id,您应使用它来存储、查询收款以及对账 webhook。pix.txid 和 settlement.end_to_end_id 是由 BACEN 定义的上下文 Pix 数据,仅在适用时出现:
{
"id": "ch_a1b2c3d4-0000-0000-0000-000000000009",
"pix": { "txid": "BACEN-TXID-77" },
"settlement": {}
}charge.id !== charge.pix.txid,始终如此,即使两者都存在也是如此。切勿以 TXID 或 end_to_end_id 作为数据库键;请使用 ch_…。
#付款人 CPF 锁定
设置 expected_payer_tax_id 可要求只有某个特定的 CPF/CNPJ 才能支付收款。例如,用于确保买家从自己的账户而非第三方账户付款。
⚠️ 发送此字段将锁定收款。 当您的账户启用锁定时,只有指定的 CPF/CNPJ 可以付款:任何从其他账户付款的人,其付款都会被银行拒绝(或退回,取决于服务商)。仅在您确实需要此限制时发送,例如必须来自客户本人账户的投注或存款。如果付款人可能是其他人(如父母为孩子付款、公司为合作伙伴付款),请勿发送:请仅使用
customer.document,它仅供参考,不会锁定任何内容。
可用性。 锁定功能默认关闭:它取决于为您账户提供服务的服务商,并且仅在支持团队已完成配置的情况下生效。在未配置锁定的账户上,携带
expected_payer_tax_id的收款会正常创建,不带锁定:任何付款人都可以付款,款项也会入账。您可以从响应中判断:此时收款不包含expected_payer_tax_id。当锁定生效时,该字段会在收款中回显,并适用以下规则。需要锁定功能?请联系支持团队。
curl -X POST https://api.liqfy.com.br/v1/charges \
-H "Authorization: Bearer $LIQFY_API_KEY" \
-H "Idempotency-Key: ORD-7821" \
-H "Content-Type: application/json" \
-d '{
"amount": 24900,
"payment_method": "pix",
"customer": { "name": "Maria Silva", "document": "12345678901" },
"expected_payer_tax_id": "12345678901"
}'工作原理:
- 收款的创建和支付方式与其他任何 Pix 收款完全相同。
- 结算时,Liqfy 从银行读取实际付款人的证件,并与
expected_payer_tax_id进行比对。 - 匹配 → 收款变为
paid,您的余额照常入账。 - 由其他付款人支付 → 取决于为您账户提供服务的服务商如何执行锁定:
- 检测式(fail-closed):收款不会入账。Liqfy 会自动将款项退还给付款人(标准的 Pix devolução,依据原始
end_to_end_id发起);收款保持processing状态,直到退款结算完成,之后才变为refunded。您永远不会收到第三方资金。 - 预防式:银行端规则应在付款到账前拒绝其他付款人。如果第三方仍然成功付款(规则未生效),资金仍会入账,收款保持
paid,并被标记为付款人不匹配;该款项归您所有。
- 检测式(fail-closed):收款不会入账。Liqfy 会自动将款项退还给付款人(标准的 Pix devolução,依据原始
- 银行未披露付款人证件 → 收款将保持
processing状态(永不入账)以进行人工审核,而不会为无法验证的付款人入账。
注意事项:
- 捕获并退还的保证仅适用于检测式(fail-closed)路径:收款保持
processing状态,直到自动退款(devolução)结算完成,之后才变为refunded,并且您的商户余额永远不会因不匹配的付款人而入账。在该路径上,检查发生在结算时,而非在银行层面拦截。在预防式路径上,绕过银行端规则的付款仍会入账,收款保持paid(并被标记为付款人不匹配)。在两种模式下,BACEN 都允许任何付款人扫描二维码,因此付款人的应用仍可能显示该收款。 expected_payer_tax_id需要customer.name(收款和退款都需要该字段),必须为校验和有效的 CPF(11 位)或 CNPJ(14 位);如果您同时发送了customer.document,则必须与之一致。否则请求将被拒绝400。- 该值会在收款中回显(
expected_payer_tax_id);实际付款人的证件永远不会被公开。
#2. 查询收款
端点 GET /v1/charges/{id}
curl https://api.liqfy.com.br/v1/charges/ch_a1b2c3d4-0000-0000-0000-000000000009 \
-H "Authorization: Bearer $LIQFY_API_KEY"接受带 ch_… 前缀的 id 或原始 id。Pix 付款并结算后,settlement.end_to_end_id 会出现,status 变为 paid:
{
"id": "ch_a1b2c3d4-0000-0000-0000-000000000009",
"object": "charge",
"status": "paid",
"amount": 24900,
"currency": "BRL",
"payment_method": "pix",
"customer": { "name": "Maria Silva", "document": "12345678901" },
"settlement": { "end_to_end_id": "E12345678202610281433Zx9Yw8Vu7Ts" },
"metadata": { "order_id": "ORD-7821" },
"created_at": "2026-07-23T14:30:00.000Z"
}#通过 Idempotency-Key 查询
端点 GET /v1/charges/by-idempotency-key/{key}
返回与 GET /v1/charges/{id} 相同的公共 Charge,在您的账户内依据创建时发送的 Idempotency-Key 进行查找。当创建请求超时且您从未收到 ch_… id 时,此端点非常有用。
curl https://api.liqfy.com.br/v1/charges/by-idempotency-key/ORD-7821 \
-H "Authorization: Bearer $LIQFY_API_KEY"密钥会去除首尾空白;空白密钥或长度超过 255 个字符的密钥将被拒绝,并返回 400(Invalid idempotency key)。
#轮询与 webhook
履约和数据库写入请完全依赖 webhook,webhook 是唯一可信来源。GET /v1/charges/{id} 用于按需状态检查(例如支持工具、手动“检查状态”按钮),而不应用于轮询循环。
#3. 列出收款
端点 GET /v1/charges,采用游标分页(绝不使用偏移量:没有 page/offset)。
| 查询参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
limit | int | 25 | 1–100。 |
starting_after | string | — | 游标:您看到的最后一个收款的 ch_… id(或原始 id)。 |
status | string | — | 上述状态之一。 |
created_after / created_before | ISO-8601 datetime | — | 严格 UTC(…Z),带时区偏移的值将被拒绝。 |
customer_id | string | — | 按付款人证件筛选。 |
无效的查询将被拒绝,并返回 400 及校验详情。
curl "https://api.liqfy.com.br/v1/charges?limit=25&status=paid" \
-H "Authorization: Bearer $LIQFY_API_KEY"响应 200 OK,即游标信封:
{
"object": "list",
"data": [ { "id": "ch_a1b2c3d4-0000-0000-0000-000000000009", "object": "charge", "status": "paid" } ],
"has_more": true,
"next_cursor": "ch_a1b2c3d4-0000-0000-0000-000000000009"
}将 next_cursor 作为 starting_after 传入以逐页遍历,直到 has_more 为 false。结果按从新到旧排序。
#4. 接收 webhook
当付款人付款时,您注册的 webhook 端点将收到一个已签名的 POST,其中包含规范的事件信封:
{
"id": "evt_5f3a9b2c1d4e5f6a7b8c9d0e1f2a3b4c",
"object": "event",
"api_version": "2026-07-23",
"type": "charge.paid",
"created_at": "2026-07-23T14:31:00.000Z",
"data": {
"object": {
"id": "ch_a1b2c3d4-0000-0000-0000-000000000009",
"object": "charge",
"amount": 24900,
"currency": "BRL",
"status": "paid",
"payment_method": "pix",
"settlement": { "end_to_end_id": "E12345678202610281433Zx9Yw8Vu7Ts" }
}
}
}有关签名验证、重试语义和注册,请参阅 Webhooks。
#代码示例
使用官方 SDK(所有品牌使用同一个中立的包,请使用本页的 API 基础 URL 进行配置:https://api.liqfy.com.br):
| node | python | php | dotnet |
|---|---|---|---|
client.charges.create(input, { idempotencyKey }) | client.charges.create(input, idempotency_key) | $client->charges->create($input, $idempotencyKey) | client.Charges.CreateAsync(input, idempotencyKey) |
client.charges.retrieve(id) | client.charges.retrieve(id) | $client->charges->retrieve($id) | client.Charges.RetrieveAsync(id) |
client.charges.list(query) | client.charges.list(**query) | $client->charges->list($query) | client.Charges.ListAsync(query) |
charges.list 返回游标信封 { object: "list", data, has_more, next_cursor }。以下是对应的原始 HTTP 示例。
#Node.js (fetch)
const res = await fetch('https://api.liqfy.com.br/v1/charges', {
method: 'POST',
headers: {
'Authorization': `Bearer ${process.env.LIQFY_API_KEY}`,
'Idempotency-Key': order.id,
'Content-Type': 'application/json',
},
body: JSON.stringify({
amount: 24900,
currency: 'BRL',
payment_method: 'pix',
customer: { name: order.customer.name, document: order.customer.document },
metadata: { order_id: order.id },
}),
});
if (!res.ok) throw new Error(`Liqfy ${res.status}: ${await res.text()}`);
const charge = await res.json();
// charge.id (ch_…) → store on the order; charge.pix.br_code / qr_code_url → render immediately#PHP
$ch = curl_init('https://api.liqfy.com.br/v1/charges');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_POST => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . getenv('LIQFY_API_KEY'),
'Idempotency-Key: ' . $order->id,
'Content-Type: application/json',
],
CURLOPT_POSTFIELDS => json_encode([
'amount' => 24900,
'currency' => 'BRL',
'payment_method' => 'pix',
'customer' => ['name' => $order->customerName],
'metadata' => ['order_id' => $order->id],
]),
]);
$body = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
if ($status !== 201) throw new Exception("Liqfy $status: $body");
$charge = json_decode($body, true);#Python (requests)
import os, requests
r = requests.post(
"https://api.liqfy.com.br/v1/charges",
headers={
"Authorization": "Bearer " + os.environ['LIQFY_API_KEY'],
"Idempotency-Key": order.id,
},
json={
"amount": 24900,
"currency": "BRL",
"payment_method": "pix",
"customer": {"name": order.customer.name},
"metadata": {"order_id": order.id},
},
timeout=10,
)
r.raise_for_status()
charge = r.json()#边界情况与常见问题
问:响应中缺少 pix.br_code / 二维码字段。
答:Pix 优先创建会同步返回这些字段。如果缺失,status 通常已显示 failed。请先检查请求是否存在校验错误(使用 GET /v1/charges/{id} 重新读取已存储的收款)。
问:我的创建请求超时了,收款是否已创建?
答:使用相同的 Idempotency-Key 和请求体重试:如果收款已存在,您将获得原始收款(带有 Idempotency-Replayed: true)。您也可以通过 GET /v1/charges/by-idempotency-key/{key} 查询。
问:二维码的有效期有多长?
答:请查看收款上的 pix.expires_at,它按每笔收款单独设置。到期后,status 变为 expired,必须创建新的收款。
问:我可以对 PIX 收款退款吗?
答:目前退款需通过管理后台申请。API 未提供商户可用的退款端点(它会拒绝使用 API 密钥的调用方)。/v1/charges/{id}/refund 同样如此,该端点并不存在。
问:如果客户从未付款,我会被收取费用吗?
答:不会。费用仅适用于 paid 的收款,并且从不会在公共 charge 响应中逐项列出(参见 API 约定 §3)。
问:我的客户支付的金额不正确。
答:PIX 要求金额完全匹配。少付的收款保持 pending,银行会将款项退还给付款人。多付的情况很少见,但处理方式相同。
#下一步
有关 E2E 保证和保留期限,请参阅结算标识符与查询。