PAYATHON 2026

如何在 iPhone app 中实现 P2P payment?

支付老李

结论

Apple 没有提供通用的 iOS P2P payment framework,无法直接完成“从付款人的信用卡扣款,再向收款人的银行账户打款”的整套流程。

这类 App 通常要接入支持 marketplace、platform payments 或 connected accounts 的第三方支付服务商。收款、身份验证、资金拆分、余额管理和银行出款由服务商处理,iOS App 负责展示支付界面并调用自己的后端,不能直接保存银行卡资料或自行执行银行转账。

常见选择有 Stripe Connect、Adyen for Platforms 和 PayPal 等。具体能否使用、覆盖哪些国家以及需要哪些资质,要根据业务注册地和用户所在地分别确认。

先确定交易类型

选择支付方式前,先要明确 App 销售的商品或服务类型。

实体商品或线下服务

打车、配送、家政和二手实物交易等业务,通常可以通过信用卡、Apple Pay 或第三方支付服务商收款。

Apple Pay 只是一种付款方式,不负责以下事项:

  • 给卖家开设收款账户
  • 对卖家进行 KYC 身份验证
  • 保存平台余额
  • 拆分平台佣金
  • 将款项汇入卖家的银行账户
  • 处理跨境结算和税务申报

这些功能需要由支付服务商和你的后端完成。

App 内消费的数字内容或数字服务

如果用户购买会员、虚拟商品、游戏道具或在 App 内使用的数字功能,通常需要遵守 StoreKit 和 App Store Review Guidelines 中的应用内购买规则。

StoreKit 不是 P2P 转账工具,也不能把一笔应用内购买直接结算给另一个普通用户。平台型业务是否适用例外,要结合商品性质、服务发生地点、销售地区和当时有效的审核规则判断。上线前应核对最新版 App Store Review Guidelines,尤其是支付相关章节。

推荐的实现架构

典型流程如下:

  1. 卖家在 App 中注册。
  2. 后端通过支付服务商为卖家创建 connected account 或 merchant account。
  3. 卖家在支付服务商托管的页面中提交姓名、地址、身份证明和银行账户等资料。
  4. 买家下单后,App 请求你的后端创建支付。
  5. App 使用支付服务商的 iOS SDK 或 Apple Pay 确认付款。
  6. 后端通过 webhook 接收支付成功、退款和争议等事件。
  7. 后端确认商品或服务已经履约。
  8. 支付服务商扣除退款准备金、服务费或平台佣金后,将可结算资金转入卖家的银行账户。

敏感信息最好直接提交给支付服务商,不要经过自己的服务器。尤其不能自行收集或保存完整卡号、CVV、网上银行密码等数据。

iOS 端示例

下面的代码只演示客户端如何请求自己的后端创建支付订单。金额计算、收款人确定和支付服务商 API 调用都必须由服务器完成。

import Foundation

struct CreatePaymentRequest: Encodable {
    let orderID: String
}

struct CreatePaymentResponse: Decodable {
    let clientSecret: String
}

func createPayment(orderID: String) async throws -> CreatePaymentResponse {
    let url = URL(string: "https://api.example.com/payments")!

    var request = URLRequest(url: url)
    request.httpMethod = "POST"
    request.setValue("application/json", forHTTPHeaderField: "Content-Type")
    request.setValue(
        "Bearer \(try await currentAccessToken())",
        forHTTPHeaderField: "Authorization"
    )
    request.httpBody = try JSONEncoder().encode(
        CreatePaymentRequest(orderID: orderID)
    )

    let (data, response) = try await URLSession.shared.data(for: request)

    guard let httpResponse = response as? HTTPURLResponse,
          (200..<300).contains(httpResponse.statusCode) else {
        throw PaymentError.requestFailed
    }

    return try JSONDecoder().decode(
        CreatePaymentResponse.self,
        from: data
    )
}

enum PaymentError: Error {
    case requestFailed
}

func currentAccessToken() async throws -> String {
    // 从应用的安全认证流程中获取短期访问令牌。
    fatalError("Implement authentication")
}

取得 clientSecret 等客户端参数后,再将其交给所选支付服务商的官方 iOS SDK。各服务商使用的 SDK 类型和初始化参数不同,应以其当前文档为准。

支付服务商的 secret key 不能放在 App 中。客户端只能使用明确允许公开的 publishable key 或短期客户端令牌。

后端需要承担的职责

后端不能只把银行卡信息从一方转发给另一方。它至少要负责:

  • 根据服务端订单记录确定金额、币种和收款人
  • 创建支付及幂等键,防止重复扣款
  • 验证卖家账户是否完成 KYC
  • 记录平台佣金和卖家应得金额
  • 验证 webhook 签名
  • 处理退款、拒付和支付争议
  • 控制向卖家结算的时间
  • 建立订单、支付、退款和出款之间的审计记录

金额不能由客户端直接决定。客户端可以发送 orderID,但后端必须从数据库重新读取订单价格。

简化后的服务端逻辑可以写成:

POST /payments
    authenticate buyer
    load order from database
    verify order is payable
    verify seller account is eligible
    calculate amount and platform fee
    create payment with payment provider
    save provider payment ID
    return client confirmation parameters

也不能只根据 App 返回的“成功”判断支付结果。最终状态应以支付服务商签名 webhook 中的数据为准。

是否需要按国家或地区分别实现

通常需要按国家或地区分别评估,但未必需要为每个国家编写一套完全不同的客户端代码。大部分差异可以由支付服务商和后端配置处理。

需要确认的事项包括:

  • 服务商是否支持平台、买家和卖家所在国家
  • 支持哪些银行卡、银行账户和本地支付方式
  • 是否允许跨境收款及跨境出款
  • KYC、AML 和制裁名单筛查要求
  • 是否需要支付机构、汇款或货币传输相关许可
  • 强客户认证要求,例如欧洲经济区的 SCA
  • 结算币种、汇率和到账周期
  • 退款、拒付以及负余额由谁承担
  • 平台是否需要代扣、申报或提供税务资料
  • 用户资金能否暂存,以及允许暂存多长时间

如果你的公司先收下付款,再自行通过 bank transfer 转给卖家,公司可能会被认定为实际控制或传输客户资金。这会大幅增加许可、合规、对账和风险管理责任。除非已经取得专业法律意见和相应资质,否则通常更适合使用支付服务商提供的 marketplace 模式。

Apple Pay 能做什么

Apple Pay 可以作为买家的支付入口。技术上通常使用 PassKit 创建支付请求:

import PassKit

func makeApplePayRequest() -> PKPaymentRequest {
    let request = PKPaymentRequest()

    request.merchantIdentifier = "merchant.com.example.app"
    request.countryCode = "US"
    request.currencyCode = "USD"
    request.merchantCapabilities = [.capability3DS]
    request.supportedNetworks = [.visa, .masterCard, .amex]

    request.paymentSummaryItems = [
        PKPaymentSummaryItem(
            label: "Order",
            amount: NSDecimalNumber(string: "50.00")
        ),
        PKPaymentSummaryItem(
            label: "Example Marketplace",
            amount: NSDecimalNumber(string: "50.00")
        )
    ]

    return request
}

这里的金额仅用于演示。生产环境必须使用后端确认的订单金额,并按照 Apple Pay 和支付服务商的要求处理 PKPaymentToken。Apple Pay 完成的是买家付款授权,并不代表款项已经转入卖家的银行账户。

容易忽略的问题

“转账成功”和“交易完成”不是一回事。信用卡付款之后仍可能发生退款或拒付,此时卖家款项可能已经转出。因此,平台通常需要设置延迟结算、风险审核或保证金机制。

还需要考虑以下情况:

  • 卖家账户审核失败后的订单处理
  • 收款银行卡失效导致的出款失败
  • 部分退款与平台佣金退还规则
  • 买卖双方串通套现
  • 被盗信用卡和账户接管
  • 未成年人交易
  • 高风险商品及受限制行业
  • 货币金额的精度和舍入规则
  • 重复 webhook 和乱序事件
  • 用户注销后的法定记录保留

应查阅的资料

实施前应查看以下官方资料:

  • Apple Developer 的 Apple Pay 和 PassKit 文档
  • 最新版 App Store Review Guidelines
  • 支付服务商的 marketplace 或 platform payments 文档
  • 支付服务商的 connected accounts、payouts、webhooks 和 disputes 文档
  • PCI DSS 适用范围说明
  • 目标国家或地区关于 KYC、AML、支付服务、消费者保护和税务的规定

比较稳妥的方案是选择覆盖目标市场的平台型支付服务商,由服务商负责卖家验证和银行出款。你的后端管理订单、佣金、支付状态和履约流程,iOS 端只负责安全地发起并确认付款。

备注:内容仅供参考。