Webhooks
Webhooks provide real-time notifications whenever an order or return changes state. They are designed as asynchronous notifications, not synchronous APIs.
See also: Webhook Events by State
Overview
Webhook events are emitted when specific order or return states are reached. Each event is delivered via HTTP and must be acknowledged immediately.
Delivery Flow
- An order or return transitions to a new state
- A webhook event is generated
- The event is sent via HTTP POST
- The merchant system:
- Returns HTTP 200
- Processes the event asynchronously
- Failed deliveries are retried
Subscription
Merchants can:
- Register a webhook URL
- Configure a shared secret
- Enable / disable delivery at any time
Webhook delivery starts only after successful registration.
URL Validation (Registration Check)
During registration, the platform performs a one-time endpoint validation to ensure the provided URL is usable.
What we validate
- The endpoint is reachable
- It responds with HTTP 200
Validation request
- Method:
POST - Content-Type:
application/json - Expected response:
HTTP 200
Headers
- If authentication is configured, an
Authorizationheader is included. - The request includes a fixed
User-Agentvalue:
User-Agent: Shopflix WebHook TestWebhook Events
Order Events
| Event Type | Description |
|---|---|
order.created | Emitted when an order enters the initial lifecycle states |
order.delivered | Emitted when the order is successfully delivered |
order.canceled | Emitted when the order is canceled or rejected |
order.deliveryFailed | Emitted when delivery to the customer fails |
Return Events
| Event Type | Description |
|---|---|
return.created | Emitted when a return request is created |
return.deliveringToStore | Emitted while the return is being shipped back |
return.canceled | Emitted when a return is canceled |
return.waitingForSupport | Emitted when manual review is required |
return.completed | Emitted when the return process is finalized |
Return events use the same payload structure as order events. The event is
identified by order_data.eventType; there is no separate return_data root.
Webhook Request
Request Metadata
| Field | Value |
|---|---|
| Method | POST |
| Content-Type | application/json |
| Body format | JSON |
Payload Example
{
"order_data": {
"id": "GR--4004973--MER75",
"eventType": "order.delivered",
"countryCode": "GR",
"hasInvoice": false,
"subTotalItemsAmount": 10,
"totalItemsAmount": 15,
"createdAt": "2025-12-18 07:37:03.000000",
"updatedAt": null,
"expiresAt": null,
"dispatchUntil": null,
"customer": {
"userId": 91755,
"email": "customer42@example.com",
"phone": "+35799123456",
"firstName": "Spencor",
"lastName": "Hopkin"
},
"addressDetails": {
"street": "Test",
"streetNumber": "53",
"postCode": "14451",
"city": "ΜΕΤΑΜΟΡΦΩΣΗ",
"region": "ΑΤΤΙΚΉ",
"regionCode": "ΑΤΤ",
"country": "Greece",
"countryCode": "GR"
},
"invoiceDetails": null,
"carrier": {
"shipmentId": 4047769,
"name": "Courier Center",
"deliveryName": "Courier Center Standard",
"deliveryKey": "courier_center_standard",
"trackingCodes": "013791689230",
"comments": null,
"deliveryToCourierEstimationDate": "18/12/2025",
"deliveryToCustomerEstimationDate": "22/12/2025"
},
"payment": {
"name": "cod"
},
"lineItems": [
{
"id": 42140,
"sku": "SF-100005366",
"merchantEan": "sf-foo-bar-5",
"merchantSku": "MERSKU-SF-09175005-MER75-S",
"productName": "Κρεμαστό Φωτιστικό GloboStar 02084 Μονόφωτο Πλέγμα για Ντουί E27 Μπεζ",
"unitPrice": 10,
"originalUnitPrice": 10,
"totalPrice": 10,
"quantity": 1,
"sfArticle39Valid": false,
"giftWrap": false,
"extendedAttributes": {
"originalValue": ""
}
}
]
},
"timestamp_webhook_creation": "2025-12-18 08:08:37",
"timestamp_webhook_submission": "2025-12-18 08:08:41",
"merchant_webhook_data": {
"merchant_url": "https://merchant.example.com/webhooks/shopflix",
"merchant_token": "merchant-token-placeholder"
}
}Payload Reference
Webhook payloads are sent with snake_case top-level keys. The order model inside
order_data uses camelCase keys.
Top-level Fields
| Field | Type | Required | Description |
|---|---|---|---|
order_data | object | ✅ | Order payload. See Order Data. |
timestamp_webhook_creation | string | ✅ | Timestamp when the webhook queue message was created, formatted as YYYY-MM-DD HH:mm:ss. |
timestamp_webhook_submission | string | ✅ | Timestamp when the webhook delivery attempt was submitted, formatted as YYYY-MM-DD HH:mm:ss. |
merchant_webhook_data | object | ✅ | Merchant webhook routing metadata. See Merchant Webhook Data. |
Order Data
| Field | Type | Required | Description |
|---|---|---|---|
id | string | ✅ | Merchant order reference, e.g. GR--4004973--MER75. |
eventType | string | ✅ | Webhook event name, e.g. order.created, order.delivered, order.canceled, order.deliveryFailed, return.created, return.deliveringToStore, return.canceled, return.waitingForSupport, return.completed. |
countryCode | string | ✅ | Country ISO-2 code. |
hasInvoice | boolean | ✅ | Whether checkout invoice details exist for the order. |
subTotalItemsAmount | number | ✅ | Order subtotal in minor currency units. |
totalItemsAmount | number | ✅ | Order total in minor currency units. |
createdAt | string | ✅ | Merchant order creation timestamp. |
updatedAt | string | null | ⚠️ | Merchant order update timestamp, if available. |
expiresAt | string | null | ⚠️ | Order expiration timestamp, if available. |
dispatchUntil | string | null | ⚠️ | Latest dispatch timestamp/date, if available. |
customer | object | ✅ | Customer information. |
addressDetails | object | ✅ | Shipping address information. |
invoiceDetails | object | null | ⚠️ | Checkout invoice details. null when hasInvoice is false. |
carrier | object | ✅ | Shipment and carrier information. |
payment | object | ✅ | Payment information. |
lineItems | array | ✅ | Merchant order line items. |
Customer
| Field | Type | Required | Description |
|---|---|---|---|
userId | int | ✅ | Numeric customer identifier. Guest orders can return 0. |
email | string | ✅ | Customer email. |
phone | string | null | ⚠️ | Customer phone. |
firstName | string | ✅ | Customer first name. |
lastName | string | ✅ | Customer last name. |
Address Details
| Field | Type | Required | Description |
|---|---|---|---|
street | string | ✅ | Street name/address line 1. |
streetNumber | string | ✅ | Street number/address line 2. |
postCode | string | ✅ | Postal code. |
city | string | ✅ | City. |
region | string | null | ⚠️ | Region/state name. |
regionCode | string | null | ⚠️ | Region/state code. |
country | string | null | ⚠️ | Country name. |
countryCode | string | ✅ | Country ISO-2 code. |
Invoice Details
invoiceDetails contains checkout invoice-request details. It is null when
the customer did not request an invoice.
{
"doy": "1201",
"doyName": "Athens A DOY",
"vatNumber": "EL123456789",
"company": "Example Company SA",
"occupation": "Retail",
"address": "Aiolou 12",
"postCode": "10552",
"city": "Athens",
"article39": null,
"article39Eligible": "1",
"article39IdentityType": "ΔΙ ΔΙΑΒΑΤΗΡΙΟ",
"article39IdentityNo": "AB1234567",
"article39MobilePhone": "+306971234567",
"article39Otp": "842315",
"article39Valid": null
}| Field | Type | Required | Description |
|---|---|---|---|
doy | string | null | ⚠️ | Tax office code. |
doyName | string | null | ⚠️ | Tax office name. |
vatNumber | string | ✅ | Customer VAT number. |
company | string | null | ⚠️ | Company name. |
occupation | string | null | ⚠️ | Business occupation/activity. |
address | string | null | ⚠️ | Invoice address. |
postCode | string | null | ⚠️ | Invoice postal code. |
city | string | null | ⚠️ | Invoice city. |
article39 | string | null | ⚠️ | Article 39 flag/value when present. |
article39Eligible | string | boolean | null | ⚠️ | Whether Article 39 is eligible. |
article39IdentityType | string | null | ⚠️ | Article 39 identity document type label. See Article 39 Identity Type Values. |
article39IdentityNo | string | null | ⚠️ | Article 39 identity document number. |
article39MobilePhone | string | null | ⚠️ | Mobile phone used for Article 39 verification. |
article39Otp | string | null | ⚠️ | Article 39 OTP value. |
article39Valid | string | boolean | null | ⚠️ | Article 39 validation status when available. |
Carrier
| Field | Type | Required | Description |
|---|---|---|---|
shipmentId | int | null | ⚠️ | Sales shipment identifier. |
name | string | null | ⚠️ | Carrier name. |
deliveryName | string | null | ⚠️ | Delivery method name. See Carrier Delivery Method Values. |
deliveryKey | string | null | ⚠️ | Delivery method key. See Carrier Delivery Method Values. |
trackingCodes | string | null | ⚠️ | Shipment tracking code. |
comments | string | null | ⚠️ | Free-text shipment comments. |
deliveryToCourierEstimationDate | string | null | ⚠️ | Estimated handover date to courier. |
deliveryToCustomerEstimationDate | string | null | ⚠️ | Estimated delivery date to customer. |
Payment
payment.name contains the payment method key stored on the order.
| Field | Type | Required | Description |
|---|---|---|---|
name | string | null | ⚠️ | Payment method key. |
Line Items
| Field | Type | Required | Description |
|---|---|---|---|
id | int | ✅ | Sales order item identifier. |
sku | string | ✅ | Product SKU. |
merchantEan | string | null | ⚠️ | Merchant EAN from product offer. |
merchantSku | string | null | ⚠️ | Merchant SKU from product offer. |
productName | string | ✅ | Product name. |
unitPrice | number | ✅ | Unit price paid, in minor currency units. |
originalUnitPrice | number | ✅ | Original unit price, in minor currency units. |
totalPrice | number | ✅ | Total line price, in minor currency units. |
quantity | int | ✅ | Quantity. |
sfArticle39Valid | boolean | ⚠️ | Whether Article 39 was applied/valid for the item. |
giftWrap | boolean | ⚠️ | Gift-wrap flag. Currently returned as false. |
extendedAttributes | object | ⚠️ | Additional item metadata. See Extended Attributes. Empty metadata is sent as {}. |
Extended Attributes
{
"originalValue": "Black / XL"
}| Field | Type | Required | Description |
|---|---|---|---|
originalValue | string | null | ⚠️ | Original selected product-offer value from offer metadata, when available. |
Merchant Webhook Data
merchant_webhook_data contains routing metadata used for webhook delivery.
Treat merchant_token as sensitive and do not log it in plaintext.
{
"merchant_url": "https://merchant.example.com/webhooks/shopflix",
"merchant_token": "merchant-token-placeholder"
}| Field | Type | Required | Description |
|---|---|---|---|
merchant_url | string | null | ⚠️ | Merchant webhook endpoint URL. |
merchant_token | string | null | ⚠️ | Merchant token configured for webhook delivery. Treat this value as sensitive. |
Processing Guidelines
- Return HTTP 200 immediately
- Process events asynchronously
- Handle duplicate deliveries safely
Failure Handling & Retries
What is considered a failure?
A delivery attempt fails if:
- The request times out
- The endpoint returns anything other than HTTP 200
Automatic retries
- Failed deliveries are retried automatically through the webhook retry queue
- A delivery can be retried up to 12 times
- The same queued payload is sent on each automatic retry attempt
Manual Resend from Merchant Portal
Manual webhook resend is supported from the Merchant Portal for merchant orders that have a webhook subscription configured.
Manual resend creates a new asynchronous delivery attempt for the selected
merchant order. It can be triggered from the Merchant Portal, and the success
message means that the webhook delivery was queued. It does not mean that the
merchant endpoint has already received or acknowledged the webhook with HTTP 200.
Use manual resend when:
- The merchant endpoint was temporarily unavailable
- A previous delivery timed out or returned a non-
200response - The merchant has fixed their webhook endpoint and needs the order state sent again
- The merchant needs to reconcile the current order or return state in their system
How to resend
- Open the Merchant Portal
- Go to the order details page
- Open the Details tab
- Click Trigger Webhook Order
- Confirm the action
What gets sent
Manual resend uses the same webhook delivery channel as automatic webhooks:
- The delivery is queued asynchronously
- The request sent to the merchant endpoint is an HTTP
POST - The payload uses the same structure described in Webhook Request
- The merchant endpoint must return
HTTP 200to acknowledge the delivery - Any timeout or non-
200response is treated as a failed delivery
Manual resend is based on the current item states of the merchant order at
the time the action is triggered. The platform maps those states to webhook
eventType values using the same rules as automatic webhook dispatch.
See the full state mapping: Webhook Events by State
Supported manual resend event types:
| Event Type | Supported by manual resend |
|---|---|
order.created | ✅ |
order.delivered | ✅ |
order.canceled | ✅ |
order.deliveryFailed | ✅ |
return.created | ✅ |
return.deliveringToStore | ✅ |
return.canceled | ✅ |
return.waitingForSupport | ✅ |
return.completed | ✅ |
If a merchant order contains items in multiple supported states, more than one webhook may be queued. States that do not map to a webhook event do not produce a manual resend delivery.
Idempotency
Because retries and manual resends are possible:
- The same event may be delivered more than once
- Merchants must treat webhook delivery as at‑least‑once
Recommended strategies:
- Store a unique event key, for example
order_data.eventType+order_data.id+timestamp_webhook_creation - Ignore already‑processed events
- Never rely on delivery count
Security
Registration vs Event Delivery
Registration validation (one-time)
- Uses a fixed
User-Agent: Shopflix WebHook Test - Expects
HTTP 200
Event delivery
- Sends a JSON request body using
Content-Type: application/json - Does not add an extra authentication header by default
- If a merchant token is configured, it is included in
merchant_webhook_data.merchant_token
Monitoring
- Signature validation failures
- 5xx responses
- Delayed processing
- Duplicate event deliveries