Skip to content
Aleksandr SotnikovGet in Touch
All cases

Case studyB2B E-Commerce · ERP

B2B E-Commerce & ERP Webhook Integration

Event-driven integration between a B2B storefront, the ERP and the warehouse. Real-time inventory, automatic order intake and zero manual re-keying.

stock sync latency (was 24 h)
< 30 s
oversell incidents
-90%
orders re-keyed by hand
0
  • Webhooks
  • REST APIs
  • Python
  • Queues
  • HMAC Auth
  • Cloudflare

Context

A wholesale distributor selling to retailers through a B2B web shop. Inventory lived in the ERP, fulfilment ran through a third-party warehouse, and the two talked to the storefront via a nightly CSV export. Every order was re-entered into the ERP by the sales back office.

The operational bottleneck

  • Overselling. Stock on the website could be up to 24 hours old, so fast-moving SKUs were sold twice and orders had to be cancelled.
  • Manual order intake. Back-office staff re-keyed each order, introducing pricing and quantity errors on large B2B baskets.
  • No single source of truth. When numbers disagreed, nobody could tell which system was right.

Architecture

The batch export was replaced with an event-driven integration layer:

  1. Inbound webhooks. order.created, order.updated and refund.created events from the storefront hit a small verification endpoint.
  2. Verification first. Every payload is checked with an HMAC-SHA256 signature and a timestamp tolerance window, so replayed or forged requests are rejected before they reach business logic.
  3. Queue + idempotent workers. Accepted events are queued and processed by workers keyed on the event ID; retries are safe and duplicate deliveries are no-ops.
  4. ERP adapter. Orders are mapped to ERP documents through its REST API, including B2B price lists and customer-specific terms.
  5. Inventory deltas. ERP stock movements are pushed back to the storefront as deltas within seconds, not as a nightly full export.
  6. Failure handling. Exponential backoff, a dead-letter queue and alerting on anything that fails three times; a 15-minute reconciliation job catches the rest.
import hashlib, hmac, time

def verify_webhook(body: bytes, signature: str, timestamp: str, secret: bytes) -> bool:
    if abs(time.time() - int(timestamp)) > 300:  # reject replays older than 5 min
        return False
    expected = hmac.new(secret, timestamp.encode() + b"." + body, hashlib.sha256).hexdigest()
    return hmac.compare_digest(expected, signature)

Observability

Structured logs carry a correlation ID from the storefront event through to the ERP document number, so any order can be traced end to end in seconds. A daily digest reports throughput, retries and anything parked in the dead-letter queue.

Results

Stock on the storefront now reflects the warehouse within seconds, orders flow into the ERP without human touch, and the back office moved from data entry to handling exceptions. Oversell cancellations dropped to a rounding error, and finance finally reconciles against a single source of truth.