Skip to content

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 ​

TopicSent when
orders/createA customer places an order containing at least one of the vendor's products
orders/updatedThat 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:

HeaderDescription
Content-Typeapplication/json
X-Garnet-Topicorders/create or orders/updated
X-Garnet-Hmac-Sha256Base64-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": []
    }
  ]
}