Webhooks Framework - Inbound Gateway
by Bitwise Technologies LLC https://github.com/bitwise-hq/odoo-webhooks| Availability |
Odoo Online
Odoo.sh
On Premise
|
| Odoo Apps Dependencies |
Discuss (mail)
|
| Community Apps Dependencies | Show |
| Lines of code | 6683 |
| Technical Name |
bwt_webhooks_inbound |
| License | LGPL-3 |
| Website | https://github.com/bitwise-hq/odoo-webhooks |
| Versions | 15.0 16.0 17.0 18.0 19.0 |
Webhooks Framework - Inbound Gateway
Secure inbound endpoints with signatures, replay protection, and rule-based processing.
Key Features
- Public endpoints with HMAC signature verification (SHA1/256/512, hex/base64).
- Timestamp and idempotency controls to block replayed events.
- Declarative rules to create, update, or upsert Odoo records.
- Semantic bindings to normalize payload fields for consistent rules.
- Full event audit trail with state, retries, and dead-letter flows.
- Operator-friendly views for endpoints, rules, and events.
Configuration
- Go to
Webhooks > Inbound Endpointsand create an endpoint. - Set the path, signature mode, and shared secret(s).
- Define identity and timestamp policies to control replays.
- Attach a handler and configure rule conditions and actions.
Usage
- Send requests to the endpoint path.
- Review events in
Webhooks > Inbound Events. - Reprocess or dead-letter events as needed.
Looking for turnkey integrations? Pair this framework with premium connector addons (e.g., Stripe) to launch faster.
Operator Guide
Webhooks Inbound - Operator Guide
This guide covers the inbound gateway: creating and configuring inbound endpoints, monitoring events, and handling failures.
Prerequisites
Install bwt_webhooks_inbound after bwt_webhooks_core and queue_job are in place. At least one handler with Direction = Inbound must exist before creating an endpoint.
Creating an Inbound Endpoint
Go to Webhooks -> Inbound -> Endpoints -> New.
Required fields:
- Name - human-readable label.
- Path - URL path suffix appended to the webhook base URL (e.g.
/webhooks/my-service). Must be unique across all endpoints. - Handler - select a handler with Direction = Inbound.
- Company - defaults to the current company.
Save the record. The endpoint is immediately active and ready to receive requests at the configured path.
Signature Verification
Under the Signature tab:
- Signature Mode - choose
None(no verification) orShared Secret HMAC(recommended for production). - When HMAC is selected, configure:
- Digest -
SHA256is recommended;SHA1andSHA512are also supported. - Encoding -
HexorBase64, depending on the upstream provider. - Primary Secret - the shared secret from the upstream provider.
- Secondary Secret - optional rotation secret; valid during key rotation.
- Signature Parts - define which header values and payload fragments are concatenated to build the signed message. Order matters and must match the upstream provider specification.
- Signature Header - the request header that carries the signature value (e.g.
X-Signature-256). - Signature Prefix - optional prefix the provider prepends to the value (e.g.
sha256=); it is stripped before comparison.
Identity and Replay Policies
Under the Identity tab:
- Delivery Identity Policy - controls deduplication on receipt (the "same request" check):
Delivery Identity- a header-carried delivery ID.Explicit Idempotency Key- a header-carried idempotency key.Raw Body SHA256- hash of the raw request body.
- Replay Identity Policy - controls business-event-level deduplication (the "same business event" check):
None- no replay protection.Business Event Identity- a field-path extracted event ID.Explicit Idempotency Key- a header-carried idempotency key.
Timestamp Validation
Enable timestamp validation under the Identity tab to reject stale or future-dated requests:
- Timestamp Header - the request header that carries the timestamp value.
- Timestamp Format -
Unix Seconds,Unix Milliseconds, orISO 8601. - Max Age (seconds) - requests older than this value are rejected.
- Max Future Skew (seconds) - requests dated this far ahead are rejected.
Monitoring Events
Go to Webhooks -> Inbound -> Events to see all received events.
Event lifecycle states:
- Received - event stored; not yet processed.
- Processing - background job is running.
- Done - processing completed successfully.
- Error - processing raised an exception; the raw traceback is stored on the event record for inspection.
- Dead Letter - handler returned a dead-letter result; manual review required.
- Rejected - signature or freshness validation failed; the event will not be retried automatically.
Use the State filter and saved views to quickly isolate failures.
Reprocessing and Dead-Letter
To reprocess an event in Error or Dead Letter state:
- Open the event record.
- Click Reset to Received to move it back to the
receivedstate. - Click Process to re-enqueue, or wait for the background runner.
Rejected events cannot be reset. Fix the endpoint configuration first (e.g. correct the signature secret), then resend the request from the upstream provider to create a fresh event.
Troubleshooting Checklist
- Signature mismatch / 401: confirm the shared secret on the endpoint matches the upstream provider exactly, including encoding (hex vs base64) and prefix stripping.
- Events arriving as Rejected with freshness error: the server clock may differ from the upstream provider; increase Max Age or sync NTP.
- Events stuck in Received: check that the
queue_jobworker is running and the job channel is not paused. - Duplicate events not deduplicated: confirm the Delivery Identity Policy is set and the upstream provider sends a consistent identity header.
- Events processed but no records created: open the event form and inspect the Matched Rule and Execution Log to see which rule fired and why the assignment did not produce the expected record.
Developer Guide
Webhooks Inbound - Developer Guide
This guide covers the inbound processing pipeline, model-driven rule contract, and extension points for developers building on or customising the inbound gateway addon.
Inbound Processing Lifecycle
When a request arrives at an inbound endpoint the pipeline is:
- HTTP reception - the controller writes a
bwt.webhook.inbound.eventrecord in statereceivedand enqueues a background job. - Signature verification (if enabled) - HMAC of the configured message parts is compared against the request signature header using constant-time comparison. Failure moves the event to state
rejected. - Freshness check (if enabled) - the timestamp header is parsed and validated against the configured age and skew bounds. Failure ->
rejected. - Delivery identity - a delivery identity key is resolved and checked for duplicates. A duplicate request updates the existing event record; the new request body is not processed again.
- Handler dispatch - the event's handler is called (model-driven rules or Python callback). The return value determines the final state.
Event State Machine
Valid state transitions:
received->processing->donereceived->processing->errorreceived->processing->dead_letterreceived->rejected(signature or freshness failure; not retryable)
Operators can reset error and dead_letter events back to received for reprocessing. rejected events are closed and require a new inbound request.
Model-Driven Rule Processing
Rules are rows on bwt.webhook.inbound.handler.rule, evaluated in ascending sequence order. Each rule exposes:
condition_ids(bwt.webhook.inbound.handler.rule.condition) - each condition specifies a field path into the event payload, an operator (=,!=,in,not in,contains, ...), and a literal value.action_type- one of:
done- mark the event done; stop rule evaluation.dead_letter- move to dead-letter; stop evaluation.retry- re-enqueue afterretry_seconds; stop evaluation.create_record- create a new record ontarget_model_name.update_record- update an existing record located vialookup_ids.upsert_record- create or update; locate vialookup_ids.
assignment_ids(bwt.webhook.inbound.handler.rule.assignment) - each assignment maps a target field name to a value source:resolved_value(extracted from the event payload path),semantic_field(a named semantic binding),event_field(a field on the event record itself), orliteral(a hardcoded string or number).
Value Extraction
The framework extracts values from event payloads using dot-separated paths (e.g. data.object.id). Path resolution is handled by services/value_extraction.py:
walk_payload_path(payload, path)- navigate nested dicts and lists.extract_header(headers, name)- case-insensitive header lookup.extract_header_parameters(value)- parsekey=valuepairs from header parameter strings (e.g.Content-Type: application/json; charset=utf-8).
These helpers are available for use in custom Python callbacks.
Semantic Bindings
Semantic bindings (bwt.webhook.inbound.endpoint.semantic.binding) allow endpoints to map named semantic names (e.g. company_id, partner_id) to resolved values extracted from the request. Assignments can then reference these by semantic name, keeping rule configuration decoupled from specific payload paths.
Extending Inbound Processing
To add a computed field available as an assignment source:
- Extend
bwt.webhook.inbound.eventwith a new stored computed field. - Add a source kind entry pointing to the new field.
- Reference the field name in model-driven rule assignments via the
event_fieldsource kind.
To add a new action type, extend bwt.webhook.inbound.handler.rule and override _execute_model_driven_handler on the event model to dispatch the new type.
No core file edits are required; all extension points use standard Odoo model inheritance.
Please log in to comment on this module