Skip to content

Shopify Order Routing

This use case demonstrates content-based routing for Shopify order webhooks. Orders are routed to different systems based on their value and topic—high-value orders trigger priority fulfillment and PagerDuty alerts, all orders update inventory, and refunds notify the finance team via Slack.

Architecture

mermaid
flowchart LR
    Shopify[Shopify Webhooks] --> Source[Hookbase Source]
    Source --> R1[Route: High-Value]
    Source --> R2[Route: Inventory]
    Source --> R3[Route: Refunds]
    R1 --> |Filter: $500+| D1A[Priority Fulfillment API]
    R1 --> |Filter: $500+| D1B[PagerDuty Alert]
    R2 --> |All Orders| D2[Inventory Management]
    R3 --> |Filter: Refunds| D3["Slack #finance"]

Flow:

  1. Shopify sends order webhooks to Hookbase source endpoint
  2. Source verifies Shopify HMAC signature
  3. Three routes evaluate the event in parallel
  4. Filters match based on order total and topic
  5. Transforms reshape payloads for each destination system

Step 1: Create the Source

Create a Shopify source with HMAC signature verification:

bash
curl -X POST https://api.hookbase.app/api/organizations/{orgId}/sources \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Shopify Production",
    "slug": "shopify-prod",
    "description": "Production Shopify order webhooks",
    "verificationConfig": {
      "type": "shopify",
      "secret": "your_shopify_webhook_signing_secret"
    }
  }'

Response:

json
{
  "data": {
    "id": "src_shopify456",
    "name": "Shopify Production",
    "slug": "shopify-prod",
    "url": "https://api.hookbase.app/ingest/your-org/shopify-prod",
    "verificationConfig": {
      "type": "shopify"
    },
    "createdAt": "2026-02-11T10:00:00Z"
  }
}

TIP

Configure this URL in your Shopify Admin under Settings → Notifications → Webhooks → Create webhook. Subscribe to orders/create, orders/updated, and refunds/create topics.

Step 2: Create Destinations

Create three destinations for priority fulfillment, inventory, and finance notifications:

Priority Fulfillment API

bash
curl -X POST https://api.hookbase.app/api/organizations/{orgId}/destinations \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Priority Fulfillment API",
    "type": "http",
    "config": {
      "url": "https://fulfillment.yourcompany.com/api/priority-orders",
      "method": "POST",
      "headers": {
        "Authorization": "Bearer YOUR_FULFILLMENT_API_KEY",
        "Content-Type": "application/json",
        "X-Priority": "high"
      }
    },
    "retryConfig": {
      "maxAttempts": 5,
      "backoffMultiplier": 2,
      "initialInterval": 1000
    }
  }'

PagerDuty Alert Destination

bash
curl -X POST https://api.hookbase.app/api/organizations/{orgId}/destinations \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "PagerDuty High-Value Orders",
    "type": "http",
    "config": {
      "url": "https://events.pagerduty.com/v2/enqueue",
      "method": "POST",
      "headers": {
        "Content-Type": "application/json"
      }
    },
    "retryConfig": {
      "maxAttempts": 3,
      "backoffMultiplier": 2,
      "initialInterval": 1000
    }
  }'

Inventory Management System

bash
curl -X POST https://api.hookbase.app/api/organizations/{orgId}/destinations \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Inventory Management",
    "type": "http",
    "config": {
      "url": "https://inventory.yourcompany.com/api/webhooks/shopify",
      "method": "POST",
      "headers": {
        "Authorization": "Bearer YOUR_INVENTORY_API_KEY",
        "Content-Type": "application/json"
      }
    },
    "retryConfig": {
      "maxAttempts": 5,
      "backoffMultiplier": 2,
      "initialInterval": 1000
    }
  }'

Slack #finance Channel

bash
curl -X POST https://api.hookbase.app/api/organizations/{orgId}/destinations \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Slack #finance",
    "type": "slack",
    "config": {
      "url": "https://hooks.slack.com/services/YOUR/FINANCE/WEBHOOK"
    },
    "retryConfig": {
      "maxAttempts": 2,
      "backoffMultiplier": 1.5,
      "initialInterval": 500
    }
  }'

Step 3: Create Filters

High-Value Order Filter ($500+)

Filter for orders with a total price of $500 or more:

bash
curl -X POST https://api.hookbase.app/api/organizations/{orgId}/filters \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "High-Value Orders ($500+)",
    "conditions": [
      {
        "field": "headers.x-shopify-topic",
        "operator": "in",
        "value": ["orders/create", "orders/updated"]
      },
      {
        "field": "total_price",
        "operator": "gte",
        "value": "500.00"
      }
    ],
    "logic": "AND"
  }'

TIP

Shopify sends total_price as a string (e.g., "749.95"). The filter engine handles string-to-number coercion for comparison operators like gte.

All Orders Filter

Match all order creation and update events:

bash
curl -X POST https://api.hookbase.app/api/organizations/{orgId}/filters \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "All Order Events",
    "conditions": [
      {
        "field": "headers.x-shopify-topic",
        "operator": "in",
        "value": ["orders/create", "orders/updated"]
      }
    ],
    "logic": "AND"
  }'

Refunds Filter

Match only refund events:

bash
curl -X POST https://api.hookbase.app/api/organizations/{orgId}/filters \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Refund Events",
    "conditions": [
      {
        "field": "headers.x-shopify-topic",
        "operator": "eq",
        "value": "refunds/create"
      }
    ],
    "logic": "AND"
  }'

Step 4: Create Routes

High-Value → Priority Fulfillment

bash
curl -X POST https://api.hookbase.app/api/organizations/{orgId}/routes \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Shopify → Priority Fulfillment",
    "sourceId": "src_shopify456",
    "destinationId": "dst_fulfillment123",
    "filterId": "flt_highvalue123",
    "transformId": "tfm_fulfillment123",
    "enabled": true
  }'

High-Value → PagerDuty Alert

bash
curl -X POST https://api.hookbase.app/api/organizations/{orgId}/routes \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Shopify → PagerDuty Alert",
    "sourceId": "src_shopify456",
    "destinationId": "dst_pagerduty123",
    "filterId": "flt_highvalue123",
    "transformId": "tfm_pagerduty123",
    "enabled": true
  }'

All Orders → Inventory

bash
curl -X POST https://api.hookbase.app/api/organizations/{orgId}/routes \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Shopify → Inventory",
    "sourceId": "src_shopify456",
    "destinationId": "dst_inventory123",
    "filterId": "flt_allorders123",
    "transformId": "tfm_inventory123",
    "enabled": true
  }'

Refunds → Slack #finance

bash
curl -X POST https://api.hookbase.app/api/organizations/{orgId}/routes \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Shopify Refunds → #finance",
    "sourceId": "src_shopify456",
    "destinationId": "dst_slack_finance123",
    "filterId": "flt_refunds123",
    "transformId": "tfm_refund_slack123",
    "enabled": true
  }'

Step 5: Add Transforms

Priority Fulfillment Transform

Extract order details for the fulfillment system with priority flags:

bash
curl -X POST https://api.hookbase.app/api/organizations/{orgId}/transforms \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Shopify → Priority Fulfillment",
    "type": "jsonata",
    "config": {
      "expression": "{\n  \"order_id\": $string(id),\n  \"order_number\": $string(order_number),\n  \"priority\": $number(total_price) >= 1000 ? \"critical\" : \"high\",\n  \"total\": $number(total_price),\n  \"currency\": currency,\n  \"customer\": {\n    \"id\": $string(customer.id),\n    \"name\": customer.first_name & \" \" & customer.last_name,\n    \"email\": customer.email\n  },\n  \"shipping_address\": {\n    \"line1\": shipping_address.address1,\n    \"line2\": shipping_address.address2,\n    \"city\": shipping_address.city,\n    \"state\": shipping_address.province_code,\n    \"zip\": shipping_address.zip,\n    \"country\": shipping_address.country_code\n  },\n  \"line_items\": line_items.{\n    \"sku\": sku,\n    \"title\": title,\n    \"quantity\": quantity,\n    \"price\": $number(price)\n  },\n  \"requires_shipping\": line_items[requires_shipping = true] ? true : false,\n  \"created_at\": created_at\n}"
    }
  }'

Example Output:

json
{
  "order_id": "5678901234",
  "order_number": "1042",
  "priority": "high",
  "total": 749.95,
  "currency": "USD",
  "customer": {
    "id": "7890123456",
    "name": "Jane Smith",
    "email": "[email protected]"
  },
  "shipping_address": {
    "line1": "123 Main St",
    "line2": "Suite 400",
    "city": "San Francisco",
    "state": "CA",
    "zip": "94105",
    "country": "US"
  },
  "line_items": [
    {
      "sku": "WIDGET-PRO-001",
      "title": "Widget Pro Bundle",
      "quantity": 2,
      "price": 299.99
    },
    {
      "sku": "ADDON-PREMIUM",
      "title": "Premium Add-on",
      "quantity": 1,
      "price": 149.97
    }
  ],
  "requires_shipping": true,
  "created_at": "2026-02-11T14:30:00-05:00"
}

PagerDuty Alert Transform

Format as a PagerDuty Events API v2 payload:

bash
curl -X POST https://api.hookbase.app/api/organizations/{orgId}/transforms \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Shopify → PagerDuty Alert",
    "type": "jsonata",
    "config": {
      "expression": "{\n  \"routing_key\": \"YOUR_PAGERDUTY_INTEGRATION_KEY\",\n  \"event_action\": \"trigger\",\n  \"dedup_key\": \"shopify-order-\" & $string(id),\n  \"payload\": {\n    \"summary\": \"High-value Shopify order #\" & $string(order_number) & \" - $\" & total_price & \" \" & currency,\n    \"severity\": $number(total_price) >= 1000 ? \"critical\" : \"warning\",\n    \"source\": \"shopify-hookbase\",\n    \"component\": \"order-processing\",\n    \"group\": \"e-commerce\",\n    \"class\": \"high-value-order\",\n    \"custom_details\": {\n      \"order_id\": $string(id),\n      \"order_number\": $string(order_number),\n      \"total_price\": total_price,\n      \"currency\": currency,\n      \"customer_email\": customer.email,\n      \"item_count\": $count(line_items),\n      \"created_at\": created_at\n    }\n  },\n  \"links\": [\n    {\n      \"href\": \"https://your-store.myshopify.com/admin/orders/\" & $string(id),\n      \"text\": \"View Order in Shopify\"\n    }\n  ]\n}"
    }
  }'

Example Output:

json
{
  "routing_key": "YOUR_PAGERDUTY_INTEGRATION_KEY",
  "event_action": "trigger",
  "dedup_key": "shopify-order-5678901234",
  "payload": {
    "summary": "High-value Shopify order #1042 - $749.95 USD",
    "severity": "warning",
    "source": "shopify-hookbase",
    "component": "order-processing",
    "group": "e-commerce",
    "class": "high-value-order",
    "custom_details": {
      "order_id": "5678901234",
      "order_number": "1042",
      "total_price": "749.95",
      "currency": "USD",
      "customer_email": "[email protected]",
      "item_count": 2,
      "created_at": "2026-02-11T14:30:00-05:00"
    }
  },
  "links": [
    {
      "href": "https://your-store.myshopify.com/admin/orders/5678901234",
      "text": "View Order in Shopify"
    }
  ]
}

Inventory Transform

Normalize order data for inventory tracking:

bash
curl -X POST https://api.hookbase.app/api/organizations/{orgId}/transforms \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Shopify → Inventory Format",
    "type": "jsonata",
    "config": {
      "expression": "{\n  \"event_type\": \"order_placed\",\n  \"order_id\": $string(id),\n  \"order_number\": $string(order_number),\n  \"items\": line_items.{\n    \"sku\": sku,\n    \"variant_id\": $string(variant_id),\n    \"product_id\": $string(product_id),\n    \"quantity\": quantity,\n    \"fulfillable_quantity\": fulfillable_quantity,\n    \"requires_shipping\": requires_shipping\n  },\n  \"fulfillment_status\": fulfillment_status ? fulfillment_status : \"unfulfilled\",\n  \"shipping_method\": shipping_lines[0].title,\n  \"warehouse_hint\": shipping_address.country_code = \"US\" ? (shipping_address.province_code $in [\"CA\",\"OR\",\"WA\",\"NV\",\"AZ\"] ? \"west\" : \"east\") : \"international\",\n  \"timestamp\": created_at\n}"
    }
  }'

Example Output:

json
{
  "event_type": "order_placed",
  "order_id": "5678901234",
  "order_number": "1042",
  "items": [
    {
      "sku": "WIDGET-PRO-001",
      "variant_id": "44567890123",
      "product_id": "8901234567",
      "quantity": 2,
      "fulfillable_quantity": 2,
      "requires_shipping": true
    },
    {
      "sku": "ADDON-PREMIUM",
      "variant_id": "44567890456",
      "product_id": "8901234890",
      "quantity": 1,
      "fulfillable_quantity": 1,
      "requires_shipping": true
    }
  ],
  "fulfillment_status": "unfulfilled",
  "shipping_method": "Standard Shipping",
  "warehouse_hint": "west",
  "timestamp": "2026-02-11T14:30:00-05:00"
}

Refund Slack Transform

Format refund events as Slack Block Kit messages for the finance team:

bash
curl -X POST https://api.hookbase.app/api/organizations/{orgId}/transforms \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Shopify Refund → Slack Blocks",
    "type": "jsonata",
    "config": {
      "expression": "(\n  $refundTotal := $sum(refund_line_items.(quantity * $number(line_item.price)));\n  $isFullRefund := $count(refund_line_items) = $count(order.line_items);\n  $color := $isFullRefund ? \"#d73a49\" : \"#e36209\";\n  $emoji := $isFullRefund ? \":rotating_light:\" : \":warning:\";\n  {\n    \"attachments\": [\n      {\n        \"color\": $color,\n        \"blocks\": [\n          {\n            \"type\": \"header\",\n            \"text\": {\n              \"type\": \"plain_text\",\n              \"text\": $emoji & \" \" & ($isFullRefund ? \"Full Refund\" : \"Partial Refund\") & \" Processed\"\n            }\n          },\n          {\n            \"type\": \"section\",\n            \"fields\": [\n              {\n                \"type\": \"mrkdwn\",\n                \"text\": \"*Order:*\\n#\" & $string(order.order_number)\n              },\n              {\n                \"type\": \"mrkdwn\",\n                \"text\": \"*Refund Amount:*\\n$\" & $string($round($refundTotal, 2)) & \" \" & order.currency\n              },\n              {\n                \"type\": \"mrkdwn\",\n                \"text\": \"*Customer:*\\n\" & order.customer.first_name & \" \" & order.customer.last_name\n              },\n              {\n                \"type\": \"mrkdwn\",\n                \"text\": \"*Reason:*\\n\" & (note ? note : \"_No reason provided_\")\n              }\n            ]\n          },\n          {\n            \"type\": \"section\",\n            \"text\": {\n              \"type\": \"mrkdwn\",\n              \"text\": \"*Refunded Items:*\\n\" & $join(refund_line_items.(\"- \" & line_item.title & \" (x\" & $string(quantity) & \") - $\" & $string($round(quantity * $number(line_item.price), 2))), \"\\n\")\n            }\n          },\n          {\n            \"type\": \"context\",\n            \"elements\": [\n              {\n                \"type\": \"mrkdwn\",\n                \"text\": \"Refund ID: \" & $string(id) & \" | <https://your-store.myshopify.com/admin/orders/\" & $string(order.id) & \"|View in Shopify>\"\n              }\n            ]\n          }\n        ]\n      }\n    ]\n  }\n)"
    }
  }'

Example Output (Slack Message):

json
{
  "attachments": [
    {
      "color": "#e36209",
      "blocks": [
        {
          "type": "header",
          "text": {
            "type": "plain_text",
            "text": ":warning: Partial Refund Processed"
          }
        },
        {
          "type": "section",
          "fields": [
            {
              "type": "mrkdwn",
              "text": "*Order:*\n#1042"
            },
            {
              "type": "mrkdwn",
              "text": "*Refund Amount:*\n$299.99 USD"
            },
            {
              "type": "mrkdwn",
              "text": "*Customer:*\nJane Smith"
            },
            {
              "type": "mrkdwn",
              "text": "*Reason:*\nItem arrived damaged"
            }
          ]
        },
        {
          "type": "section",
          "text": {
            "type": "mrkdwn",
            "text": "*Refunded Items:*\n- Widget Pro Bundle (x1) - $299.99"
          }
        },
        {
          "type": "context",
          "elements": [
            {
              "type": "mrkdwn",
              "text": "Refund ID: 9012345678 | <https://your-store.myshopify.com/admin/orders/5678901234|View in Shopify>"
            }
          ]
        }
      ]
    }
  ]
}

Step 6: Test the Pipeline

Send a test Shopify order payload to verify routing:

bash
curl -X POST https://api.hookbase.app/ingest/your-org/shopify-prod \
  -H "Content-Type: application/json" \
  -H "X-Shopify-Topic: orders/create" \
  -H "X-Shopify-Hmac-Sha256: test_signature" \
  -H "X-Shopify-Shop-Domain: your-store.myshopify.com" \
  -d '{
    "id": 5678901234,
    "order_number": 1042,
    "total_price": "749.95",
    "subtotal_price": "699.95",
    "currency": "USD",
    "financial_status": "paid",
    "fulfillment_status": null,
    "customer": {
      "id": 7890123456,
      "first_name": "Jane",
      "last_name": "Smith",
      "email": "[email protected]"
    },
    "shipping_address": {
      "address1": "123 Main St",
      "address2": "Suite 400",
      "city": "San Francisco",
      "province_code": "CA",
      "zip": "94105",
      "country_code": "US"
    },
    "line_items": [
      {
        "id": 1234567890,
        "sku": "WIDGET-PRO-001",
        "title": "Widget Pro Bundle",
        "variant_id": 44567890123,
        "product_id": 8901234567,
        "quantity": 2,
        "price": "299.99",
        "fulfillable_quantity": 2,
        "requires_shipping": true
      },
      {
        "id": 1234567891,
        "sku": "ADDON-PREMIUM",
        "title": "Premium Add-on",
        "variant_id": 44567890456,
        "product_id": 8901234890,
        "quantity": 1,
        "price": "149.97",
        "fulfillable_quantity": 1,
        "requires_shipping": true
      }
    ],
    "shipping_lines": [
      {
        "title": "Standard Shipping",
        "price": "50.00"
      }
    ],
    "created_at": "2026-02-11T14:30:00-05:00"
  }'

TIP

For production testing, create a test order in Shopify Admin or use the Shopify CLI: shopify app dev with test webhooks enabled.

Verify Deliveries:

bash
curl https://api.hookbase.app/api/organizations/{orgId}/deliveries?limit=10 \
  -H "Authorization: Bearer YOUR_TOKEN"

For a $749.95 order, you should see:

  • Delivery to Priority Fulfillment API (matches $500+ filter)
  • Delivery to PagerDuty (matches $500+ filter)
  • Delivery to Inventory Management (matches all orders filter)
  • No delivery to Slack #finance (not a refund)

Production Considerations

1. Enable Deduplication

Shopify may retry webhooks if it does not receive a timely response. Prevent duplicate processing:

bash
curl -X PATCH https://api.hookbase.app/api/organizations/{orgId}/sources/src_shopify456 \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "deduplicationConfig": {
      "enabled": true,
      "keyPath": "id",
      "windowSeconds": 86400
    }
  }'

2. Adjust the Value Threshold

The $500 threshold in this example is a starting point. Update the filter to match your business:

bash
curl -X PATCH https://api.hookbase.app/api/organizations/{orgId}/filters/flt_highvalue123 \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "conditions": [
      {
        "field": "headers.x-shopify-topic",
        "operator": "in",
        "value": ["orders/create", "orders/updated"]
      },
      {
        "field": "total_price",
        "operator": "gte",
        "value": "1000.00"
      }
    ],
    "logic": "AND"
  }'

3. Configure Circuit Breaker for Fulfillment

Protect your fulfillment API during sale events when order volume spikes:

bash
curl -X PATCH https://api.hookbase.app/api/organizations/{orgId}/destinations/dst_fulfillment123 \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "circuitBreakerConfig": {
      "enabled": true,
      "failureThreshold": 10,
      "windowSeconds": 60,
      "resetTimeoutSeconds": 300
    }
  }'

4. Set Up Failover for Critical Orders

Ensure high-value orders always reach fulfillment, even if the primary endpoint is down:

bash
curl -X PATCH https://api.hookbase.app/api/organizations/{orgId}/routes/rte_fulfillment123 \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "failoverConfig": {
      "enabled": true,
      "destinationId": "dst_fulfillment_backup123",
      "triggerAfterAttempts": 3
    }
  }'

Released under the MIT License.