yansongda/pay Airwallex 退款实战:从参数到源码的完整解析
金融科技后端【免费下载链接】pay可能是我用过的最优雅的 Alipay/WeChat/Douyin/Unipay/江苏银行 的支付 SDK 扩展包了项目地址https://gitcode.com/gh_mirrors/pa/pay点击查看免费下载Airwallex 是国际知名的跨境支付服务商其 Payment Intents 模式与 Stripe 类似退款需要基于原始payment_intent_id发起。本篇文章以 web/docs/v3/airwallex/refund.md 为核心指南结合 yansongda/pay 开源仓库的源码与测试用例系统讲解 Airwallex 退款接口的调用方法、全部参数语义、底层插件链路与常见异常处理。读完本文你将掌握用一行Pay::airwallex()-refund($order)完成完整退款流程并能从源码层面理解 SDK 的鉴权、请求组装与响应校验机制。方法签名与返回值原文档给出的调用契约非常简洁方法名参数返回值refundarray $orderCollection其中refund方法由 Airwallex Provider 提供参数为退款订单数组返回值是Yansongda\Supports\Collection类型的集合对象可直接链式调用get()、toArray()等方法取用退款结果。从源码看该方法定义于 src/Provider/Airwallex.php其实现逻辑为public function refund(array $order): Collection|Rocket { Event::dispatch(new MethodCalled(Pay::PROVIDER_AIRWALLEX, __METHOD__, $order, null)); return $this-__call(refund, [$order]); }即每次调用refund()都会先触发MethodCalled事件供 src/Event/MethodCalled.php 对应的监听器做埋点、日志或风控随后通过魔术方法__call动态装载RefundShortcut完成整个请求流程。快速上手最小退款示例沿用原文档的完整示例先初始化配置再发起退款use Yansongda\Pay\Pay; Pay::config($config); $order [ payment_intent_id int_xxx, amount 10, // reason requested_by_customer, // metadata [ // refund_no R20260414001, // ], ]; $result Pay::airwallex()-refund($order);其中$config为 Airwallex 渠道的完整配置详见下文「前置条件Airwallex 配置」。执行成功后$result中会包含 Airwallex 返回的refund_id、status、amount、currency等退款单信息业务侧应将其落库并与原始支付单关联供后续退款查询与对账使用。参数说明与源码级解析原文档明确了四个核心参数其中payment_intent_id为必填。结合 RefundPlugin 的实现参数语义可以进一步细化为下表参数必填类型说明payment_intent_id是string待退款的 Payment Intent ID即下单成功时返回的int_开头标识id二选一stringpayment_intent_id的别名传入后会被自动映射为payment_intent_idamount否number退款金额。不传时按 Airwallex 平台规则处理部分场景支持全额退款reason否string退款原因例如requested_by_customer客户申请metadata否array自定义扩展信息可用于关联业务订单号如[refund_no R20260414001]request_id否string请求幂等 ID不传时 SDK 自动生成 UUID v4必填参数校验RefundPlugin 在组装请求时会优先读取payment_intent_id若为空则回退读取id$paymentIntentId $payload-get(payment_intent_id, $payload-get(id)); if (empty($paymentIntentId)) { throw new InvalidParamsException( Exception::PARAMS_NECESSARY_PARAMS_MISSING, 参数异常: Airwallex 退款缺少必要参数 -- [payment_intent_id] or [id] ); }也就是说两种写法等价// 写法一 $result Pay::airwallex()-refund([payment_intent_id int_xxx, amount 10]); // 写法二使用 id 别名 $result Pay::airwallex()-refund([id int_xxx, amount 10]);这一行为在测试 tests/Plugin/Airwallex/V1/Pay/RefundPluginTest.php 中得到验证testUseIdAndOptionalFields传入id后断言最终请求负载中的payment_intent_id被正确映射。请求组装细节校验通过后插件会组装退款请求负载并过滤掉所有null值字段避免向 Airwallex 发送空参数$rocket-mergePayload(array_filter([ _method POST, _url /api/v1/pa/refunds/create, request_id $payload-get(request_id, self::getAirwallexRequestId()), payment_intent_id $paymentIntentId, amount $payload-get(amount), reason $payload-get(reason), metadata $payload-get(metadata), ], static fn ($value) !is_null($value)));要点如下接口路径POST /api/v1/pa/refunds/create对应 Airwallex 官方 Refunds API幂等设计request_id默认由Str::uuidV4()生成见 src/Traits/AirwallexTrait.php保证同一退款请求不会因网络重试被重复受理业务侧如需自定义幂等键可显式传入request_id金额单位amount遵循 Airwallex 平台默认的最小货币单位约定建议与下单时的币种、精度保持一致。前置条件Airwallex 配置退款属于需要身份认证的商户 API必须先配置好 Airwallex 渠道参数详见 web/docs/v3/quick-start/airwallex.mduse Yansongda\Pay\Pay; $config [ airwallex [ default [ // 「必填」Airwallex Client ID client_id , // 「必填」Airwallex API Key api_key , // 「必填」Webhook Secret用于回调验签 webhook_secret , // 「选填」支付完成后的返回地址 return_url https://example.com/airwallex/return, // 「选填」Airwallex API 版本 api_version 2024-06-14, // 「选填」平台模式代商户调用时使用 // on_behalf_of open_id_xxx, // 「选填」默认为正式模式。可选值 // MODE_NORMAL: 正式环境 // MODE_SANDBOX: 沙箱环境 mode Pay::MODE_NORMAL, ], ], ]; Pay::config($config);配置校验逻辑位于 src/Config/AirwallexConfig.phpclient_id与api_key为必填项缺失时抛出InvalidConfigException。mode决定请求的 Base URL见 src/Provider/Airwallex.phpMODE_NORMAL/MODE_SERVICEhttps://api.airwallex.comMODE_SANDBOXhttps://api-demo.airwallex.com退款开发调试阶段务必使用沙箱环境避免误退真实资金。底层调用链RefundShortcut 插件管道Pay::airwallex()-refund($order)并非直接发 HTTP 请求而是通过 Artful 管道Pipeline串联一组插件。插件链定义于 src/Shortcut/Airwallex/RefundShortcut.phpreturn [ StartPlugin::class, // 初始化 Rocket ObtainAccessTokenPlugin::class, // 获取并注入 Access Token RefundPlugin::class, // 组装退款请求参数 AddPayloadBodyPlugin::class, // 将负载序列化为请求体 AddRadarPlugin::class, // 构建 PSR-7 RequestURL 鉴权头 ResponsePlugin::class, // 校验 HTTP 响应状态码 ParserPlugin::class, // 解析响应为 Collection ];1. 获取 Access TokenObtainAccessTokenPlugin 调用getAirwallexAccessToken()src/Traits/AirwallexTrait.php若配置中已有未过期的accessToken则直接复用否则通过/api/v1/authentication/login用client_idapi_key换取新令牌并将过期时间提前 60 秒作为安全余量缓存回配置实现同一进程内多请求复用。2. 组装请求与鉴权头AddRadarPlugin 根据负载构建最终 HTTP 请求其中鉴权方式二选一客户端模式_auth_type client使用x-client-idx-api-key请求头常规模式使用Authorization: Bearer token。同时会按配置附带x-api-version如2024-06-14与平台代调用的x-on-behalf-of头。3. 响应校验与解析ResponsePlugin 会检查 HTTP 状态码非 2xx 响应直接抛出InvalidResponseException对应Exception::RESPONSE_CODE_WRONG。随后ParserPlugin将 JSON 响应解析为Collection返回给业务层。整套链路在测试 tests/Shortcut/Airwallex/RefundShortcutTest.php 中有完整断言。退款结果处理与后续操作退款结果字段退款成功后可从Collection中读取关键字段$refundId $result-get(refund_id); // Airwallex 退款单 IDref_ 开头 $status $result-get(status); // 退款状态 $amount $result-get(amount); // 退款金额 $currency $result-get(currency); // 退款币种Airwallex 的退款单状态通常包含pending受理中、succeeded成功、failed失败等建议结合异步 Webhook 回调确认最终结果而不是仅依赖同步响应。查询退款单如需主动查询退款进度可复用query方法并传入_action refund与退款单 ID参见 web/docs/v3/quick-start/airwallex.md 的「查询」章节$result Pay::airwallex()-query([ _action refund, refund_id ref_xxx, ]);退款回调验签Airwallex 会通过 Webhook 推送退款结果。SDK 提供verifyAirwallexWebhookSign()src/Traits/AirwallexTrait.php做 HMAC-SHA256 验签校验x-timestamp与x-signature请求头并检查时间戳是否在 300 秒5 分钟窗口内防重放攻击。需要先配置webhook_secret否则会抛出InvalidConfigException。收到回调后可调用$result Pay::airwallex()-callback(); return Pay::airwallex()-success();常见异常与排查异常触发场景解决建议InvalidParamsExceptionPARAMS_NECESSARY_PARAMS_MISSING未传payment_intent_id/id补全必填参数后再调用InvalidConfigExceptionCONFIG_AIRWALLEX_INVALID缺少client_id或api_key检查 src/Config/AirwallexConfig.php 对应配置InvalidResponseExceptionRESPONSE_CODE_WRONGAirwallex 返回非 2xx核对金额、币种、Payment Intent 状态与 API 权限退款金额超限退款金额大于可退余额先通过query查询原始 Payment Intent 的已支付金额与已退金额小结Airwallex 退款在 yansongda/pay 中是一个高度封装的调用业务侧只需传入payment_intent_id或id与可选的amount、reason、metadataSDK 内部通过「取 Token → 组装请求 → 鉴权 → 校验响应 → 解析」的插件管道完成全部脏活。理解 RefundPlugin 的参数映射与 RefundShortcut 的插件顺序有助于在排查退款异常、自定义幂等键或对接平台模式on_behalf_of时快速定位问题。生产环境建议开启沙箱模式联调并配合 Webhook 回调做退款状态的最终确认。赞分享金融科技后端【免费下载链接】pay可能是我用过的最优雅的 Alipay/WeChat/Douyin/Unipay/江苏银行 的支付 SDK 扩展包了项目地址https://gitcode.com/gh_mirrors/pa/pay点击查看免费下载相关推荐yansongda/pay退款功能实现详解从申请到查询全流程在现代化的电商系统中支付退款功能是保障用户体验和资金安全的重要环节。yansongda/pay 作为一款优雅的支付SDK扩展包为开发者提供了简洁高效的退款解金融科技后端QQ空间说说怎么导出到本地GetQzonehistory 新手向完整教程QQ空间说说怎么导出到本地GetQzonehistory 新手向完整教程 想找 2015 年的一条说说翻遍 QQ 空间也没有导出入口。GetQzonehis金融科技后端yansongda/pay银联支付实战从扫码到刷卡全流程yansongda/pay银联支付实战从扫码到刷卡全流程 想要快速集成银联支付功能yansongda/pay扩展包为你提供了 最优雅的解决方案 作为一款专金融科技后端上一篇React 应用启动初始化只执行一次模块级守卫 vs useEffect([]) 挂载副作用Mediago 实战下一篇不用C不用CythonCodon编译纯Python为高性能Python扩展模块完整教程创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

相关新闻

使用 AWS SDK for SAP ABAP 操作 AWS HealthLake:FHIR 数据存储与导入导出任务实战

使用 AWS SDK for SAP ABAP 操作 AWS HealthLake:FHIR 数据存储与导入导出任务实战

示例工程教程后端 【免费下载链接】aws-doc-sdk-examples Welcome to the AWS Code Examples Repository. This repo contains code examples used in the AWS documentation, AWS SDK Developer Guides, and more. For more information, see the Readme.md file below. 项目地…

2026/10/5 10:09:45 阅读更多 →
Wand-Enhancer 完整免费解锁 WeMod 专业版:5 分钟实操指南

Wand-Enhancer 完整免费解锁 WeMod 专业版:5 分钟实操指南

Wand-Enhancer 完整免费解锁 WeMod 专业版:5 分钟实操指南 【免费下载链接】Wand-Enhancer Advanced UX and interoperability extension for Wand (WeMod) app 项目地址: https://gitcode.com/GitHub_Trending/we/Wand-Enhancer WeMod 专业版可以免费解锁。…

2026/10/5 10:08:45 阅读更多 →
Warp 共享会话 Viewer 进入 Agent 视图的同步机制:REMOTE-1674 技术解析

Warp 共享会话 Viewer 进入 Agent 视图的同步机制:REMOTE-1674 技术解析

桌面应用开发者工具人工智能AI 应用AI Agent代码智能体 【免费下载链接】warp Warp is an agentic development environment, born out of the terminal. 项目地址: https://gitcode.com/GitHub_Trending/wa/warp 点击查看 免费下载 导读 本篇文章基于 Warp&#…

2026/10/5 10:08:45 阅读更多 →

最新新闻

Awesome Claude Skills实用指南:科研AI工作流4个场景,从文献调研到论文成稿

Awesome Claude Skills实用指南:科研AI工作流4个场景,从文献调研到论文成稿

Awesome Claude Skills实用指南:科研AI工作流4个场景,从文献调研到论文成稿 【免费下载链接】awesome-claude-skills A curated list of awesome Claude Skills, resources, and tools for customizing Claude AI workflows 项目地址: https://gitcode…

2026/10/5 13:04:59 阅读更多 →
Python40-42:核心语法-数据容器-列表list-案例(解包、推导式)

Python40-42:核心语法-数据容器-列表list-案例(解包、推导式)

列表案例一# 案例1. 将用户输入的10个数字,存储到一个列表中,并将列表中的数字进行排序,输出其中的最小值、最大值和平均值。# 1. 定义列表 num_list [] # 定义空列表# 2. 将用户输入的10个数字存入列表 for i in range(10): # 循环的次数…

2026/10/5 13:04:59 阅读更多 →
CubeFS 命令行工具 cfs-cli 使用指南:编译、配置与集群管理命令全解析

CubeFS 命令行工具 cfs-cli 使用指南:编译、配置与集群管理命令全解析

存储分布式文件系统对象存储云原生 【免费下载链接】cubefs cloud-native distributed storage 项目地址: https://gitcode.com/gh_mirrors/cu/cubefs 点击查看 免费下载 导读 cfs-cli 是 CubeFS 提供的命令行管理工具,用于对集群进行日常运维与管理&a…

2026/10/5 13:04:59 阅读更多 →
Mooncake Store 的 OSS 对象存储卸载(Offload)部署指南:架构、配置与故障排查

Mooncake Store 的 OSS 对象存储卸载(Offload)部署指南:架构、配置与故障排查

人工智能大模型模型推理服务后端 【免费下载链接】Mooncake Mooncake is the serving platform for Kimi, a leading LLM service provided by Moonshot AI. 项目地址: https://gitcode.com/gh_mirrors/mo/Mooncake 点击查看 免费下载 导读 本文介绍 Mooncake 项目…

2026/10/5 13:04:59 阅读更多 →
LiveKit 拆解 Safari 下 AV1 黑屏的兜底链路

LiveKit 拆解 Safari 下 AV1 黑屏的兜底链路

LiveKit 拆解 Safari 下 AV1 黑屏的兜底链路 【免费下载链接】livekit End-to-end realtime stack for connecting humans and AI 项目地址: https://gitcode.com/GitHub_Trending/li/livekit 用 Safari 进会,远端画面是一块黑屏,或者自己的摄像头…

2026/10/5 13:04:59 阅读更多 →
游戏存档保护的终极解决方案:3步搞定跨平台进度备份 [特殊字符]

游戏存档保护的终极解决方案:3步搞定跨平台进度备份 [特殊字符]

游戏存档保护的终极解决方案:3步搞定跨平台进度备份 😎 【免费下载链接】ludusavi Backup tool for PC game saves 项目地址: https://gitcode.com/GitHub_Trending/lu/ludusavi 还在为游戏进度丢失而烦恼吗?Ludusavi 是一款专业的游戏…

2026/10/5 13:03:59 阅读更多 →

日新闻

马斯克杀回智能体战场,Grok 4.5万亿参数撑腰,Cursor接手数字白领项目:用TaoToken统一Key跑通多模型Agent工作流

马斯克杀回智能体战场,Grok 4.5万亿参数撑腰,Cursor接手数字白领项目:用TaoToken统一Key跑通多模型Agent工作流

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/5 0:00:22 阅读更多 →
AI编程工具插件机制详解:plugin.json配置与加载失败排查指南

AI编程工具插件机制详解:plugin.json配置与加载失败排查指南

1. 从“plugins”这个词说起:它到底在解决什么问题如果你最近在折腾 AI 编程工具,尤其是 Cursor、Codex CLI、Claude Code 这类带 CLI 的编辑器或命令行助手,那你大概率绕不开一个词——plugins。这个词本身不新鲜,从浏览器到 IDE…

2026/10/5 0:00:23 阅读更多 →
第26课:OpenClaw|日志审计与问题诊断:把日志链路改到 TaoToken 的排查清单

第26课:OpenClaw|日志审计与问题诊断:把日志链路改到 TaoToken 的排查清单

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/5 0:00:23 阅读更多 →

周新闻

KT148A语音芯片外挂8002D功放的工程实践指南

KT148A语音芯片外挂8002D功放的工程实践指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/5 5:06:42 阅读更多 →
LLC谐振变换器增益公式推导:从FHA等效到完整归一化表达式

LLC谐振变换器增益公式推导:从FHA等效到完整归一化表达式

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/5 1:10:22 阅读更多 →
ARM架构深度解析:从RISC设计理念到交叉编译实战

ARM架构深度解析:从RISC设计理念到交叉编译实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/5 3:06:17 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/4 11:40:45 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/4 9:43:54 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/4 20:14:29 阅读更多 →