Webhooks and Events

Receive signed webhook events from Stafiel.

Receive signed, asynchronous order events from Stafiel at your HTTPS endpoint.

Configure the Endpoint

In the Merchant Dashboard, open **Merchants > select merchant > Merchant Settings

Webhook Configuration**. Save a public HTTPS endpoint. The signing secret is generated on first save and shown in the same section.

Delivery Headers

Every webhook delivery includes the following headers:

Header Description
X-Webhook-Signature HMAC-SHA256 signature for the raw request body, formatted as sha256=<hex>.
X-Webhook-Event-Id Event ID within the network identified by X-App-Network.
X-Webhook-Event-Type Canonical event type, such as order.payment.received_fullpaid.
X-Webhook-Timestamp Delivery-attempt time as a Unix timestamp in milliseconds, for example 1782777600000.
X-Webhook-Delivery-Attempt Delivery attempt number for this event, starting at 1.
X-App-Network Event network: mainnet or testnet.

Signature Verification

Important: Verify X-Webhook-Signature before parsing the JSON. Read the exact raw request body without parsing or reserializing it. Compute HMAC-SHA256 using the webhook signing secret as the key, encoded as UTF-8 text without hex-decoding it. Encode the digest as hexadecimal and compare it with the value after the sha256= prefix using a constant-time comparison.

After verification, require every listed header and confirm that X-Webhook-Event-Id, X-Webhook-Event-Type, and X-App-Network match the payload. Reject missing, malformed, or mismatched values.

The signature covers the request body; delivery headers are outside that signature. A timestamp-age check alone does not establish whether an event has already been processed. Event deduplication is described in Acknowledgement and Retries.

Event Types

Handle event types as exact strings.

Event Type When It Is Sent
order.payment.detected Stafiel detects an incoming payment for the order.
order.payment.received_fullpaid Recorded payment reaches the expected order amount.
order.payment.received_underpaid Recorded payment is below the expected order amount.
order.payment.received_overpaid Recorded payment is above the expected order amount.
order.payment.confirmed A recorded payment reaches Stafiel's confirmation threshold.
order.after_sales.available After-sales functionality becomes available for the order.
order.expired The order enters the expired state.
order.closed The order is closed.
order.compliance_hold The order is held by risk or compliance controls.
order.refund.by_merchant A merchant refund is completed.
order.refund.by_platform A platform-initiated refund is completed.

For payment stages and merchant handling guidance, see Payment Flow and Order Lifecycle and Payment Status. Settlement updates are available through the Settlements API rather than a separate webhook event.

Using Events for Business Decisions

Use webhooks as notifications of payment or order activity. Before fulfillment, or if an expected notification has not arrived, check the current order through the Orders API.

order.payment.received_fullpaid means that the recorded payment amount reached the checkout amount. order.payment.confirmed indicates that a recorded payment reached Stafiel's confirmation threshold. The event's data.confirmation object contains the confirmation details. The data.order.status field reports the order status carried with the event; it is not itself a confirmation signal.

For refund events, use the Refund API and the current order state when updating your own refund records.

Webhook Payload Example

{
  "event": "order.payment.received_fullpaid",
  "eventId": "wh_your_event_id",
  "timestamp": "2026-06-30T00:00:00.000Z",
  "network": "mainnet",
  "data": {
    "order": {
      "id": "ord_your_order_id",
      "merchantId": "mch_your_merchant_id",
      "chainId": 8453,
      "chainName": "base-main",
      "tokenAddress": "0x...",
      "tokenSymbol": "USDC",
      "amountUsd": "49.00",
      "orderAddress": "0x...",
      "status": "fullpaid",
      "totalPaidAmountUsd": "49.00",
      "expiresAt": "2026-06-30T00:15:00.000Z",
      "createdAt": "2026-06-29T23:30:00.000Z",
      "metadata": {
        "customerReference": "CUS-8842"
      }
    },
    "oldBalance": "0.00",
    "newBalance": "49.00",
    "delta": "49.00"
  }
}

Webhook Payload Fields

Field Type Description
event string Canonical event type. See Event Types.
eventId string Event ID within the payload's network.
timestamp string Event creation time in ISO 8601 format, for example 2026-06-30T00:00:00.000Z.
network string mainnet or testnet.
data object Contains data.order and any applicable conditional fields listed below.
data.order.id string Stafiel order ID.
data.order.merchantId string Merchant ID that owns the order.
data.order.chainId number or null Numeric chain ID when available.
data.order.chainName string or null Normalized chain label used in the webhook payload. It may differ from the chain label used when creating the checkout session.
data.order.tokenAddress string or null Token contract or mint address.
data.order.tokenSymbol string or null Token symbol.
data.order.amountUsd string or null Original checkout amount.
data.order.orderAddress string or null Payment contract or payment address.
data.order.status string Order status for this event.
data.order.totalPaidAmountUsd string or null Total recorded payment amount when token decimals are known.
data.order.expiresAt string or null ISO 8601 expiration timestamp.
data.order.createdAt string or null ISO 8601 order creation timestamp.
data.order.metadata object or null Sanitized order metadata.

Conditional Payload Fields

These fields are included only for the listed events:

Field Events Description
data.oldBalance, data.newBalance, data.delta order.payment.detected, order.payment.received_fullpaid, order.payment.received_underpaid, order.payment.received_overpaid; also order.expired when a recorded balance is available Previous balance, current balance, and balance change as decimal strings.
data.confirmation order.payment.confirmed Contains transactionHash, blockNumber, confirmationCount, and confirmedAt.
data.contract order.after_sales.available Contains contractAddress, transactionHash, and contractStatus.
data.refund order.refund.by_merchant, order.refund.by_platform Contains refundType, refundAmountUsd, transactionHash, recipients, chainId, and notes.

Correlate webhook events with your order records using network and data.order.id.

Acknowledgement and Retries

Stafiel treats 2xx responses as successful delivery. Network errors, timeouts, 408, 425, 429, and 5xx responses are eligible for retry. Other unsuccessful HTTP responses end delivery attempts for the event. Redirects are not followed.

Receivers generally persist an event before returning 2xx. A temporary acceptance failure can be reported with a retryable response.

Idempotent handling can use (network, eventId) as the deduplication key and avoid repeating the same business side effect. Once a duplicate is recognized, the receiver can acknowledge it with 2xx.

Delivery attempts use the same verification process. A retry keeps the same payload and event ID, while X-Webhook-Delivery-Attempt increases and X-Webhook-Timestamp records the new delivery attempt.

Note: Normal delivery uses a bounded attempt budget: the initial delivery plus up to four retry attempts. Retry delays generally increase between attempts and may be affected by Retry-After, queue lag, or delivery controls. This is delivery behavior, not a delivery-time SLA.