Appearance
Order Webhooks (External Notifications)
Flow ID: IN-20 | Module(s):
ecommercen/libraries/internal/| Complexity: Medium
Business Overview
Ecommercen provides an outbound webhook system that notifies external systems (typically ERP or warehouse management systems) when specific order lifecycle events occur. Three webhook types are supported:
- ERP Ready -- Fired when an order reaches a status that makes it ready for ERP processing (e.g., payment confirmed, order approved).
- Cancel -- Fired when an order is canceled.
- Return -- Fired when an order is returned.
The webhooks operate as fire-and-forget GET requests to configurable external endpoints. Each request includes the order ID in the URL path and is authenticated via a Bearer token. The system is designed for integration with external APIs that need real-time order state notifications.
API Reference
Webhook Types
| Hook | Class | Trait | Config Key | Trigger |
|---|---|---|---|---|
| ERP Ready | AdvInternalApiOrderForErpHook | OrderForErpHookFireTrait | erpReady | Order reaches ERP-ready status |
| Cancel | AdvInternalApiOrderCancelHook | OrderCancelHookFireTrait | cancel | Order is canceled |
| Return | AdvInternalApiOrderReturnHook | OrderReturnHookFireTrait | return | Order is returned |
Outbound Request Format
GET {configured_url}/{orderId}
Headers:
Authorization: Bearer {apiToken}
Accept: application/json
Content-Type: application/json
Options:
connect_timeout: {clientConnectTimeout}
timeout: {clientConnectTimeout}Interface Contract
php
interface InternalApiOrderHookInterface
{
public function fireHook($orderId);
public function getUrl($orderId): string;
}Code Flow
Hook Firing Sequence
Order state change occurs (e.g., order confirmed, canceled, returned)
-> Controller or model uses trait method:
e.g., $this->internalApiOrderForErpHook($orderId)
-> Trait creates hook instance:
(new InternalApiOrderForErpHook())->fireHook($orderId)
-> FireHookTrait::fireHook($orderId):
1. isApiEnabled() -- check config_item('internalApi')['useApi']
-> If false, return immediately (no-op)
2. getUrl($orderId) -- build URL from config
-> Read config_item('internalApi')['apiOrderWebHooks']['{type}']
-> If empty, return '' (no-op)
-> Append /{orderId} to base URL
3. call($url, $orderId) -- execute GET request
-> Create Guzzle client with Bearer token auth
-> GET request with connect_timeout and timeout
-> On exception: log error, continue (fire-and-forget)ERP Ready Hook Usage
Checkout completion / Payment webhook / Admin approval
-> Adv_checkout::internalApiOrderForErpHook($orderId)
or Adv_orders_admin::internalApiOrderForErpHook($orderId)
or AdvSmartCart::internalApiOrderForErpHook($orderId)
or AdvJcc::internalApiOrderForErpHook($orderId)
or Cronjob::internalApiOrderForErpHook($orderId)
-> AdvInternalApiOrderForErpHook->fireHook($orderId)
-> GET {INTERNAL_API_HOOK_ERP_READY}/{orderId}Cancel Hook Usage
Admin cancels order / Incomplete order cleanup job
-> Adv_orders_admin::internalApiOrderCancelHook($orderId)
or Adv_order_model::internalApiOrderCancelHook($orderId)
or AdvCancelIncompleteOrders::internalApiOrderCancelHook($orderId)
or Cronjob::internalApiOrderCancelHook($orderId)
-> AdvInternalApiOrderCancelHook->fireHook($orderId)
-> GET {INTERNAL_API_HOOK_CANCEL}/{orderId}Return Hook Usage
Admin marks order as returned
-> Controller with OrderReturnHookFireTrait
-> AdvInternalApiOrderReturnHook->fireHook($orderId)
-> GET {INTERNAL_API_HOOK_RETURN}/{orderId}Architecture
ecommercen/libraries/internal/
InternalApiOrderHookInterface.php # Contract: fireHook(), getUrl()
FireHookTrait.php # Core logic: enabled check, URL build, call
IsApiEnabledTrait.php # Checks config_item('internalApi')['useApi']
HookGetClientOptionsTrait.php # Builds Guzzle client with Bearer auth
AdvInternalApiOrderForErpHook.php # ERP-ready webhook implementation
AdvInternalApiOrderCancelHook.php # Cancel webhook implementation
AdvInternalApiOrderReturnHook.php # Return webhook implementation
OrderForErpHookFireTrait.php # Convenience trait for controllers/models
OrderCancelHookFireTrait.php # Convenience trait for controllers/models
OrderReturnHookFireTrait.php # Convenience trait for controllers/models
application/libraries/internal/
InternalApiOrderForErpHook.php # Client-overridable (extends Adv* version)
InternalApiOrderCancelHook.php # Client-overridable (extends Adv* version)
InternalApiOrderReturnHook.php # Client-overridable (extends Adv* version)Trait Composition
Each hook implementation uses two traits:
FireHookTrait-- Provides thefireHook()method (enabled check + URL resolution + call)HookGetClientOptionsTrait-- ProvidesgetClient()(Guzzle with auth headers) anddefaultRequestOptions()(timeouts)
The FireHookTrait internally uses IsApiEnabledTrait for the feature toggle check.
Consumer Traits
Controllers and models that need to fire hooks use the convenience traits:
| Trait | Method | Used By |
|---|---|---|
OrderForErpHookFireTrait | internalApiOrderForErpHook($id) | Adv_checkout, Adv_orders_admin, Adv_shopflix_orders_admin, Adv_public_orders_admin, Adv_skroutz_orders_admin, AdvSmartCart, AdvJcc, AdvCancelIncompleteOrders, Cronjob |
OrderCancelHookFireTrait | internalApiOrderCancelHook($id) | Adv_orders_admin, Adv_order_model, AdvCancelIncompleteOrders, Cronjob |
OrderReturnHookFireTrait | internalApiOrderReturnHook($id) | Controllers handling order returns |
Data Model
No Dedicated Tables
Order webhooks do not store state in the database. They are fire-and-forget: the request is made and any failure is logged but not retried. The order itself is not modified by the webhook system.
Order Status Context
The webhooks fire in response to order status transitions managed by the existing order model:
| Webhook | Typical Order Status | Context |
|---|---|---|
| ERP Ready | COMPLETED, CONFIRMED, etc. | After payment confirmation or admin approval |
| Cancel | CANCELED | Admin action or auto-cancel job |
| Return | RETURN | Admin action |
Configuration
Environment Variables (.env)
| Variable | Description | Default |
|---|---|---|
INTERNAL_API_USE | Master toggle for webhook system | false |
INTERNAL_API_TOKEN | Bearer token for authentication | -- |
INTERNAL_API_HOOK_ERP_READY | Base URL for ERP-ready webhook | -- |
INTERNAL_API_HOOK_CANCEL | Base URL for cancel webhook | -- |
INTERNAL_API_HOOK_RETURN | Base URL for return webhook | -- |
INTERNAL_API_CONNECT_TIMEOUT | Guzzle connect timeout (seconds) | 3 |
INTERNAL_API_TIMEOUT | Guzzle request timeout (seconds) | 3 |
Config File (application/config/api.php)
php
$config['internalApi'] = [
'useApi' => env('INTERNAL_API_USE', false),
'apiToken' => env('INTERNAL_API_TOKEN'),
'apiOrderWebHooks' => [
'erpReady' => env('INTERNAL_API_HOOK_ERP_READY'),
'cancel' => env('INTERNAL_API_HOOK_CANCEL'),
'return' => env('INTERNAL_API_HOOK_RETURN')
],
'clientConnectTimeout' => env('INTERNAL_API_CONNECT_TIMEOUT', 3),
'clientTimeout' => env('INTERNAL_API_TIMEOUT', 3),
];Selective Activation
Each webhook type can be independently enabled or disabled:
- Set
INTERNAL_API_USE=trueto enable the system globally. - Leave any
INTERNAL_API_HOOK_*variable empty to disable that specific webhook type. - The
getUrl()method returns empty string for unconfigured hooks, causingfireHook()to no-op.
Client Extension Points
Override Hook Classes
Client repos provide application/libraries/internal/InternalApiOrderForErpHook.php (etc.) which extend the Adv* versions. Override these to:
- Change the HTTP method (e.g., POST instead of GET)
- Add custom request headers or body
- Add retry logic
- Modify URL construction
- Add response processing
Override Traits
Replace the convenience traits in application/libraries/internal/ if the hook instantiation pattern needs to change (e.g., injecting dependencies, using a different hook class).
Custom Webhooks
To add a new webhook type (e.g., order update, partial refund):
- Create a new
Adv*Hookclass implementingInternalApiOrderHookInterface - Use
FireHookTraitandHookGetClientOptionsTrait - Add the URL config key in
application/config/api.php - Create a convenience trait for consumer classes
- Add the trait to relevant controllers/models
Business Rules
- Master toggle: The entire webhook system is disabled when
INTERNAL_API_USEis false. No network calls are made. - Fire-and-forget: Webhook failures are logged but do not affect order processing. The order state change completes regardless of webhook success or failure.
- No retries: Failed webhooks are not retried. External systems must implement their own reconciliation if they miss a notification.
- GET method: All webhooks use HTTP GET with the order ID in the URL path. This design assumes the receiving system uses the order ID to fetch order details from Ecommercen's API.
- Bearer token auth: All webhook requests include an
Authorization: Bearerheader with the configured API token. The receiving system should validate this token. - Timeout protection: Both connect and request timeouts are configured (default 3 seconds each) to prevent webhook calls from blocking order processing.
- Idempotency: The same webhook may fire multiple times for the same order (e.g., if the status transition is triggered by multiple code paths). External systems should handle duplicate notifications idempotently.
- Marketplace integration: The ERP Ready hook is used by marketplace order controllers (Skroutz, Shopflix, SmartCart) ensuring external ERPs are notified regardless of the order source.
Related Flows
- CF-07 Order Confirmation -- Order status transitions that trigger ERP Ready hook
- CF-08 Payment Processing -- Payment webhooks (JCC, SmartCart) that fire ERP Ready hook
- AD-11 Marketplace Orders -- Marketplace order processing with ERP Ready hook
- SY-01 Cron Framework --
AdvCancelIncompleteOrdersjob fires both cancel and ERP hooks