Webhooks
Webhooks
#Overview
Webhooks allow Hiboutik to automatically notify an external application when an event occurs on your account.
Instead of regularly querying the Hiboutik API to detect changes, you can configure an HTTP endpoint that Hiboutik will call when the corresponding event occurs.
Common use cases include:
- synchronizing inventory after a sale;
- synchronizing customers with an external system;
- reacting to product updates;
- processing payments or sale items;
- synchronizing stock transfers;
- triggering external workflows.
#Configuration
Webhooks can be configured from your Hiboutik account under:
Settings / API
Additional webhook configurations are available through the Hiboutik API.
On multi-store accounts, webhooks can be restricted to specific points of sale.
Webhooks can be processed synchronously or asynchronously.
#Receiving webhooks
Hiboutik sends webhook requests using HTTP POST.
The request body is encoded as:
Content-Type: application/x-www-form-urlencoded
The data contained in the payload depends on the webhook event.
#Webhook authentication
Webhook requests sent by Hiboutik are signed using HMAC-SHA256.
Each Hiboutik account has its own Webhook secret key, available under:
Settings / API → Webhook secret key
This key must be kept confidential.
#Signature header
The HMAC signature is sent in the following HTTP header:
X-HIBOUTIK-HMAC-SHA256: <signature>
The signature is calculated using:
- the HMAC-SHA256 algorithm;
- the account's Webhook secret key;
- the exact URL-encoded HTTP request body sent by Hiboutik.
Conceptually:
HMAC-SHA256(raw_request_body, webhook_secret_key)
The resulting hexadecimal digest is sent in the X-HIBOUTIK-HMAC-SHA256 header.
#Verifying the signature
The signature should always be verified before processing the webhook data.
It is important to calculate the signature from the raw HTTP request body exactly as received.
Do not reconstruct the signed payload from parsed POST parameters. Parsing and serializing the parameters again may change their encoding or ordering and therefore produce a different signature.
#PHP example
<?php
$payload = file_get_contents('php://input');
$signature = $_SERVER['HTTP_X_HIBOUTIK_HMAC_SHA256'] ?? '';
$webhookSecretKey = 'YOUR_WEBHOOK_SECRET_KEY';
$expectedSignature = hash_hmac(
'sha256',
$payload,
$webhookSecretKey
);
if (
empty($signature) ||
!hash_equals($expectedSignature, $signature)
) {
http_response_code(401);
exit('Invalid webhook signature');
}
parse_str($payload, $data);
// Process the webhook...
Using hash_equals() is recommended for comparing the received and expected signatures.
#Security considerations
The current webhook signature authenticates the HTTP request body.
The signature does not include a timestamp or a unique delivery identifier. There is currently no timestamp-based replay-protection mechanism associated with the webhook HMAC signature.
Webhook consumers should therefore implement appropriate safeguards according to their own security requirements and should be able to safely handle duplicate deliveries.
HMAC signature verification using X-HIBOUTIK-HMAC-SHA256 is the recommended method for authenticating incoming Hiboutik webhook requests.
#Webhook events and payloads
#sale
Triggered when a sale is closed.
The webhook contains the complete sale payload.
The exact fields therefore depend on the content of the sale and correspond to the sale data exposed by Hiboutik.
#sale_item
Triggered when a product line is added, deleted, or updated on a sale.
The type field identifies the operation.
Product added (type=add)
| Field | Description |
|---|---|
order_id |
Sale identifier |
sale_id |
Sale identifier |
type |
add |
line_item |
Sale line identifier |
product_id |
Product identifier |
product_size |
Product size identifier |
quantity |
Quantity added |
product_price |
Product price |
Example:
order_id=12345
sale_id=12345
type=add
line_item=678
product_id=42
product_size=3
quantity=2
product_price=19.90
Product deleted (type=del)
| Field | Description |
|---|---|
order_id |
Sale identifier |
sale_id |
Sale identifier |
type |
del |
store_id |
Store identifier |
line_item |
Sale line identifier |
product_id |
Product identifier |
product_size |
Product size identifier |
quantity |
Quantity concerned by the deletion |
Product line updated (type=update)
| Field | Description |
|---|---|
order_id |
Sale identifier |
sale_id |
Sale identifier |
type |
update |
store_id |
Store identifier |
line_item |
Sale line identifier |
product_id |
Product identifier |
product_size |
Product size identifier |
quantity |
Current quantity |
Depending on the operation, the fields are not strictly identical. For example,
product_priceis sent when a product is added, whilestore_idis sent for deletion and update operations.
#payment
Triggered when a payment method is selected, added, deleted or modified on a sale.
Several payload formats can be sent depending on the payment operation.
Standard payment event
| Field | Description |
|---|---|
sale_id |
Sale identifier |
shop_id |
Store identifier |
vendor_id |
User/vendor identifier |
payment_type |
Payment method identifier |
total |
Sale total |
currency |
Sale currency |
Cash tendered
| Field | Description |
|---|---|
sale_id |
Sale identifier |
shop_id |
Store identifier |
vendor_id |
User/vendor identifier |
total |
Sale total |
action |
cash_tendered |
cash_tendered |
Amount of cash tendered |
cash_change |
Change returned |
payment_type |
Payment method identifier |
currency |
Sale currency |
Additional / split payment
| Field | Description |
|---|---|
sale_id |
Sale identifier |
shop_id |
Store identifier |
vendor_id |
User/vendor identifier |
action_div |
add |
payment_type |
Payment method identifier |
payment_amount |
Payment amount |
payment_detail_id |
Payment detail identifier |
payment_date |
Payment date |
currency |
Sale currency |
The exact fields depend on the payment action. Consumers should not assume that every
paymentwebhook contains all payment fields listed above.
#customer
Triggered when a customer record is created, modified, or deleted.
| Field | Description |
|---|---|
customer_id |
Customer identifier |
shop_id |
Store identifier |
date_time |
Date and time of the event |
The payload identifies the affected customer but does not contain the complete customer record.
If additional customer information is required, it can be retrieved through the Hiboutik API.
The payload itself does not indicate whether the customer was created, modified, or deleted.
#store_credit
Triggered when a store credit entry is added to a customer account.
| Field | Description |
|---|---|
customer_id |
Customer identifier |
credit_line_id |
Store credit line identifier |
shop_id |
Store identifier |
date_time |
Date and time of the event |
#product
Triggered when a product is created, modified, deleted, or when a lightweight stock update occurs.
Product record change
| Field | Description |
|---|---|
product_id |
Product identifier |
shop_id |
Store identifier |
date_time |
Date and time of the event |
The payload identifies the affected product but does not contain the complete product record.
If additional product information is required, it can be retrieved through the Hiboutik API.
For this payload, the webhook itself does not indicate whether the product was created, modified, or deleted.
Lightweight stock update
| Field | Description |
|---|---|
product_id |
Product identifier |
shop_id |
Store identifier |
action |
update_stock_light |
size_id |
Product size identifier |
warehouse_id |
Warehouse identifier |
quantity |
Updated stock quantity |
date_time |
Date and time of the event |
#stock_order
Triggered when a stock order is received, unreceived, or when one of its product lines is updated.
Common fields
| Field | Description |
|---|---|
inventory_input_id |
Stock order identifier |
shop_id |
Store identifier |
user_id |
Identifier of the user who performed the action |
date_time |
Date and time of the event |
event[label] |
Type of stock order event |
Possible values for event[label] include:
stock_order_receivedstock_order_unreceivedqtity_updatedproduct_line_receivedproduct_line_unreceivedproduct_line_price_update
For qtity_updated, product_line_received, product_line_unreceived and product_line_price_update, the following additional fields are sent:
| Field | Description |
|---|---|
event[inventory_input_detail_id] |
Stock order line identifier |
event[product_id] |
Product identifier |
event[product_size] |
Product size identifier |
event[quantity] |
Quantity associated with the event |
Example:
inventory_input_id=123
shop_id=1
user_id=12
date_time=2026-09-01+11%3A00%3A00
event[label]=product_line_received
event[inventory_input_detail_id]=456
event[product_id]=42
event[product_size]=3
event[quantity]=10
For
product_line_price_update, the updated purchase price itself is not included in the webhook payload. Retrieve the stock order information through the Hiboutik API if the new value is required.
#stock_transfer
Triggered when a stock transfer between stores is confirmed.
| Field | Description |
|---|---|
transfer_id |
Stock transfer identifier |
shop_id |
Store identifier |
date_time |
Date and time of the event |
#line_item_exchange
Triggered when a product is returned or exchanged on a sale.
| Field | Description |
|---|---|
sale_id |
Sale identifier |
line_item_id |
Sale line identifier |
warehouse_id |
Warehouse identifier |
shop_id |
Store identifier |
date_time |
Date and time of the event |
vendor_id |
User/vendor identifier |
#sale_creation
Triggered when a sale is created.
| Field | Description |
|---|---|
order_id |
Sale identifier |
sale_id |
Sale identifier |
shop_id |
Store identifier |
type |
sale_creation |
#sale_deletion
Triggered when a sale is deleted.
| Field | Description |
|---|---|
order_id |
Deleted sale identifier |
sale_id |
Deleted sale identifier |
shop_id |
Store identifier |
type |
sale_deletion |
#Synchronous webhooks
Synchronous webhook requests have a 4-second timeout.
The receiving endpoint must return:
HTTP 200 OK
The endpoint should perform only the operations required before acknowledging the request.
If processing may take longer, asynchronous webhooks should be used.
#Asynchronous webhooks
Asynchronous webhook requests have a 10-second timeout.
A successful delivery must return:
HTTP 200 OK
As soon as Hiboutik receives an HTTP 200 response, the webhook is considered successfully delivered and no further attempts are made.
If Hiboutik does not receive HTTP 200, for example because the endpoint returns another status code, the connection fails, or the request times out, another delivery attempt is scheduled.
Hiboutik performs up to 8 additional attempts, with an increasing delay between attempts.
Retry attempts stop immediately when an HTTP 200 response is received.
If no HTTP 200 response is received after all attempts, the webhook is abandoned.
Because asynchronous webhooks may be delivered more than once, webhook consumers should process requests idempotently whenever possible.
#Recommended processing flow
When receiving a Hiboutik webhook:
- Read the raw HTTP request body.
- Read the
X-HIBOUTIK-HMAC-SHA256header. - Calculate the HMAC-SHA256 of the raw body using your Webhook secret key.
- Compare the calculated signature with the received signature using a timing-safe comparison.
- Reject the request if the signature is invalid.
- Parse the
application/x-www-form-urlencodedpayload. - Process the webhook.
- Return HTTP
200 OKwithin the applicable timeout.
For asynchronous webhooks, the receiving application should also be designed to safely handle duplicate deliveries.