Automation Engine

Shipping Rules

Automate carrier and service selection with intelligent rules. Define conditions based on weight, destination, dimensions, value, and more — then let the engine choose the optimal carrier for every shipment.

How It Works

STEP 01

Define Rules

Create condition-based or service group rules in the admin panel or via API

STEP 02

Assign to Users

Assign rules to Sub-Admins who can pass them to their customers

STEP 03

Ship with Rule ID

Customers use shipping_rule_id instead of carrier_id in API calls

STEP 04

Auto-Allocate

Engine evaluates conditions and returns the matched carrier + service

Rule Types

Available Condition Properties

These properties can be used in rule conditions to match against shipment data. Multiple conditions within a statement are evaluated as AND logic.

PropertyTypeOperatorsDescription
destination_postcode
list
innot instarts with
Destination postal code or postcode range
origin_postcode
list
innot instarts with
Origin/warehouse postal code
destination_country
string
isis not
ISO 3166-1 two-letter country code
total_weight
decimal
=<>
Total shipment weight in kg or g
max_dimension
decimal
=<>
Largest dimension (L, W, or H) in cm
package_count
integer
=<>
Number of packages in the shipment
shipment_value
decimal
=<>
Total declared value of goods
is_residential
boolean
isis not
Whether destination is residential
warehouse_id
list
innot in
Source warehouse identifier
item_sku
list
containsnot contains
SKU of items in the order

Multi-Tenant Rule Hierarchy

Shipping rules integrate with the 3-tier pricing model. Each level of the hierarchy has different permissions for creating and managing rules.

Master Admin
  • Create global shipping rules applied platform-wide
  • Assign rules to specific Sub-Admins with markup
  • Override any Sub-Admin or Customer rule
  • View rule performance across all tenants
  • Set auto-package rules for all carriers
Sub-Admin
  • Create private rules for their own customers
  • Customize inherited global rules (add conditions)
  • Set carrier preferences and exclusions
  • Define auto-package rules for their network
  • View rule match statistics for their customers
Customer
  • Use rules assigned by their Sub-Admin via API
  • Pass shipping_rule_id instead of carrier_id
  • View which rule was applied to each shipment
  • Cannot create or modify rules

Rule Evaluation Flow

Evaluation Logic — Condition-Based Rule
┌─────────────────────────────────────────────────────┐
│                  Shipment Created                    │
│          shipping_rule_id: "rule_abc123"             │
└──────────────────────┬──────────────────────────────┘
                       │
                       ▼
              ┌────────────────┐
              │  Statement 1   │
              │  weight < 5kg  │──── YES ──▶ Allocate: AusPost eParcel
              │  postcode = 2* │
              └───────┬────────┘
                      │ NO
                      ▼
              ┌────────────────┐
              │  Statement 2   │
              │  weight < 25kg │──── YES ──▶ Allocate: Startrack Premium
              │  postcode = 2* │
              └───────┬────────┘
                      │ NO
                      ▼
              ┌────────────────┐
              │    DEFAULT     │
              │                │──────────▶ Allocate: TGE Road
              └────────────────┘

After allocation:
  ┌──────────────────────────────────────────────┐
  │  Apply 3-Tier Pricing Cascade                │
  │  base_cost → +master_markup → +sub_markup    │
  │  Store all cost tiers on shipment record     │
  └──────────────────────────────────────────────┘

API Endpoints

Database Schema

shipping_rules & shipping_rule_statements tables
-- Shipping Rules
CREATE TABLE shipping_rules (
  id              UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  organization_id UUID NOT NULL REFERENCES organizations(id),
  name            VARCHAR(255) NOT NULL,
  type            VARCHAR(20) NOT NULL,  -- 'condition' | 'service_group' | 'auto_package'
  is_active       BOOLEAN DEFAULT true,
  priority        INTEGER DEFAULT 0,     -- Higher = evaluated first
  
  -- Default action (condition rules)
  default_carrier_id   UUID REFERENCES carrier_connections(id),
  default_service_code VARCHAR(100),
  
  -- Scope
  scope           VARCHAR(20) DEFAULT 'private',  -- 'global' | 'private'
  assigned_to     UUID[],                          -- Sub-Admin org IDs (global rules)
  
  created_by      UUID NOT NULL REFERENCES users(id),
  created_at      TIMESTAMPTZ DEFAULT NOW(),
  updated_at      TIMESTAMPTZ DEFAULT NOW(),
  
  UNIQUE(organization_id, name)
);

-- Rule Statements (conditions + actions)
CREATE TABLE shipping_rule_statements (
  id              UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  rule_id         UUID NOT NULL REFERENCES shipping_rules(id) ON DELETE CASCADE,
  position        INTEGER NOT NULL,       -- Evaluation order
  
  -- Conditions (JSON array of condition objects)
  conditions      JSONB NOT NULL DEFAULT '[]',
  -- Example: [{"field":"total_weight","operator":"less_than","value":5,"unit":"kg"}]
  
  -- Action (condition rules: allocate carrier)
  carrier_id      UUID REFERENCES carrier_connections(id),
  service_code    VARCHAR(100),
  
  -- Action (service group rules: exclude services)
  excluded_services JSONB DEFAULT '[]',
  
  -- Action (auto-package rules: assign package)
  package_id      UUID REFERENCES predefined_packages(id),
  
  created_at      TIMESTAMPTZ DEFAULT NOW()
);

-- Service Group Priority List
CREATE TABLE shipping_rule_services (
  id              UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  rule_id         UUID NOT NULL REFERENCES shipping_rules(id) ON DELETE CASCADE,
  carrier_id      UUID NOT NULL REFERENCES carrier_connections(id),
  service_code    VARCHAR(100) NOT NULL,
  priority        INTEGER NOT NULL,       -- 1 = highest priority
  
  UNIQUE(rule_id, carrier_id, service_code)
);

-- Rule Match Log (for analytics)
CREATE TABLE shipping_rule_matches (
  id              UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  rule_id         UUID NOT NULL REFERENCES shipping_rules(id),
  shipment_id     UUID NOT NULL REFERENCES shipments(id),
  statement_pos   INTEGER,                -- Which statement matched (NULL = default)
  matched_at      TIMESTAMPTZ DEFAULT NOW()
);

Common Use Cases

Cheapest Carrier by Zone

Route metro shipments to Australia Post, regional to Startrack, and rural to TGE based on postcode ranges.

destination_postcodecondition

Weight-Based Carrier Split

Use satchel services for items under 5kg, pallet services for items over 25kg, and standard parcels for everything in between.

total_weightcondition

High-Value Shipment Routing

Automatically route shipments over $500 to carriers with built-in insurance and signature-on-delivery.

shipment_valuecondition

Auto-Package Selection

Automatically select the right satchel or box size based on total order weight, eliminating manual packaging decisions.

total_weightauto_package

Express vs Economy

Use a service group with express services prioritized, but exclude them for heavy or oversized items to control costs.

max_dimensionservice_group

Warehouse-Based Routing

Route shipments from your Sydney warehouse to one carrier and Melbourne warehouse to another based on negotiated rates.

warehouse_idcondition