SDK 集成(V2)
Quick Reference
A55Pay JavaScript SDK V2 在买家浏览器中运行:采集卡数据、执行设备数据采集(Device Data Collection,DDC)、处理 3DS 认证、完成支付并触发回调。原始卡数据不会经过您的源站服务器。
为何使用 SDK
| 优势 | 说明 |
|---|---|
| 默认安全 | 卡数据留在浏览器——A55 全面处理卡数据安全 |
| 最快集成 | 一个 script 标签 + 一次函数调用 |
| 内置 DDC 与 3DS | SDK 自动运行设备指纹与认证 |
| 事件回调 | onSuccess、onError、onReady / onClose 供您完全掌控 |
工作原理
分步集成
加载 SDK
在结账页加入 script 标签:
<script src="https://cdn.jsdelivr.net/npm/a55pay-sdk"></script>
生产环境请固定次版本(例如 a55pay-sdk@1.2.x),以便各次部署行为可复现。
在后端创建收费
后端创建不含卡数据的收费——SDK 将在浏览器中采集并提交卡数据。
- cURL
- Python
- Node.js
- Go
- Java
- PHP
curl -sS -X POST "https://sandbox.api.a55.tech/api/v1/bank/wallet/charge/" \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"wallet_uuid": "00000000-0000-4000-8000-000000000001",
"merchant_id": "merchant_123",
"payer_name": "张伟",
"payer_email": "zhangwei@example.com",
"payer_tax_id": "12345678901",
"currency": "BRL",
"installment_value": 10000,
"installment_count": 1,
"type_charge": "credit_card",
"description": "SDK 测试收费",
"reference_external_id": "sdk_001",
"webhook_url": "https://merchant.example/webhooks/a55",
"redirect_url": "https://merchant.example/return"
}'
import os, requests
r = requests.post(
"https://sandbox.api.a55.tech/api/v1/bank/wallet/charge/",
headers={"Authorization": f"Bearer {os.environ['ACCESS_TOKEN']}",
"Content-Type": "application/json"},
json={
"wallet_uuid": "00000000-0000-4000-8000-000000000001",
"merchant_id": "merchant_123",
"payer_name": "张伟", "payer_email": "zhangwei@example.com",
"payer_tax_id": "12345678901",
"currency": "BRL", "installment_value": 10000, "installment_count": 1,
"type_charge": "credit_card",
"reference_external_id": "sdk_001",
"webhook_url": "https://merchant.example/webhooks/a55",
},
)
charge_uuid = r.json()["uuid"]
const res = await fetch(
"https://sandbox.api.a55.tech/api/v1/bank/wallet/charge/",
{
method: "POST",
headers: {
Authorization: `Bearer ${process.env.ACCESS_TOKEN}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
wallet_uuid: "00000000-0000-4000-8000-000000000001",
merchant_id: "merchant_123",
payer_name: "张伟", payer_email: "zhangwei@example.com",
payer_tax_id: "12345678901",
currency: "BRL", installment_value: 10000, installment_count: 1,
type_charge: "credit_card",
reference_external_id: "sdk_001",
webhook_url: "https://merchant.example/webhooks/a55",
}),
}
);
const { uuid: chargeUuid } = await res.json();
payload := map[string]interface{}{
"wallet_uuid": "00000000-0000-4000-8000-000000000001",
"type_charge": "credit_card", "currency": "BRL",
"installment_value": 10000, "installment_count": 1,
"reference_external_id": "sdk_001",
"webhook_url": "https://merchant.example/webhooks/a55",
}
body, _ := json.Marshal(payload)
req, _ := http.NewRequest("POST",
"https://sandbox.api.a55.tech/api/v1/bank/wallet/charge/", bytes.NewReader(body))
req.Header.Set("Authorization", "Bearer "+os.Getenv("ACCESS_TOKEN"))
req.Header.Set("Content-Type", "application/json")
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
var result struct{ UUID string `json:"uuid"` }
json.NewDecoder(resp.Body).Decode(&result)
String json = """
{"wallet_uuid":"00000000-0000-4000-8000-000000000001",
"type_charge":"credit_card","currency":"BRL",
"installment_value":10000,"installment_count":1,
"reference_external_id":"sdk_001",
"webhook_url":"https://merchant.example/webhooks/a55"}
""";
HttpRequest req = HttpRequest.newBuilder()
.uri(URI.create("https://sandbox.api.a55.tech/api/v1/bank/wallet/charge/"))
.header("Authorization", "Bearer " + System.getenv("ACCESS_TOKEN"))
.header("Content-Type", "application/json")
.POST(HttpRequest.BodyPublishers.ofString(json)).build();
HttpResponse<String> resp = HttpClient.newHttpClient()
.send(req, HttpResponse.BodyHandlers.ofString());
String chargeUuid = new JSONObject(resp.body()).getString("uuid");
$payload = [
"wallet_uuid" => "00000000-0000-4000-8000-000000000001",
"type_charge" => "credit_card", "currency" => "BRL",
"installment_value" => 10000, "installment_count" => 1,
"reference_external_id" => "sdk_001",
"webhook_url" => "https://merchant.example/webhooks/a55",
];
$ch = curl_init("https://sandbox.api.a55.tech/api/v1/bank/wallet/charge/");
curl_setopt_array($ch, [
CURLOPT_POST => true, CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
"Authorization: Bearer " . getenv("ACCESS_TOKEN"),
"Content-Type: application/json"],
CURLOPT_POSTFIELDS => json_encode($payload),
]);
$chargeUuid = json_decode(curl_exec($ch))->uuid;
在浏览器中调用 A55Pay.payV2()
传入后端返回的 chargeUuid 以及在浏览器中采集的卡数据:
A55Pay.payV2({
charge_uuid: chargeUuid,
userData: {
name: '张伟',
email: 'zhangwei@example.com',
document: '12345678901',
card_number: '4111111111111111',
card_expiry_month: '12',
card_expiry_year: '2030',
card_cvv: '123',
address: {
street: 'Av. Paulista 1000',
city: 'São Paulo',
state: 'SP',
zip_code: '01310100',
country: 'BR',
},
},
onSuccess: (payload) => {
// 支付已确认——向买家展示成功
console.log('收费已确认:', payload);
},
onError: (err) => {
// 拒绝或错误——展示适当的错误信息
console.error('收费失败:', err);
},
onReady: () => {
// SDK 已初始化——可以显示支付表单
},
});
SDK 将自动:运行 DDC → 提交支付 → 处理 3DS 挑战(如需要)→ 调用 onSuccess 或 onError。
处理回调
| 回调 | 触发时机 | 建议操作 |
|---|---|---|
onSuccess(payload) | 支付完成(confirmed 或 paid) | 展示成功,跳转订单页 |
onError(err) | 拒绝、错误或认证失败 | 展示用户可理解的错误信息 |
onReady() | SDK 已初始化并就绪 | 可选:显示卡表单 |
onSuccess 预期载荷:
{
"chargeUuid": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"status": "confirmed",
"reference_external_id": "sdk_001"
}
onError 预期载荷:
{
"chargeUuid": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"status": "error",
"message": "Card declined by issuer"
}
通过 Webhook 确认
请始终将 Webhook(网络钩子)作为最终事实来源(source of truth)。买家可能在 onSuccess 触发前关闭浏览器。
{
"charge_uuid": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"status": "paid",
"transaction_reference": "txn_ref_001"
}
A55Pay.open(config)——iframe 结账
若要在 iframe 或弹层中获得完全托管的结账体验:
const { close } = A55Pay.open({
checkoutUuid: chargeUuid,
display: 'modal', // 'modal' 或 'inline'
containerId: 'checkout', // 'inline' 模式下必填
onSuccess: (payload) => {
console.log('支付已确认:', payload);
},
onError: (err) => {
console.error('支付错误:', err);
},
onClose: () => {
console.log('用户关闭了结账');
},
onEvent: (event) => {
console.log('结账事件:', event);
},
});
| 回调 | payV2 | open |
|---|---|---|
onSuccess | 是 | 是 |
onError | 是 | 是 |
onReady | 是 | 否 |
onClose | 否 | 是 |
onEvent | 否 | 是 |
A55Pay.startApplePay(config)——Apple Pay 按钮
使用 A55Pay.startApplePay() 在 Safari 中原生处理 Apple Pay 支付,无需在后端处理 Apple Pay 令牌。
Apple Pay 需要提前在 A55 的 Apple Pay 账户中注册您的商户,并托管域名验证文件。集成前请联系 tech.services@a55.tech。
第 1 步——创建收款单(无卡数据)
在后端使用 type_charge: "applepay" 创建收款单,但不填写卡字段。收款单返回 status: "issued" 和 charge_uuid。
curl -X POST https://sandbox.api.a55.tech/api/v1/bank/wallet/charge/ \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"merchant_id": "您的_MERCHANT_UUID",
"wallet_uuid": "您的_WALLET_UUID",
"payer_name": "John Does",
"description": "订单 #123",
"due_date": "2025-10-31",
"installment_count": 1,
"installment_value": 100.00,
"currency": "BRL",
"webhook_url": "https://yoursite.com/webhook",
"type_charge": "applepay"
}'
{
"charge_uuid": "58e6dabd-71fe-49ed-8f55-ec055648dae7",
"status": "issued",
"type": "applepay",
"charge_payment_url": "https://pay.a55.tech/charge/v2/58e6dabd-71fe-49ed-8f55-ec055648dae7"
}
第 2 步——渲染 Apple Pay 按钮
在 /.well-known/apple-developer-merchantid-domain-association 路径托管域名验证文件,然后将 charge_uuid 传入 A55Pay.startApplePay():
<apple-pay-button
id="apple-pay-btn"
buttonstyle="black"
type="pay"
locale="zh-CN"
style="display:none; --apple-pay-button-width:240px; --apple-pay-button-height:44px; --apple-pay-button-border-radius:8px;"
></apple-pay-button>
<script src="https://cdn.jsdelivr.net/npm/a55pay-sdk/dist/a55pay-sdk.min.js"></script>
<script>
var btn = document.getElementById('apple-pay-btn');
if (A55Pay.isApplePayAvailable()) {
btn.style.display = 'inline-block';
}
btn.addEventListener('click', function () {
A55Pay.startApplePay({
chargeUuid: '第1步获取的_CHARGE_UUID',
countryCode: 'CN',
amount: 100.00,
currencyCode: 'BRL', // 默认: 'BRL'
merchantDomain: 'pay.a55.tech', // 默认: 'pay.a55.tech'
displayName: '您的公司', // 默认: 'A55Pay'
supportedNetworks: ['visa', 'masterCard', 'elo', 'amex'],
onSuccess: function (result) { console.log('已批准:', result); },
onError: function (error) { console.error('错误:', error.message); },
onClose: function () { console.log('用户取消'); },
});
});
</script>
| 回调 | 触发时机 | 处理方式 |
|---|---|---|
onSuccess(result) | 支付已批准 | 显示成功信息,跳转订单页面 |
onError(error) | 被拒绝或出错 | 向用户显示友好错误信息 |
onClose() | 用户关闭 Apple Pay 面板 | 恢复 UI 至初始状态 |
| 方法 | payV2 | open | startApplePay |
|---|---|---|---|
| 支付方式 | 信用/借记卡 | 信用/借记卡 | Apple Pay |
| 卡数据采集方 | 您的表单 | A55(托管) | Apple Pay(设备) |
| 需要 Apple 注册 | 否 | 否 | 是 |
| 仅限 Safari | 否 | 否 | 是 |
使用沙箱测试卡
| Card Number | Brand | Scenario | Expected Status |
|---|---|---|---|
4111 1111 1111 1111 | Visa | 支付成功 | confirmed |
5500 0000 0000 0004 | Mastercard | 支付成功 | confirmed |
4000 0000 0000 0002 | Visa | 卡被拒绝 | declined |
4000 0000 0000 0101 | Visa | 需要 3DS 挑战 | confirmed |
4000 0000 0000 0069 | Visa | 处理错误 | error |
切勿记录回调载荷中的 PAN、CVV 或密码文(cryptogram)。SDK 在浏览器上下文中处理卡数据——请保持在该环境中。
希望提高通过率?
Visa Data Only 通过 3DS 通道与发卡行共享丰富数据——无需任何挑战。Square 的试点显示最高可达 +646 个基点 的提升。
若使用 payV2,SDK 已通过 DDC 采集设备数据。您可在后端收费请求上同时设置 data_only: true,在几乎不增加摩擦的情况下尽量提高通过率。