Skip to content

RFC-009: Nexus Webhook Standard (NWS)

MetadataValue
TitleNexus Webhook Standard
Version1.2.0
StatusStandards Track (Draft)
AuthorCipher & Nexus Architect Team
Created2026-02-24
Updated2026-04-01
Depends OnRFC-005v4 (Payment Core)

1. Abstract

本 RFC 定义 Nexus Core 向 Merchant Agent 发送支付结果通知的 Webhook 标准。包括事件类型、Payload 格式、HMAC 安全签名、重试策略和幂等性保障。

2. Motivation

在 Escrow Settlement 模式下,商户需要及时获知以下事件:

  • 用户资金已进入 Escrow(以便发货/出票)
  • 支付超时未完成(以便释放库存)
  • 链上交易失败(以便通知用户重试)
  • 支付被取消(以便释放库存并更新订单状态)

Webhook 是连接 Nexus Core 与 Merchant Agent 的关键桥梁。

3. Event Types

Event TypeTriggerMerchant Expected Action
payment.createdPayment order created in CoreOptional: update internal state
payment.escrowedFunds deposited in escrow contractBegin fulfillment (deliver goods/service)
payment.settledEscrow released to merchant (on-chain)Archive: funds received
payment.completedMerchant confirmed deliveryArchive (informational)
payment.expiredPayment timed outRelease inventory
payment.failedOn-chain transaction revertedNotify user to retry
payment.refundedEscrow refunded to payer (timeout or dispute)Mark order cancelled, release inventory
payment.cancelledPayment cancelled by merchant/operator (v1.2.0)Release inventory, update order status
dispute.openedPayer opened dispute on escrowPrepare dispute evidence
dispute.resolvedArbiter resolved disputeUpdate order based on resolution

4. Webhook Payload Format

4.1 Envelope

json
{
  "event_id": "evt_01JAXYZ123...",
  "event_type": "payment.settled",
  "created_at": "2026-02-24T10:35:00.000Z",
  "data": { ... }
}
  • event_id: UUID v7 (time-ordered), serves as idempotency key
  • event_type: One of the defined event types
  • created_at: ISO 8601 timestamp
  • data: Event-specific payload

4.2 Payment Event Data

json
{
  "data": {
    "nexus_payment_id": "NEX-01JAXYZ-0001",
    "merchant_order_ref": "FLT-1708761234-abc123",
    "merchant_did": "did:nexus:20250407:demo_flight",
    "status": "SETTLED",
    "amount": "530000000",
    "amount_display": "530.00",
    "currency": "XSGD",
    "chain_id": 20250407,
    "payer_wallet": "0x1234...abcd",

    "settlement": {
      "tx_hash": "0xabc123...def456",
      "block_number": 12345678,
      "block_timestamp": "2026-02-24T10:34:55.000Z",
      "payment_address": "0xMerchant...Address"
    },

    "iso_metadata": {
      "end_to_end_id": "NEX-01JAXYZ-0001",
      "remittance_info": "FLT-1708761234-abc123",
      "instructed_amount": "530.00",
      "instructed_currency": "USD",
      "creditor_id": "did:nexus:210425:demo_flight",
      "settlement_asset": "DTI:4H95J0R2X"
    }
  }
}

Notes:

  • settlement object is only present for payment.settled events
  • iso_metadata is OPTIONAL for all payment events (enterprise feature for ERP integration)
  • amount is uint256 string (6 decimals for USDC)
  • amount_display is human-readable decimal string

4.3 Escrow Event Data (v1.1.0 新增)

For escrow-related events (payment.escrowed, payment.refunded, dispute.opened, dispute.resolved), the data payload includes additional escrow fields:

json
{
  "data": {
    "nexus_payment_id": "PAY-01JAXYZ-0001",
    "merchant_order_ref": "FLT-1708761234-abc123",
    "merchant_did": "did:nexus:20250407:demo_flight",
    "status": "ESCROWED",
    "amount": "530000000",
    "amount_display": "530.00",
    "currency": "USDC",
    "chain_id": 20250407,
    "payer_wallet": "0x1234...abcd",

    "escrow": {
      "escrow_contract": "0xeB33a9C2b4c7D3F44Fd5514F90C355AF6bb79236",
      "deposit_tx_hash": "0xabc123...def456",
      "release_deadline": "2026-02-25T10:34:55.000Z",
      "dispute_deadline": "2026-02-27T10:34:55.000Z"
    }
  }
}

4.4 Cancel Event Data (v1.2.0 新增)

For payment.cancelled events, the data payload includes cancellation context:

json
{
  "data": {
    "nexus_payment_id": "PAY-01JAXYZ-0001",
    "merchant_order_ref": "FLT-1708761234-abc123",
    "merchant_did": "did:nexus:20250407:demo_flight",
    "status": "CANCELLED",
    "amount": "530000000",
    "amount_display": "530.00",
    "currency": "XSGD",
    "chain_id": 20250407,
    "payer_wallet": "0x1234...abcd",

    "cancellation": {
      "cancelled_by": "merchant",
      "cancel_reason": "Out of stock",
      "was_escrowed": true,
      "refund_tx_hash": "0xabc123...def456"
    }
  }
}

Notes:

  • was_escrowed: true if funds were on-chain and refunded via cancelByOperator()
  • refund_tx_hash: present only when was_escrowed is true
  • Pre-escrow cancellations have was_escrowed: false and no refund_tx_hash

4.5 Implementation Status (v1.2.0 注记)

以下 RFC-009 特性已在 src/nexus-core/src/services/webhook-notifier.ts 中实现:

  • HMAC-SHA256 签名: X-Nexus-Signature + X-Nexus-Timestamp headers
  • 6 次重试 (exponential backoff: 10s, 30s, 2min, 10min, 30min)
  • webhook_delivery_logs 表记录投递历史
  • Timing-safe signature comparison
  • 11 种事件类型 (含 v1.2.0 新增的 payment.cancelled)

5. HTTP Request Format

5.1 Method and Headers

POST {merchant_webhook_url}
Content-Type: application/json
X-Nexus-Event: payment.settled
X-Nexus-Delivery-Id: evt_01JAXYZ123
X-Nexus-Timestamp: 1708766100
X-Nexus-Signature: sha256=a1b2c3d4e5f6...
User-Agent: Nexus-Webhook/1.0

5.2 Signature Computation

payload = timestamp + "." + raw_request_body
signature = HMAC-SHA256(webhook_secret, payload)
header = "sha256=" + hex(signature)

Where:

  • timestamp = value of X-Nexus-Timestamp header (Unix epoch seconds)
  • raw_request_body = exact JSON string sent as POST body
  • webhook_secret = shared secret from merchant_registry

6. Security

6.1 Merchant Verification

Merchants MUST verify incoming webhooks:

Verification Steps:
1. Extract X-Nexus-Timestamp and X-Nexus-Signature headers
2. Compute expected = HMAC-SHA256(my_secret, timestamp + "." + raw_body)
3. Compare: "sha256=" + hex(expected) === X-Nexus-Signature
4. Reject if timestamp is older than 5 minutes (replay protection)
5. Reject if signature does not match

6.2 Idempotency

  • Merchants MUST track event_id to prevent duplicate processing
  • Core MAY deliver the same event multiple times (at-least-once delivery)
  • Merchants MUST handle duplicate deliveries gracefully

6.3 Secret Rotation

  • webhook_secret can be rotated via merchant_registry update
  • During rotation, Core sends with new secret
  • Old secret is invalidated immediately
  • Merchants should update their verification within the rotation window

7. Retry Strategy

7.1 Retry Schedule

AttemptDelay After PreviousCumulative Wait
1 (initial)immediate0
210 seconds10s
330 seconds40s
42 minutes2m 40s
510 minutes12m 40s
6 (final)30 minutes42m 40s

7.2 Success and Failure Criteria

  • Success: HTTP response status 2xx
  • Failure: HTTP 4xx, 5xx, connection timeout, DNS failure
  • Timeout: 10 seconds per request
  • Max Attempts: 6 (1 initial + 5 retries)

7.3 After Max Retries

If all retry attempts fail:

  • Log final failure in webhook_delivery_logs
  • Set payment.webhook_failed flag
  • Merchant can use nexus_get_payment_status MCP tool to poll
  • Admin dashboard shows undelivered webhooks for manual review

8. Webhook Registration

8.1 Per-Merchant Configuration

Stored in merchant_registry table:

sql
webhook_url    TEXT    -- HTTPS endpoint
webhook_secret TEXT    -- HMAC shared secret (32+ bytes, hex encoded)

8.2 URL Requirements

  • MUST use HTTPS (HTTP only allowed for localhost development)
  • MUST respond within 10 seconds
  • MUST return 2xx to acknowledge receipt
  • SHOULD be idempotent (handle duplicate event_id)

9. Database Schema

sql
CREATE TABLE IF NOT EXISTS webhook_delivery_logs (
  log_id              TEXT PRIMARY KEY,
  nexus_payment_id    TEXT NOT NULL REFERENCES payments(nexus_payment_id),
  merchant_did        TEXT NOT NULL,
  webhook_url         TEXT NOT NULL,
  event_type          TEXT NOT NULL,
  request_body        JSONB NOT NULL,
  response_status     INTEGER,
  response_body       TEXT,
  attempt_number      INTEGER NOT NULL DEFAULT 1,
  next_retry_at       TIMESTAMPTZ,
  delivered_at        TIMESTAMPTZ,
  created_at          TIMESTAMPTZ NOT NULL DEFAULT NOW()
);

CREATE INDEX idx_webhook_payment ON webhook_delivery_logs (nexus_payment_id);
CREATE INDEX idx_webhook_retry ON webhook_delivery_logs (next_retry_at)
  WHERE delivered_at IS NULL AND attempt_number <= 6;

10. Merchant SDK Integration

The @nexus/seller-sdk SHOULD provide a webhook verification helper:

typescript
import { verifyWebhook } from '@nexus/seller-sdk';

app.post('/webhook/nexus', (req, res) => {
  const isValid = verifyWebhook({
    secret: process.env.NEXUS_WEBHOOK_SECRET,
    signature: req.headers['x-nexus-signature'],
    timestamp: req.headers['x-nexus-timestamp'],
    body: req.rawBody,
  });

  if (!isValid) {
    return res.status(401).json({ error: 'Invalid signature' });
  }

  const { event_type, data } = req.body;

  switch (event_type) {
    case 'payment.escrowed':
      // Funds in escrow — begin fulfillment (deliver goods/service)
      await fulfillOrder(data.merchant_order_ref);
      // Trigger escrow release via nexus-core
      await confirmFulfillment(data.nexus_payment_id, data.merchant_did);
      break;
    case 'payment.settled':
      // Escrow released — funds received by merchant
      await archiveOrder(data.merchant_order_ref);
      break;
    case 'payment.expired':
      // Release inventory
      await releaseInventory(data.merchant_order_ref);
      break;
    case 'payment.refunded':
      // Escrow refunded to payer
      await cancelOrder(data.merchant_order_ref);
      break;
    case 'payment.cancelled':
      // Payment cancelled by merchant/operator
      await cancelOrder(data.merchant_order_ref);
      await releaseInventory(data.merchant_order_ref);
      break;
    case 'dispute.opened':
      // Prepare dispute evidence
      await prepareDisputeEvidence(data.merchant_order_ref);
      break;
  }

  res.status(200).json({ received: true });
});

11. Testing

11.1 Webhook Testing Endpoint

Core SHOULD provide a test webhook tool:

MCP Tool: nexus_test_webhook
Input: { merchant_did: string, event_type: string }
Action: Sends a test webhook with synthetic data to the merchant's webhook_url
Output: { delivered: boolean, response_status: number }

11.2 Event Log Inspection

Merchants can inspect webhook delivery history via:

  • Core Portal Dashboard (webhook delivery logs section)
  • MCP Resource: nexus://core/webhooks/

Copyright (c) 2026 Nexus Protocol. All Rights Reserved.