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
X-Webhook-Signature authenticates the exact raw request body. Verify it before
parsing the JSON. Compute HMAC-SHA256 with your webhook signing secret and
compare the result 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.
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.
Using Events for Business Decisions
Use webhooks as notifications of payment or order activity. Before fulfillment, 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 means that a recorded payment
reached Stafiel's confirmation threshold; use data.confirmation for its
confirmation details.
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 name, such as base-main, solana-main, or bsc-testnet. |
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. |
Acknowledgement and Retries
Return 2xx after durably accepting the event; no response body is required.
For a permanent validation failure, return 4xx. If the event was not durably
accepted because of a temporary failure, return a retryable response or allow
the request to time out. Redirects are not followed.
Use (network, eventId) as the durable idempotency key. Return 2xx for a
duplicate without repeating the business side effect, and use the current order
state when handling each delivery.
A retry keeps the same payload and eventId.
X-Webhook-Delivery-Attempt increases and X-Webhook-Timestamp records the new
delivery time. Verify every delivery independently.

