Orders
Technical details for partners integrating with the Event Bridge system to receive real-time order event notifications via webhooks. Our service processes orders and sends it to your provided endpoint
Prerequisites
To integrate, our team will work with you to configure:
Your Webhook URL: A secure HTTPS URL endpoint on your system capable of receiving HTTP POST requests with a JSON payload.
Shared Secret (Generated by Us): We will generate a unique, secure secret string for your specific webhook configuration. This secret must be used by you to verify the HMAC signature on incoming requests. We will provide this secret to you securely.
Custom Headers (Optional): You can specify any additional HTTP headers (key-value pairs) you require us to include in the webhook requests (e.g., for static authentication tokens or routing). We will store and send these with each request, provided they don't conflict with essential headers.
Webhook Request Details
Our service will send events to your configured Webhook URL using the following specifications:
Method:
POST
Headers:
Content-Type: application/json
User-Agent: liquid-commerce-event-bridge-service/1.0
x-liquid-commerce-event-type
: The type of event (e.g.,order
).x-liquid-commerce-hmac-sha256
: The HMAC signature (see Security section).x-liquid-commerce-idempotency-key
: A unique identifier for this specific webhook delivery attempt, generated by our service.x-liquid-commerce-delivery-id
: A unique identifier for this delivery, constructed from order identifiers and a timestamp.x-liquid-commerce-timestamp
: An ISO 8601 timestamp indicating when the webhook was sent by our service.Any custom headers you provided during setup.
Payload Structure (event-type: order
)
event-type: order
)The request body is a complex JSON object representing the transformed and serialized order data. The following structure, but may be simplified for documentation clarity. Refer to specific fields relevant to your integration.
{
referenceId: 'unique-order-ref-123', // Optional: Our internal unique order reference for new services orders
legacyOrderNumber: 'RBR-LEGACY-456', // Optional: Legacy order number if applicable
isHybrid: false, // Flag indicating if order involves legacy components
partnerId: 'partner-id', // Your assigned Partner ID in our system
createdAt: '2023-10-27T10:00:00.000Z', // ISO 8601 timestamp of order creation
updatedAt: '2023-10-27T10:30:00.000Z', // ISO 8601 timestamp of last relevant update triggering webhook
customer: {
id: 'cust-id',
firstName: 'Jane',
lastName: 'Doe',
email: '[email protected]',
phone: '(212) 290-9820',
birthdate: '1990-05-15', // YYYY-MM-DD
},
addresses: {
shipping: {
firstName: 'Jane',
lastName: 'Doe',
email: '[email protected]',
phone: '+15551234567',
company: null,
one: '123 Main St',
two: 'Apt 4B',
city: 'Anytown',
state: 'CA',
zip: '90210',
country: 'US',
},
billing: {
// ... similar structure, may differ from shipping ...
firstName: 'Jane',
lastName: 'Doe',
email: '[email protected]',
phone: '+15551234567',
company: null,
one: '123 Main St',
two: 'Apt 4B',
city: 'Anytown',
state: 'CA',
zip: '90210',
country: 'US',
},
},
options: {
isGift: true,
giftMessage: 'Happy Birthday!',
giftRecipient: {
name: 'John Smith',
email: '[email protected]',
phone: '+15559876543',
},
hasVerifiedAge: true,
allowsSubstitution: false,
billingSameAsShipping: true,
deliveryInstructions: 'Leave at front door.',
marketingPreferences: {
email: false,
sms: false,
},
},
amounts: {
subtotal: 10000,
shipping: 1000,
platform: 599, // Fee charged by our platform
tax: 850,
engraving: 500,
service: 200,
delivery: 0, // Specific delivery fee component
discounts: 1500, // Total discounts applied
giftCards: 2500, // Amount paid via gift cards
tip: 500,
total: 9150,
taxDetails: {
products: 700,
shipping: 100,
delivery: 0,
bag: 0,
bottleDeposits: 5,
retailDelivery: 0,
},
discountDetails: {
products: 1000,
shipping: 500,
delivery: 0,
engraving: 0,
service: 0,
},
},
paymentMethods: [
{
type: 'card', // e.g., card, paypal
card: 'Visa', // e.g., Visa, Mastercard
last4: '1234',
holder: 'Jane Doe',
code: null, // If a Gift Card was used an abstrct code will be available (ex: 'TER*****FH9W48Y')
},
],
retailers: [
{
id: 'retailer-id-1',
legacyId: 'legacy-retailer-abc',
name: 'Best Drinks Store',
system: 'LiquidCommerce OMS', // Actual values: LiquidCommerce OMS, ReserveBar OMS
timezone: 'America/Los_Angeles',
address: {
one: '456 Side St',
two: null,
city: 'Anytown',
state: 'CA',
zip: '90211',
country: 'US',
coordinates: {
latitude: 34.0522,
longitude: -118.2437,
},
},
amounts: {
// Amounts specific to this retailer's fulfillment
// ... structure similar to top-level amounts ...
subtotal: 6000,
shipping: 500,
platform: 599,
tax: 510,
engraving: 5000,
service: 120,
delivery: 0,
discounts: 1000,
giftCards: 1000,
tip: 250,
total: 5940,
taxDetails: {
products: 700,
shipping: 100,
delivery: 0,
bag: 0,
bottleDeposits: 5,
retailDelivery: 0,
},
},
discountDetails: {
products: 1000,
shipping: 500,
delivery: 0,
engraving: 0,
service: 0,
},
},
fulfillments: [
{
id: 'fulfillment-id-xyz',
type: 'onDemand', // Actual values: shipping, onDemand, digital, bopis
status: 'processing', // Actual values: created, processing, inTransit, canceled, delivered
scheduledFor: null, // ISO 8601 if scheduled
updatedAt: '2023-10-27T10:25:00.000Z',
itemIds: ['item-id-1', 'item-id-2'],
packages: [
{
id: 'package-id-123',
carrier: 'UPS',
trackingNumber: '1Z999AA10123456784',
trackingUrl: 'https://wwwapps.ups.com/...',
status: 'shipped', // Actual values: created, processing, inTransit, canceled, delivered
dateShipped: '2023-10-27T10:25:00.000Z',
},
],
timeline: [
{ status: 'created', timestamp: '2023-10-27T10:00:00.000Z' }, // Actual values for status: created, scheduled, onHold, pending, processing, inTransit, delivered, canceled
{ status: 'processing', timestamp: '2023-10-27T10:15:00.000Z' },
// Potentially more status updates (inTransit, delivered, etc.)
],
},
// Potentially multiple fulfillments per retailer if split
],
},
// Potentially multiple retailers if multi-retailer order
],
items: [
{
id: 'item-id-1',
fulfillmentId: 'fulfillment-id-xyz',
retailerId: 'retailer-id-1',
variantId: 'variant-id-1',
liquidId: 'liquid-id-123',
legacyGrouping: null,
legacyPid: 'pid-abc',
customerPlacement: 'standard', // Actual values for status: standard, pre_sale, back_order
isPresale: false,
estimatedShipBy: null,
product: {
name: 'Example Wine 750ml',
brand: 'Example Vineyards',
upc: '012345678912',
sku: 'EXWINE750',
mskus: ['RETAILER123'],
category: 'Red Wine',
size: '750ml',
volume: '750',
uom: 'ml',
proof: null,
attributes: {
pack: false,
packDescription: null,
abv: '13.5',
container: 'Bottle',
containerType: 'Glass',
},
},
image: 'https://example.com/image.jpg',
pricing: {
price: 2000,
unitPrice: 2000,
quantity: 2,
tax: 340,
bottleDeposits: 20,
},
attributes: {
engraving: {
hasEngraving: true,
fee: 5000,
location: 'Front',
lines: ['Line 1 Text', 'Line 2 Text'],
},
giftCard: {
// Based on PartnerOrderItemGiftCardSerialization
sender: 'Jane Doe',
message: null,
recipients: ['John Smith <[email protected]>'],
sendDate: null,
},
},
},
// ... more items ...
],
}
Key Fields & Notes:
Identifiers:
referenceId
,partnerId
,retailers[].id
,items[].id
, etc., are our internal relevant identifiers.Timestamps: All timestamps are in ISO 8601 format (UTC).
Payload Granularity: The payload contains details potentially aggregated across multiple internal entities (orders, shipments, fulfillments, retailers). The
retailers
array allows for orders fulfilled by multiple retailers. Each retailer has its ownfulfillments
,packages
, andamounts
.Status Fields: Note the different status enums used at different levels (e.g.,
fulfillments[].status
vs.packages[].status
). Use the status most relevant to your needs.Amounts: Amounts are provided at the top level (order total) and broken down within
amounts.taxDetails
,amounts.discountDetails
, and also within eachretailers[].amounts
. Item-level pricing is initems[].pricing
.Optional Fields: Many fields are optional (nullable) depending on the specific order details (e.g.,
giftMessage
,deliveryInstructions
,legacyOrderNumber
,referenceId
). At leastreferenceId
orlegacyOrderNumber
will be included and for hybrid orders you'll receive both.Additional Headers: Our service includes a few additional headers for traceability and idempotency assistance:
x-liquid-commerce-idempotency-key
: A unique UUID for each delivery attempt. While you must implement your own idempotency based on payload content (likereferenceId
andupdatedAt
), this key can be useful for logging and tracing specific delivery attempts on your end.x-liquid-commerce-delivery-id
: A unique identifier for this delivery, typically formed using order identifiers and a timestamp. Useful for tracing.x-liquid-commerce-timestamp
: An ISO 8601 timestamp marking when the webhook request was initiated from our service.
Headers (Recap)
Content-Type: application/json
User-Agent: liquid-commerce-event-bridge-service/1.0
x-liquid-commerce-event-type
: e.g.,orders
x-liquid-commerce-hmac-sha256
: (If secret provided) Base64 encoded HMAC-SHA256 signature.x-liquid-commerce-idempotency-key
: Unique identifier for the delivery attempt.x-liquid-commerce-delivery-id
: Unique identifier for the delivery.x-liquid-commerce-timestamp
: Timestamp of when the webhook was sent.Any custom headers you specified.
Expected Partner Response
Your webhook endpoint must respond promptly to acknowledge receipt.
Success: Respond with an HTTP
2xx
status code (e.g.,200 OK
,202 Accepted
,204 No Content
).Respond immediately after validating the signature (if applicable) and before performing complex/long-running business logic to avoid timeouts. Our service treats any
2xx
as success for the delivery attempt.
Failure: Respond with an HTTP
4xx
(Client Error) or5xx
(Server Error) status code if:The signature verification fails (respond with
401 Unauthorized
or400 Bad Request
).Your service encounters an error preventing acceptance (e.g., temporary overload, validation error on your side).
Retry Mechanism & DLQ
If your endpoint:
Responds with a non-
2xx
status code.Times out (default: 5000ms).
Experiences a network connectivity issue.
Our service will automatically retry 3 times with exponential backoff delays: 1000ms, 2000ms, 4000ms (approximately).
If the event delivery fails after the initial attempt and all 3 retries (total 4 attempts), the original event payload and error details will be sent to our internal Dead Letter Queue (DLQ) which purges after 7 days. No further delivery attempts will be made for that event. Consistent failures indicate an issue with your endpoint that needs investigation.
Idempotency
While we have internal mechanisms, the nature of our Distributed Event Streaming System with at-least-once delivery guarantee means you might receive the same logical update via multiple webhook calls.
It is CRITICAL that your system implements idempotency checks to prevent duplicate processing. Use a combination of identifiers from the payload relevant to your use case. A good candidate is the top-level referenceId
combined with a relevant timestamp like updatedAt
, or specific fulfillment/package IDs if processing at that level.
Example Check: Before processing, check if you've already successfully processed an update for referenceId
with the same or an earlier updatedAt
timestamp. If so, respond 2xx OK
but skip processing.
Security: HMAC Signature Verification
You must verify the x-liquid-commerce-hmac-sha256
header on every incoming request using the unique Shared Secret we provide.
Algorithm: HMAC-SHA256
Encoding: Base64
Data Signed: The raw, unparsed JSON request body (exactly as received, including whitespace).
Verification Steps:
Retrieve the raw request body bytes.
Compute the HMAC-SHA256 hash of the raw body using the Shared Secret we provided.
Encode the resulting hash in Base64.
Securely compare (using a timing-safe comparison function) your calculated signature with the value from the
x-liquid-commerce-hmac-sha256
header.
Failure to implement and correctly verify this signature poses a significant security risk, potentially allowing attackers to send fraudulent data to your endpoint.
Example: Basic Webhook Receiver
Here are conceptual examples demonstrating the core logic (signature verification, immediate acknowledgment, asynchronous processing) in various languages. These examples focus on the essential security and request handling aspects. Refer to the "Webhook Request Details" section for a comprehensive list of all headers your endpoint will receive, including informational headers like x-liquid-commerce-idempotency-key
. Adapt the business logic, error handling, logging, security practices, and asynchronous mechanisms to your specific framework and production needs.
Support
If you encounter issues during integration or have questions about the webhook format or behavior, please contact [email protected].
Last updated