Order webhooks
When a customer places an order on the marketplace, Garnet sends it to the vendor's system as a webhook: an HTTP POST request to the vendor's registered webhook URL, with the order as JSON payload.
WARNING
Webhook registration is not self-service yet. Contact us with the URL you want orders delivered to, you will receive in return the webhook secret used to verify deliveries.
Topics
| Topic | Sent when |
|---|---|
orders/create | A customer places an order containing at least one of the vendor's products |
orders/updated | That order is later updated (payment, cancellation, refund, address change, edit) |
The order only contains the vendor's own line items: an order spanning several vendors is split, and each vendor receives their share only.
Each delivery includes the following headers:
| Header | Description |
|---|---|
Content-Type | application/json |
X-Garnet-Topic | orders/create or orders/updated |
X-Garnet-Hmac-Sha256 | Base64-encoded signature of the payload (see below) |
Respond with a 2xx status code to acknowledge the delivery. Any other response is treated as a failed delivery and reported to the Garnet team.
Verifying a webhook
Before processing a delivery, verify it was sent by Garnet and not by a third party. Compute the HMAC-SHA256 digest of the raw request body using your webhook secret as the key, base64-encode it, and compare it to the X-Garnet-Hmac-Sha256 header using a constant-time comparison. If they differ, reject the request with a 401 status.
js
import crypto from 'crypto';
function verifyWebhook(rawBody, hmacHeader, secret) {
const digest = crypto.createHmac('sha256', secret).update(rawBody, 'utf8').digest('base64');
return crypto.timingSafeEqual(Buffer.from(digest, 'base64'), Buffer.from(hmacHeader, 'base64'));
}TIP
The digest must be computed on the raw request body, exactly as received — before any JSON parsing or re-serialization. Most frameworks need to be configured to expose the raw body (e.g. express.raw() or the verify option of express.json()).
Order payload
The payload follows the Shopify Order datatype — the exact same format Shopify uses for its own orders/create and orders/updated webhooks.
Test payload
json
{
"id": 5290791567663,
"admin_graphql_api_id": "gid://shopify/Order/5290791567663",
"app_id": 580111,
"browser_ip": "125.208.136.218",
"buyer_accepts_marketing": false,
"cancel_reason": null,
"cancelled_at": null,
"cart_token": "64e26fd0b2dde9496bac47e76abb1cff",
"checkout_id": 36641550467375,
"checkout_token": "104e23f0d8060aa91880be1d3736068c",
"client_details": {
"accept_language": "en-SG",
"browser_height": null,
"browser_ip": "125.208.136.218",
"browser_width": null,
"session_hash": null,
"user_agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:109.0) Gecko/20100101 Firefox/113.0"
},
"closed_at": null,
"confirmed": true,
"contact_email": "vendor+test@garnetmarketplace.com",
"created_at": "2023-04-26T05:13:22-04:00",
"currency": "SGD",
"current_subtotal_price": "126.00",
"current_subtotal_price_set": {
"shop_money": {
"amount": "126.00",
"currency_code": "SGD"
},
"presentment_money": {
"amount": "126.00",
"currency_code": "SGD"
}
},
"current_total_additional_fees_set": null,
"current_total_discounts": "0.00",
"current_total_discounts_set": {
"shop_money": {
"amount": "0.00",
"currency_code": "SGD"
},
"presentment_money": {
"amount": "0.00",
"currency_code": "SGD"
}
},
"current_total_duties_set": null,
"current_total_price": "143.58",
"current_total_price_set": {
"shop_money": {
"amount": "143.58",
"currency_code": "SGD"
},
"presentment_money": {
"amount": "143.58",
"currency_code": "SGD"
}
},
"current_total_tax": "10.08",
"current_total_tax_set": {
"shop_money": {
"amount": "10.08",
"currency_code": "SGD"
},
"presentment_money": {
"amount": "10.08",
"currency_code": "SGD"
}
},
"customer_locale": "en-SG",
"device_id": null,
"discount_codes": [],
"email": "vendor+test@garnetmarketplace.com",
"estimated_taxes": false,
"financial_status": "pending",
"fulfillment_status": null,
"landing_site": "/",
"landing_site_ref": null,
"location_id": null,
"merchant_of_record_app_id": null,
"name": "#1030",
"note": null,
"note_attributes": [],
"number": 30,
"order_number": 1030,
"order_status_url": "https://ananature.com/74172334383/orders/abec6a39605c6db59aea2a722d285b10/authenticate?key=9662ba1502890060c852ff24c798f355",
"original_total_additional_fees_set": null,
"original_total_duties_set": null,
"payment_gateway_names": ["Cash on Delivery (COD)"],
"phone": null,
"presentment_currency": "SGD",
"processed_at": "2023-04-26T05:13:20-04:00",
"reference": "305b49b833b6811a84232c0bb3340d73",
"referring_site": "",
"source_identifier": "305b49b833b6811a84232c0bb3340d73",
"source_name": "web",
"source_url": null,
"subtotal_price": "126.00",
"subtotal_price_set": {
"shop_money": {
"amount": "126.00",
"currency_code": "SGD"
},
"presentment_money": {
"amount": "126.00",
"currency_code": "SGD"
}
},
"tags": "",
"tax_lines": [
{
"price": "10.08",
"rate": 0.08,
"title": "GST",
"price_set": {
"shop_money": {
"amount": "10.08",
"currency_code": "SGD"
},
"presentment_money": {
"amount": "10.08",
"currency_code": "SGD"
}
},
"channel_liable": false
}
],
"taxes_included": false,
"test": false,
"token": "abec6a39605c6db59aea2a722d285b10",
"total_discounts": "0.00",
"total_discounts_set": {
"shop_money": {
"amount": "0.00",
"currency_code": "SGD"
},
"presentment_money": {
"amount": "0.00",
"currency_code": "SGD"
}
},
"total_line_items_price": "126.00",
"total_line_items_price_set": {
"shop_money": {
"amount": "126.00",
"currency_code": "SGD"
},
"presentment_money": {
"amount": "126.00",
"currency_code": "SGD"
}
},
"total_outstanding": "143.58",
"total_price": "143.58",
"total_price_set": {
"shop_money": {
"amount": "143.58",
"currency_code": "SGD"
},
"presentment_money": {
"amount": "143.58",
"currency_code": "SGD"
}
},
"total_shipping_price_set": {
"shop_money": {
"amount": "7.50",
"currency_code": "SGD"
},
"presentment_money": {
"amount": "7.50",
"currency_code": "SGD"
}
},
"total_tax": "10.08",
"total_tax_set": {
"shop_money": {
"amount": "10.08",
"currency_code": "SGD"
},
"presentment_money": {
"amount": "10.08",
"currency_code": "SGD"
}
},
"total_tip_received": "0.00",
"total_weight": 0,
"updated_at": "2023-04-26T05:13:23-04:00",
"user_id": null,
"billing_address": {
"first_name": "Frncois",
"address1": "Tekka Centre",
"phone": null,
"city": "Singapore",
"zip": "123212",
"province": null,
"country": "Singapore",
"last_name": "Rulliere",
"address2": null,
"company": null,
"latitude": null,
"longitude": null,
"name": "Frncois Rulliere",
"country_code": "SG",
"province_code": null
},
"customer": {
"id": 7012590813487,
"email": "vendor+test@garnetmarketplace.com",
"accepts_marketing": false,
"created_at": "2023-04-26T05:13:21-04:00",
"updated_at": "2023-04-26T05:13:22-04:00",
"first_name": "Frncois",
"last_name": "Rulliere",
"state": "disabled",
"note": null,
"verified_email": true,
"multipass_identifier": null,
"tax_exempt": false,
"phone": null,
"email_marketing_consent": {
"state": "not_subscribed",
"opt_in_level": "single_opt_in",
"consent_updated_at": null
},
"sms_marketing_consent": null,
"tags": "",
"currency": "SGD",
"accepts_marketing_updated_at": "2023-04-26T05:13:21-04:00",
"marketing_opt_in_level": null,
"tax_exemptions": [],
"admin_graphql_api_id": "gid://shopify/Customer/7012590813487",
"default_address": {
"id": 9225310241071,
"customer_id": 7012590813487,
"first_name": "Frncois",
"last_name": "Rulliere",
"company": null,
"address1": "Tekka Centre",
"address2": null,
"city": "Singapore",
"province": null,
"country": "Singapore",
"zip": "123212",
"phone": null,
"name": "Frncois Rulliere",
"province_code": null,
"country_code": "SG",
"country_name": "Singapore",
"default": true
}
},
"discount_applications": [],
"fulfillments": [],
"line_items": [
{
"id": 13797034197295,
"admin_graphql_api_id": "gid://shopify/LineItem/13797034197295",
"fulfillable_quantity": 2,
"fulfillment_service": "manual",
"fulfillment_status": null,
"gift_card": false,
"grams": 0,
"name": "Burmanguese Pineapple",
"price": "19.00",
"price_set": {
"shop_money": {
"amount": "19.00",
"currency_code": "SGD"
},
"presentment_money": {
"amount": "19.00",
"currency_code": "SGD"
}
},
"product_exists": true,
"product_id": 8214156149039,
"properties": [],
"quantity": 2,
"requires_shipping": true,
"sku": "BURMANGUESE",
"taxable": true,
"title": "Burmanguese Pineapple",
"total_discount": "0.00",
"total_discount_set": {
"shop_money": {
"amount": "0.00",
"currency_code": "SGD"
},
"presentment_money": {
"amount": "0.00",
"currency_code": "SGD"
}
},
"variant_id": 44827692302639,
"variant_inventory_management": "shopify",
"variant_title": null,
"vendor": "Sunshine Sweet Produce",
"tax_lines": [
{
"channel_liable": false,
"price": "3.04",
"price_set": {
"shop_money": {
"amount": "3.04",
"currency_code": "SGD"
},
"presentment_money": {
"amount": "3.04",
"currency_code": "SGD"
}
},
"rate": 0.08,
"title": "GST"
}
],
"duties": [],
"discount_allocations": []
},
{
"id": 13797034230063,
"admin_graphql_api_id": "gid://shopify/LineItem/13797034230063",
"fulfillable_quantity": 2,
"fulfillment_service": "manual",
"fulfillment_status": null,
"gift_card": false,
"grams": 0,
"name": "Brecheche Pineapple",
"price": "19.00",
"price_set": {
"shop_money": {
"amount": "19.00",
"currency_code": "SGD"
},
"presentment_money": {
"amount": "19.00",
"currency_code": "SGD"
}
},
"product_exists": true,
"product_id": 8214156181807,
"properties": [],
"quantity": 2,
"requires_shipping": true,
"sku": "BRCHECHE",
"taxable": true,
"title": "Brecheche Pineapple",
"total_discount": "0.00",
"total_discount_set": {
"shop_money": {
"amount": "0.00",
"currency_code": "SGD"
},
"presentment_money": {
"amount": "0.00",
"currency_code": "SGD"
}
},
"variant_id": 44807633404207,
"variant_inventory_management": "shopify",
"variant_title": null,
"vendor": "Sunshine Sweet Produce",
"tax_lines": [
{
"channel_liable": false,
"price": "3.04",
"price_set": {
"shop_money": {
"amount": "3.04",
"currency_code": "SGD"
},
"presentment_money": {
"amount": "3.04",
"currency_code": "SGD"
}
},
"rate": 0.08,
"title": "GST"
}
],
"duties": [],
"discount_allocations": []
},
{
"id": 13797034262831,
"admin_graphql_api_id": "gid://shopify/LineItem/13797034262831",
"fulfillable_quantity": 1,
"fulfillment_service": "manual",
"fulfillment_status": null,
"gift_card": false,
"grams": 0,
"name": "Blue Pineapple",
"price": "50.00",
"price_set": {
"shop_money": {
"amount": "50.00",
"currency_code": "SGD"
},
"presentment_money": {
"amount": "50.00",
"currency_code": "SGD"
}
},
"product_exists": true,
"product_id": 8262501531951,
"properties": [],
"quantity": 1,
"requires_shipping": true,
"sku": "green-pineapple",
"taxable": true,
"title": "Blue Pineapple",
"total_discount": "0.00",
"total_discount_set": {
"shop_money": {
"amount": "0.00",
"currency_code": "SGD"
},
"presentment_money": {
"amount": "0.00",
"currency_code": "SGD"
}
},
"variant_id": 44959491457327,
"variant_inventory_management": "shopify",
"variant_title": null,
"vendor": "Lampy Electronics Pte Ltd",
"tax_lines": [
{
"channel_liable": false,
"price": "4.00",
"price_set": {
"shop_money": {
"amount": "4.00",
"currency_code": "SGD"
},
"presentment_money": {
"amount": "4.00",
"currency_code": "SGD"
}
},
"rate": 0.08,
"title": "GST"
}
],
"duties": [],
"discount_allocations": []
}
],
"payment_terms": null,
"refunds": [],
"shipping_address": {
"first_name": "Frncois",
"address1": "Tekka Centre",
"phone": null,
"city": "Singapore",
"zip": "123212",
"province": null,
"country": "Singapore",
"last_name": "Rulliere",
"address2": null,
"company": null,
"latitude": null,
"longitude": null,
"name": "Frncois Rulliere",
"country_code": "SG",
"province_code": null
},
"shipping_lines": [
{
"id": 4327852114223,
"carrier_identifier": "650f1a14fa979ec5c74d063e968411d4",
"code": "Expedited",
"delivery_category": null,
"discounted_price": "7.50",
"discounted_price_set": {
"shop_money": {
"amount": "7.50",
"currency_code": "SGD"
},
"presentment_money": {
"amount": "7.50",
"currency_code": "SGD"
}
},
"phone": null,
"price": "7.50",
"price_set": {
"shop_money": {
"amount": "7.50",
"currency_code": "SGD"
},
"presentment_money": {
"amount": "7.50",
"currency_code": "SGD"
}
},
"requested_fulfillment_service_id": null,
"source": "shopify",
"title": "Expedited",
"tax_lines": [],
"discount_allocations": []
}
]
}