商户 Webhook
- 服务地址
https://{merchantWebhookHost}Merchant-owned delivery endpoint configured for the account.- 认证
- Ed25519 签名
- 版本
- 1.1.0
- OpenAPI
- 下载规范
Canonical outbound contract for PSP merchant events delivered to
merchant-owned HTTPS endpoints. The request body is one of five envelopes;
route on the X-Webhook-Event header first.
ClassifiedMerchantWebhookEnvelope: payment intent, transfer and credit card lifecycle events.dataalways carries classification schema version 1 and the resolved public payment classification.UnclassifiedMerchantWebhookEnvelope: refund and account freeze lifecycle events.datacannot carry classification fields.MerchantSettlementWebhookEnvelope:merchant_settlement.*.v1events for settlement items. Different top-level fields; amounts are decimal strings.WithdrawalStatusWebhookEnvelopeandSettlementStatusWebhookEnvelope: flat status bodies sent by the withdrawal and settlement workflows.
Amounts are integers in the currency’s minor unit unless a schema states
otherwise. Fields documented as aliases always carry the same value.
Only the data objects of ClassifiedMerchantWebhookEnvelope and
UnclassifiedMerchantWebhookEnvelope stay open
(additionalProperties: true) so PSP can add fields without a new
contract version. MerchantSettlementWebhookEnvelope, its
MerchantSettlementEventData, both flat status envelopes, the classified
and unclassified envelopes themselves, InvoicePaymentPolicy and
ResolvedPaymentClassification reject undeclared fields. Retries and
operator redeliveries resend the stored body unchanged, so fields
introduced later may be absent from older events. A callback regenerated
by an operator refresh is stored and resent the same way; bodies stored
before a refresh rebuilt the complete event can carry only a subset of the
fields documented as required for first deliveries (for example
classification on payment events), and may omit fields that are optional
for first deliveries as well (for example the refund fee_amount or
original_intent_type). Stable taxonomy IDs,
direction, provenance, aliases,
defaults, and legacy flat classification fields are intentionally not
exposed.
Deliver a merchant transaction event
Section titled “Deliver a merchant transaction event”PSP signs the exact request body as <X-Timestamp>.<raw-body> with the
account-level Ed25519 signing key identified by X-Webhook-Key-ID.
Verify the signature and timestamp window before parsing the body, and
deduplicate by X-Webhook-Event-ID.
请求头
| 名称 | 类型 | 必填 | 说明 |
|---|---|---|---|
X-Timestamp |
string | 必填 | Unix time in seconds (UTC) at which PSP signed this HTTP attempt. It is regenerated on every attempt (automatic retry, merchant manual retry and operator redelivery), so it is neither the event time nor a deduplication key. Reject requests whose value differs from the receiver’s clock by more than 300 seconds. · 格式 ^[0-9]+$ |
X-Signature |
string | 必填 | Standard Base64 encoding of the 64-byte Ed25519 signature over the ASCII bytes <X-Timestamp>.<raw request body>. It is recomputed on every attempt because X-Timestamp changes. Verify against the raw body bytes, never a re-serialized JSON document. · 最短 1 |
X-Signature-Algorithm |
string | 必填 | Signature algorithm; always ed25519. · 固定值 ed25519 |
X-Webhook-Key-ID |
string | 必填 | Identifier of the account-level signing key bound to this delivery. All attempts of a delivery, including operator redeliveries of it, are signed with the originally bound key. Select the public key by this ID and keep retired keys available during rotation. · 最短 1 |
X-Webhook-Version |
string | 必填 | Version of the delivery header and signing contract, fixed to 2026-06-11. It does not version the body; merchant settlement bodies carry their own schema_version. · 固定值 2026-06-11 |
X-Webhook-ID |
string<uuid> | 必填 | Delivery ID. It stays the same across automatic retries and merchant manual retries of one delivery. An operator redelivery creates a new delivery with a new X-Webhook-ID while keeping the same X-Webhook-Event-ID and body. Use it to correlate attempts with PSP delivery records, not for business deduplication. |
X-Webhook-Event |
string | 必填 | Event type of the body: the body event for event/data envelopes, or the body event_type for merchant settlement, withdrawal and settlement status bodies. Route on this header before parsing the body; record and acknowledge event types you do not handle. · 最短 1 |
X-Webhook-Event-ID |
string<uuid> | 必填 | Event ID. It never changes across attempts, manual retries or operator redeliveries of the same event and is the recommended deduplication key. For merchant settlement events it equals the body event_id; for other events it is a stable PSP-derived ID that is not repeated in the body. |
X-Merchant-Account-ID |
string<uuid> | 必填 | Merchant account the delivery belongs to; identical on every attempt. Use it to scope events whose data has no account ID, such as refund completion events. |
请求体 application/json · 必填
变体 ClassifiedMerchantWebhookEnvelope
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
event |
enum | 必填 | 可选值:payment.intent.completed、payment.intent.partially_paid、payment.intent.expired、payment.intent.canceled、payment.transfer.completed、payment.transfer.failed、payment.transfer.returned、creditcard_invoice.captured、creditcard_invoice.3ds_timeout |
timestamp |
string<date-time> | 必填 | Time the event occurred (RFC 3339, may include fractional seconds and an offset). |
data |
object | 必填 | — |
data.classification_schema_version |
integer | 必填 | 固定值 1 |
data.classification |
object | 必填 | — |
data.classification.classification_status |
string | 必填 | 固定值 resolved |
data.classification.payment_category |
string | 必填 | 格式 ^[a-z0-9]+(?:_[a-z0-9]+)*$ |
data.classification.payment_method |
string | 必填 | 格式 ^[a-z0-9]+(?:_[a-z0-9]+)*$ |
data.classification.rail_variant |
string | 必填 | 格式 ^[a-z0-9]+(?:_[a-z0-9]+)*$ |
变体 UnclassifiedMerchantWebhookEnvelope
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
event |
enum | 必填 | 可选值:payment.refund.completed、payment.transfer_refund.completed、payment.refund.failed、account.frozen、account.unfrozen |
timestamp |
string<date-time> | 必填 | Time the event occurred (RFC 3339, may include fractional seconds and an offset). |
data |
object | 必填 | Merchant event data for event types that do not carry payment classification. |
data.classification_schema_version |
— | 可选 | 该事件不会包含此字段 |
data.classification |
— | 可选 | 该事件不会包含此字段 |
变体 MerchantSettlementWebhookEnvelope
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
schema_version |
string | 必填 | Body schema version. · 固定值 1.0.0 |
event_id |
string<uuid> | 必填 | Original settlement event ID (UUIDv7); the deduplication key. |
event_type |
enum | 必填 | Settlement event type. · 可选值:merchant_settlement.completed.v1、merchant_settlement.adjusted.v1、merchant_settlement.reversed.v1 |
occurred_at |
string<date-time> | 必填 | Event time in UTC. · 格式 ^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(\.\d{1,9})?Z$ |
aggregate_type |
string | 必填 | Aggregate type; always merchant_settlement_item. · 固定值 merchant_settlement_item |
aggregate_id |
string<uuid> | 必填 | Settlement item ID; equals data.merchant_item_id. |
aggregate_version |
integer | 必填 | Settlement item version that produced the event. · ≥ 1 |
data |
object | 必填 | Public settlement item projection. Amounts are non-negative decimal strings in minor units, never JSON numbers, and satisfy gross_amount = merchant_fee_amount + net_amount. |
data.merchant_item_id |
string<uuid> | 必填 | Settlement item ID. |
data.merchant_account_id |
string<uuid> | 必填 | Merchant account ID; equals X-Merchant-Account-ID. |
data.source_type |
enum | 必填 | Source of the settlement item. merchant_settlement.completed.v1 is only delivered for invoice items; adjusted and reversed events use adjustment and reversal respectively. · 可选值:invoice、transfer、refund、chargeback、adjustment、reversal |
data.status |
enum | 必填 | Item status; settled, adjusted or reversed for the respective event type. · 可选值:settled、adjusted、reversed |
data.gross_amount |
string | 必填 | Gross amount as a decimal string in minor units. · 格式 ^(0|[1-9][0-9]*)$ |
data.merchant_fee_amount |
string | 必填 | Merchant fee as a decimal string in minor units. · 格式 ^(0|[1-9][0-9]*)$ |
data.net_amount |
string | 必填 | Net amount as a decimal string in minor units. · 格式 ^(0|[1-9][0-9]*)$ |
data.currency |
string | 必填 | ISO 4217 currency code. · 格式 ^[A-Z]{3}$ |
data.due_at |
string<date-time> | 必填 | Time the item became due for settlement, in UTC. · 格式 ^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(\.\d{1,9})?Z$ |
data.settled_at |
string<date-time> | 必填 | Time the item was settled, in UTC. · 格式 ^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(\.\d{1,9})?Z$ |
data.parent_item_id |
string,null<uuid> | 必填 | Parent settlement item for adjustments and reversals; null otherwise. |
data.relation_type |
enum | 必填 | Relation to parent_item_id; null when there is no parent. · 可选值:adjustment、reversal、null |
变体 WithdrawalStatusWebhookEnvelope
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
event_type |
enum | 必填 | Withdrawal event type; equals X-Webhook-Event. · 可选值:withdrawal.completed、withdrawal.failed |
withdrawal_id |
string<uuid> | 必填 | PSP withdrawal ID. |
status |
enum | 必填 | Terminal withdrawal status. · 可选值:completed、failed |
timestamp |
string<date-time> | 必填 | Workflow time of the status change, UTC with second precision. |
amount |
string | 可选 | Withdrawal amount as a decimal string; present only when populated. |
currency |
string | 可选 | ISO 4217 currency code; present only when populated. |
channel_ref |
string | 可选 | Channel reference; present only when populated. |
e2e_id |
string | 可选 | End-to-end payment identifier; present only when populated. |
error_code |
string | 可选 | Failure code; present only when populated. |
error_message |
string | 可选 | Failure message; present only when populated. |
变体 SettlementStatusWebhookEnvelope
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
event_type |
enum | 必填 | Settlement event type; equals X-Webhook-Event. · 可选值:settlement.completed、settlement.failed、settlement.rejected、settlement.canceled |
settlement_id |
string<uuid> | 必填 | PSP settlement ID. |
status |
enum | 必填 | Settlement status. · 可选值:completed、failed、rejected、canceled |
timestamp |
string<date-time> | 必填 | Workflow time of the status change, UTC with second precision. |
net_amount |
string | 必填 | Settlement amount as a decimal string of integer minor units. · 格式 ^-?(0|[1-9][0-9]*)$ |
currency |
string | 可选 | ISO 4217 currency code; omitted when the settlement has no currency. |
请求示例
curl -X POST 'https://<merchantWebhookHost>/<your-webhook-path>' \ -H 'X-Timestamp: <timestamp>' \ -H 'X-Signature: <signature>' \ -H 'X-Signature-Algorithm: <signature-algorithm>' \ -H 'X-Webhook-Key-ID: <webhook-key-id>' \ -H 'X-Webhook-Version: <webhook-version>' \ -H 'X-Webhook-ID: <webhook-id>' \ -H 'X-Webhook-Event: <webhook-event>' \ -H 'X-Webhook-Event-ID: <webhook-event-id>' \ -H 'X-Merchant-Account-ID: <merchant-account-id>' \ -H 'Content-Type: application/json' \ -d '{ "event": "payment.intent.completed", "timestamp": "2026-01-01T00:00:00Z", "data": { "classification_schema_version": 0, "classification": { "classification_status": "string", "payment_category": "string", "payment_method": "string", "rail_variant": "string" } } }'响应
Event accepted.
Event accepted without a response body.