银行卡支付
通过由 Liqfy 托管的支付页面接受 Visa、Mastercard、American Express、Elo、Hipercard 及其他主要卡组织的付款——卡数据绝不会经过您的服务器,3D Secure 自动处理。
#流程概览
1. POST /v1/payments ──────▶ Liqfy returns the payment: id, status WAITING_PAYMENT, cardRedirectUrl + checkoutUrl
2. Redirect (or open in iframe) the customer to cardRedirectUrl
3. Customer enters card details + completes 3DS challenge on Liqfy's secure page
4. Customer is bounced back to your returnUrl (success or failure)
5. Webhook charge.paid (or charge.failed) confirms the outcome — trust the webhook, not the redirect为什么要重定向? 这样持卡人数据完全不会进入您的基础设施。您的应用(无论后端还是前端)永远不会看到 PAN、CVV 或有效期。Liqfy 的处理方在我们这一侧负责 3DS、令牌化和欺诈筛查。
#1. 创建支付
端点 POST /v1/payments
curl -X POST https://api.liqfy.com.br/v1/payments \
-H "Authorization: Bearer $LIQFY_API_KEY" \
-H "Idempotency-Key: ORD-9821" \
-H "Content-Type: application/json" \
-d '{
"amount": 8990,
"currency": "EUR",
"paymentMethods": ["CREDIT_CARD"],
"customerName": "João Costa",
"customerEmail": "joao@example.com",
"customerPhone": "+351912345678",
"returnUrl": "https://shop.example.com/orders/9821/return",
"cancelUrl": "https://shop.example.com/cart",
"metadata": { "orderId": "ORD-9821" }
}'幂等性。 POST /v1/payments 接受 Idempotency-Key 请求头(推荐);在缺少该请求头时,也可使用请求体字段 idempotencyKey 作为备选;至少须发送其一。如果两者都发送,它们必须一致——值不一致返回 400,两者都未发送则在此路由上返回 400。可以是任意非空字符串(首尾空白会被去除),作用域为每个商户((merchant, key)):使用相同的键和请求体重放会返回已存储的响应,相同的键配不同的请求体则返回 409。此路由不会返回 Idempotency-Replayed 请求头——请勿基于它构建重试逻辑。
| 字段 | 说明 |
|---|---|
amount | 大于 0 的整数,以最小货币单位(分)计。8990 = € 89,90。 |
currency | 3–8 个字符,默认 "BRL"(BRL、EUR、USD;其他币种可按需开通)。 |
paymentMethods | 此处为 ["CREDIT_CARD"]。API 接受 PIX、CRYPTO、CREDIT_CARD、BOLETO、MBWAY、MULTIBANCO、IDEAL、BANCONTACT、SEPA、BIZUM、SWAP_NOW。至少一项。除非发送了 checkout,否则为必填(否则返回 400 —— paymentMethods is required unless a checkout template is provided)。 |
checkout | 可选的结账模板 slug(1–80)。使用模板时可省略 paymentMethods:由模板加上收费币种决定支付方式,并筛选为实际可路由的方式,它们将成为该笔收费的 paymentMethods。未知 slug → 404;模板服务不可达 → 503。 |
customerId | 可选字符串。 |
customerName / customerDocument / customerEmail / customerPhone | 扁平化的客户字段。customerEmail 必须是电子邮件地址;customerPhone 为自由格式(建议使用 E.164)。强烈建议提供 customerEmail——用于收据、欺诈信号及拒付争议证明。 |
customer | 另一种嵌套形式 { name?, document?, email?, phone? }(email 必须是电子邮件地址);会被展开到上述字段中(以扁平字段为准)。 |
expectedPayerDocument | 仅含数字的预期付款人 CPF/CNPJ;在服务商支持的情况下作为付款人锁定。锁定的收费还需要付款人姓名(customerName),否则返回 PAYER_NAME_REQUIRED。 |
returnUrl | 客户完成支付后(成功或失败)的跳转地址。http(s) URL,不得包含片段(fragment)。规范字段。 |
cancelUrl | 客户中止支付时的跳转地址。URL 规则相同;需要同时提供 returnUrl(否则返回 400 —— cancelUrl requires returnUrl)。 |
metadata | 自由格式的键/值。metadata.returnUrl / metadata.cancelUrl 如存在,必须是 http(s) URL。metadata.returnUrl 仍会驱动托管结账页的重定向,但规范字段是顶层的 returnUrl。 |
items | 可选 { name, quantity, unitPrice, totalPrice }[];name 不能为空,数值为大于 0 的整数。 |
webhookUrl | 可选的单笔交易 webhook URL 覆盖;必须是有效的 URL。 |
idempotencyKey | Idempotency-Key 请求头的请求体备选(见上文)。 |
country | 可选,2–3 个字符;服务商账户路由输入。 |
riskTier | 可选 LOW、MEDIUM 或 HIGH;服务商账户路由输入。 |
environment | 可选 SANDBOX、STAGING、PRODUCTION —— 让您可以明确指定沙盒账户。省略时根据服务器环境推导。 |
expiresIn | 可选的 Pix 二维码有效期(秒),60–604800;作为请求的过期时间转发给服务商(以服务商返回的过期时间为准)。 |
响应 201 Created —— 创建响应已包含支付方式产物(此处为 cardRedirectUrl)和 checkoutUrl;无需再调用 GET 即可查看。
{
"id": "b2c3d4e5-f6a7-4890-9bcd-ef0123456789",
"status": "WAITING_PAYMENT",
"amount": 8990,
"currency": "EUR",
"paymentMethods": ["CREDIT_CARD"],
"customerName": "João Costa",
"customerEmail": "joao@example.com",
"customerPhone": "+351912345678",
"cardRedirectUrl": "https://checkout.liqfy.com.br/c/b2c3d4e5-f6a7-4890-9bcd-ef0123456789",
"checkoutUrl": "https://checkout.liqfy.com.br/b2c3d4e5-f6a7-4890-9bcd-ef0123456789",
"createdAt": "2026-04-25T15:50:11.000Z"
}checkoutUrl 仅在创建和查询时返回——列表行和取消响应中不包含该字段。
#创建时的错误
| HTTP | code | 触发条件 |
|---|---|---|
400 | —(扁平化的校验错误) | 请求体无效;缺少幂等键或请求头/请求体不一致;发送了 cancelUrl 但未提供 returnUrl;缺少 paymentMethods 且未提供 checkout。 |
401 | — | 请求未能识别您的账户(请求必须经过 API 网关认证后到达)。 |
403 | fraud.tenant_velocity_exceeded | 您的账户在短时间内支付尝试过多(默认:每 60 秒 200 次)。 |
403 | fraud.customer_velocity_exceeded | 同一 customerDocument 或 customerEmail 在短时间内支付尝试过多(默认:每 300 秒 10 次)。已过期和已取消的收费不计入;被拒绝的收费计入。两个字段都没有的收费不受此规则限制。 |
404 | — | 未知的 checkout slug。 |
4xx | NO_PROVIDER_CONFIGURED | 此支付方式和币种未配置支付服务商。 |
4xx | UNKNOWN_METHOD | 不支持该支付方式。 |
4xx | MOCK_PROVIDER_IN_PRODUCTION | 该支付方式不可用于正式收费。 |
4xx | PAYER_IDENTITY_REQUIRED | 该收费需要付款人的完整身份信息(姓名、电子邮件、电话和税号)。 |
4xx | PAYER_NAME_REQUIRED | 发送了 expectedPayerDocument 但未提供付款人姓名。 |
4xx | PAYMENT_REJECTED | 服务商拒绝了该收费(也是其他任何服务商侧拒绝的兜底代码)。 |
503 | PROVIDER_UNAVAILABLE | 支付服务商暂时不可用——请稍后重试(使用相同的 Idempotency-Key)。 |
5xx | PROVIDER_ERROR | 服务商返回了意外的响应。 |
服务商侧的 4xx 错误保留路由层返回的 HTTP 状态码。错误消息按设计保持中立——绝不会提及服务商名称或其内部代码;如需详情,请向支持团队提供请求 ID。
使用官方 SDK(所有品牌通用的同一个中立包——通过 https://api.liqfy.com.br 进行配置):
| node | python | php | dotnet |
|---|---|---|---|
client.payments.create(input, { idempotencyKey }) | client.payments.create(input, idempotency_key) | $client->payments->create($input, $idempotencyKey) | client.Payments.CreateAsync(input, idempotencyKey) |
client.payments.retrieve(id) | client.payments.retrieve(id) | $client->payments->retrieve($id) | client.Payments.RetrieveAsync(id) |
client.payments.list(query) | client.payments.list(**query) | $client->payments->list($query) | client.Payments.ListAsync(query) |
payments.list(GET /v1/payments)返回分页封装 { data, total, page, limit }。查询参数:page(默认 1)、limit(默认 20,最大 100)、status、currency、startDate / endDate(ISO-8601 日期时间)、source(API、PANEL、MANUAL、INDEFINIDO)、sortBy、sortOrder(asc / desc)。
#2. 重定向客户
cardRedirectUrl 包含在创建响应中(以及每次 GET /v1/payments/{id} 的响应中),因此您可以立即重定向:
curl https://api.liqfy.com.br/v1/payments/b2c3d4e5-f6a7-4890-9bcd-ef0123456789 \
-H "Authorization: Bearer $LIQFY_API_KEY"{
"id": "b2c3d4e5-f6a7-4890-9bcd-ef0123456789",
"status": "WAITING_PAYMENT",
"amount": 8990,
"currency": "EUR",
"cardRedirectUrl": "https://checkout.liqfy.com.br/c/b2c3d4e5-f6a7-4890-9bcd-ef0123456789",
"createdAt": "2026-04-25T15:50:11.000Z"
}将客户引导至 cardRedirectUrl:
<a href="{{ cardRedirectUrl }}">Pay with card</a>或在服务器端执行 303 See Other:
res.redirect(303, transaction.cardRedirectUrl);客户完成流程(或中止)后,会被跳转回您提供的 returnUrl(托管结账页从 metadata.returnUrl 读取相同的重定向地址),并附加 ?transactionId=...&status=...。不要信任这些查询参数。 它们仅供参考——请在收到 webhook 后再履约。
#3. 通过 webhook 确认
{
"id": "evt_00000000000000000000000000000001",
"object": "event",
"api_version": "2026-07-23",
"type": "charge.paid",
"created_at": "2026-04-25T15:52:34.000Z",
"data": {
"object": {
"id": "ch_b2c3d4e5-f6a7-4890-9bcd-ef0123456789",
"object": "charge",
"status": "paid",
"amount": 8990,
"currency": "EUR",
"payment_method": "card",
"settlement": {}
}
}
}银行卡支付成功时,公开收费状态为 paid。公开状态词汇包括 pending、processing、paid、failed、expired、cancelled、refunded、disputed。
拒绝以 charge.failed 的形式送达;过期优先使用 charge.expired。请读取 data.object.status 获取公开结果。该事件不会暴露发卡行的拒绝原因。
#生命周期
WAITING_PAYMENT ──▶ PROCESSING ──▶ APPROVED ✓ fulfill order
──▶ REFUSED issuer declined
──▶ CANCELLED customer abandoned
──▶ EXPIRED redirect link aged out (24h)结算后(根据卡组织和您的合同,D+1 至 D+30),您还可能看到:
APPROVED ──▶ CHARGEBACK issuer raised a chargeback
APPROVED ──▶ DISPUTE cardholder opened a dispute
APPROVED ──▶ REFUNDED you (or Liqfy) issued a refund每种状态都会触发 webhook,以便您同步订单状态。
#支付的其他操作
| 端点 | 作用 |
|---|---|
POST /v1/payments/{id}/cancel | 取消支付;以与 GET /v1/payments/{id} 相同的结构返回(不含 checkoutUrl)。 |
POST /v1/payments/{id}/resend-webhook | 请求 Liqfy 重新发送该支付的 webhook。 |
POST /v1/payments/{id}/reconcile | 向服务商重新核查支付状态;返回 { reconciled, status }。 |
GET /v1/payments/{id}/refunds | 该支付的退款历史。failureReason 始终为 null,且 reason 仅在您自己发起的退款中填写。 |
POST /v1/payments/{id}/confirm-sandbox | 仅限沙盒——确认模拟收费以触发完成 webhook。任何非沙盒收费都会被拒绝;绝不会入账到钱包。 |
POST /v1/payments/{id}/refund | API 密钥调用方不可用:返回 403 REFUND_ADMIN_ONLY(见常见问题)。 |
#测试卡
在沙盒中,重定向页面接受以下确定性卡号(任意未来有效期、任意 CVV):
| 卡号 | 结果 |
|---|---|
4111 1111 1111 1111 | 始终 APPROVED |
4000 0000 0000 0002 | 始终 REFUSED —— 通用拒绝 |
4000 0000 0000 0069 | 始终 REFUSED —— 卡已过期 |
4000 0000 0000 9995 | 始终 REFUSED —— 余额不足 |
4000 0000 0000 3220 | 触发 3DS 验证后 APPROVED |
沙盒收费在模拟器上运行:绝不会入账到您的钱包,也不计入交易量、收入和指标数据(但仍会出现在列表和收费详情中)。使用 POST /v1/payments/{id}/confirm-sandbox 可通过测试密钥端到端触发完成 webhook。
完整列表请参阅沙盒。
#常见问题
问:能让客户留在我的域名上吗? 答:第二阶段我们将推出可嵌入组件(iframe + 令牌化器),既保留您的品牌风格,又让持卡人数据不进入您的基础设施。目前:托管重定向。
问:支持保存卡吗? 答:支持,但需要您一方持有自己的卡数据安全合规证明。请发送邮件至 suporte@liqfy.com.br 以启用 Vault API。
问:使用哪个 3DS 版本? 答:3DS 2.x,在发卡行允许时采用无摩擦流程。EUR 必须进行强客户认证(SCA)——由服务器端强制执行。
问:退款?
答:目前退款需在管理后台发起,支持全额或部分退款——API 未提供商户可用的退款端点:使用 API 密钥调用 POST /v1/payments/{id}/refund 会返回 403 REFUND_ADMIN_ONLY。您仍可通过 GET /v1/payments/{id}/refunds 读取退款历史。
问:客户已被扣款,但我从未收到 webhook。
答:请检查 GET /v1/webhooks/deliveries——很可能我们已尝试发送,但您的端点返回了非 2xx 状态。我们最多重试 15 次。之后请使用 POST /v1/payments/{id}/resend-webhook 或联系支持团队重放。
#下一步
→ MB WAY · Multibanco · API 参考