支付设置——以及那个会悄无声息地亏钱的步骤
支付凭据是 仅服务器端 的:它们存放在你机器上的 .env 里,绝不进入数据库、绝不进入表单、绝不进入这个管理端。这是刻意的。下面讲的是每一个值该放在哪里——以及那个容易被漏掉、漏掉代价高昂的步骤。
跳过就会亏钱的那一步
大多数印尼支付方式是 异步 的。买家挑一个虚拟账户、一个电子钱包,或者在零售网点付款,然后 关掉标签页。他们可能一个小时后才付完,从他们的银行 App,在另一台设备上。这个过程中没有任何东西会返回到你的网站。
因此,购买是由支付商调用 你的 服务器来完成的——一个 webhook——除此之外别无他物。
如果那个调用永不到达:
- 买家的钱到了你手里,
- 他们的许可证从未签发,
- 订单停在 “pending”,
- 而任何地方都没有说明为什么。
这不是一个罕见的边缘情况。在印尼的支付方式上,它是 正常 路径。
每个支付商从哪里获得它的 URL
| 支付商 | Webhook URL | 由谁设置 |
|---|---|---|
| Xendit | https://yourdomain/webhooks/xendit |
由你手动设置,一次 |
| PayPal | (无) | 不需要——它在返回时完成 |
PayPal 在买家返回时完成,因此它根本不需要 webhook。Xendit 是那个需要你的——见下文。
Xendit 是那个需要你的。 它的 “invoice paid” 回调是账户级的,不是每张发票级的,因此它在 Xendit 自己的仪表盘里设置一次。
Xendit,一步一点
- 在 dashboard.xendit.co 登录。
- Settings → Developers → Webhooks。
- 在 Invoices paid 下,粘贴你的管理页面为 Xendit 显示的那个 URL
(
https://yourdomain/webhooks/xendit)。 - 保存,并复制同一页面上显示的 webhook verification token。
- 把那个令牌放进你服务器的
.env,作为XENDIT_CALLBACK_TOKEN,与XENDIT_SECRET_KEY并列。 - 重启站点,好让新的值被读取。
两半都是必需的。有 URL 而没有令牌,意味着投递到达却被拒绝;有令牌而没有 URL,意味着什么都不会到达。
证明它确实有效
不要相信 “我粘贴过了”。打开 Admin → Settings → Payment webhooks。它会报告真正到达你服务器的东西:
| 它显示什么 | 它意味着什么 | 该怎么办 |
|---|---|---|
| Never received | 从这个支付商那里从未有任何东西到达 | 支付商仪表盘里的 URL 缺失或错误 |
| Not matching | 投递到达了,但没有指名你的任何订单 | 那个 URL 是从一个与商店所用不同的支付商 账户 指向你的 |
| Working | 至少有一次投递匹配上了一个真实订单 | 什么都不用——它接好了 |
计数器只为携带支付商自己凭据的调用而移动,因此一个来自互联网的随机探测永远无法让一个未配置的网关看起来健康。
在你收真实的钱之前,端到端地测试它。 Xendit 的仪表盘在同一页面上有一个 “test webhook” 按钮;用它,然后重新加载管理卡片。如果它仍然显示 Never received,那 URL 就是错的——检查有没有笔误、缺失的 https://,或一个末尾的斜杠。
凭据本身
有两种方式来设置它们。两种都把密钥藏在视线之外——两种都绝不显示任何一个已保存的值。
从管理页面(推荐)
Admin → Settings → Payment gateway credentials。 输入 PayPal Client ID + Secret(以及 sandbox/live 开关)以及 Xendit Secret Key + Callback token。它们在服务器上以 加密 方式存储;这些字段是只写的,因此一旦保存就再也不会被显示——页面只显示 Configured / Not set。把某个字段留空即可保持它不变;用 Remove stored credentials 来清除某一个。
一次性设置:生成用来加密它们的密钥,它与应用密钥 分开 保管,这样数据库转储和一次 .env 泄露各自单独都毫无用处:
php artisan store:secrets-key # writes STORE_SECRETS_KEY to .env — then BACK IT UP off the server
php artisan config:clear
丢失 STORE_SECRETS_KEY 会使已存储的凭据无法读取(你只需重新输入它们即可)。
或者从 .env(替代方式)
如果你更愿意,也可以改为在服务器上的 .env 里设置它们,然后重启。当两者都存在时,管理页面的值优先。
# Xendit
XENDIT_SECRET_KEY=...
XENDIT_CALLBACK_TOKEN=... # from Settings → Developers → Webhooks
# PayPal
PAYPAL_CLIENT_ID=...
PAYPAL_SECRET=...
PAYPAL_ENV=sandbox # or: live
一个没有凭据的网关就是被简单地关掉了——没有其他东西需要启用。
如果你的服务器在代理或防火墙之后
webhook 路径是一个 公开的、服务器到服务器的 URL。它没有登录,出于必要——支付商无法以你的身份登录。它转而由支付商自己的签名或令牌、一次直接从支付商权威地重新读取支付状态,以及一个速率限制来保护。
这意味着 POST /webhooks/* 必须能从公共互联网访问到。如果你屏蔽它,或者把整个站点放在一个 IP 允许列表之后,异步支付就不再被履行——症状与从未配置过 URL 完全一样地悄无声息。